主流消息队列的网络模型
Kafka 网络模型
Kafka 的网络层没有用 Netty 作为底层的通信库,而是直接采用 Java NIO 实现网络通信。在网络模型中,也是参照 Reactor 多线程模型,采用多线程、多 Selector 的设计。
Processor 线程和 Handler 线程之间通过 RequestChannel 传递数据,RequestChannel 中包含一个 RequestQueue 队列和多个 ResponseQueues 队列。每个 Processor 线程对应一个 ResponseQueue。
具体流程上:
一个 Acceptor 接收客户端建立连接的请求,创建 Socket 连接并分配给 Processor 处理。
Processor 线程把读取到的请求存入 RequestQueue 中,Handler 线程从 RequestQueue 队列中取出请求进行处理。
Handler 线程处理请求产生的响应,会存放到 Processor 对应的 ResponseQueue 中,Processor 线程从其对应的 ResponseQueue 中取出响应信息,并返回给客户端。
RocketMQ 网络模型
RocketMQ 采用 Netty 组件作为底层通信库,遵循 Reactor 多线程模型,同时又在 Reactor 模型上做了一些扩展和优化。
所以它的网络模型是 Netty 的网络模型,Netty 底层采用的是主从 Reactor 多线程模型,模型的原理逻辑跟前面讲到的主从 Reactor 多线程模型是一样的。
具体流程上:
一个 Reactor 主线程负责监听 TCP 网络连接请求,建立好连接,创建 SocketChannel,并注册到 Selector 上。RocketMQ 的源码中会自动根据 OS 的类型选择 NIO 和 Epoll,也可以通过参数配置,监听真正的网络数据。
接收到网络数据后,会把数据传递给 Reactor 线程池处理。
真正执行业务逻辑之前,会进行 SSL 验证、编解码、空闲检查、网络连接管理,这些工作在 Worker 线程池处理(defaultEventExecutorGroup)。
处理业务操作,放在业务 Processor 线程池中执行。
NIO 编程和 RPC 框架
因为 RPC 调用的是一个远端对象,调用者和被调用者处于不同的节点上,想完成调用,必须实现 4 个能力。
网络传输协议:远端调用底层需要经过网络传输,所以需要选择网络通信协议,比如 TCP。
应用通信协议:网络传输需要设计好应用层的通信协议,比如 HTTP2 或自定义协议。
服务发现:调用的是远端对象,需要可以定位到调用的服务器地址以及调用的具体方法。
序列化和反序列化:网络传输的是二进制数据,因此 RPC 框架需要自带序列化和反序列化的能力。
参考
《深入拆解消息队列 47 讲》