文章目录
一、消息队列的网路模型拟解决问题
单个请求性能优化
1. 编解码速度
- 选择高效的序列化协议(如 Protocol Buffers、MessagePack)
- 优化编解码算法,减少 CPU 开销
- 考虑使用零拷贝技术减少内存拷贝
2. 网络模块处理速度
- 及时处理响应:确保业务线程处理完成后,网络模块能快速回包
- 异步处理机制:避免阻塞主线程
- 缓冲区管理:合理设置读写缓冲区大小
并发请求性能优化
1. 高效的连接管理
- 连接池设计:复用 TCP 连接,减少连接建立/断开的开销
- 连接生命周期管理:及时清理无效连接
- 负载均衡:合理分配连接负载
- 连接复用:支持多路复用技术(如 HTTP/2、gRPC)
2. 快速处理高并发请求
- I/O 多路复用:使用 epoll/kqueue/IOCP 等高效 I/O 模型
- 线程池设计:合理分配业务处理线程
- 事件驱动架构:基于事件回调的非阻塞处理
- 请求队列优化:高效的请求排队和调度机制
3. 大流量场景处理
- 零拷贝技术:减少数据在用户态和内核态之间的拷贝
- 内存池管理:预分配内存,减少 GC 压力
- 批量处理:合并多个小请求进行批量处理
- 流量控制:实现背压机制,防止系统过载
二、一些技术基础知识
1. 基于多路复用技术管理 TCP 连接(提高性能)
(1)单条 TCP 连接的复用
TCP 连接复用是指在一条 TCP 连接上传输多个独立的请求/响应,而不是为每个请求建立新的连接。
TCP 连接复用是指在一条 TCP 连接上传输多个独立的请求/响应,而不是为每个请求建立新的连接。能从一定程度上提高性能,缺点是在协议设计和编码实现的时候有额外开发工作量,而且近年随着异步 IO、IO 多路复用技术的发展,这种方案有点多余。因为语言特性、历史背景原因,RabbitMQ 用的就是这种方案。
(2)IO 多路复用技术
IO 多路复用技术,是指通过把多个 IO 的阻塞复用到同一个 selector 的阻塞上,让系统在单线程的情况下可以同时处理多个客户端请求。最大的优势是系统开销小,系统不需要创建额外的进程或者线程,降低了维护的工作量,也节省了资源。
目前支持 IO 多路复用的系统调用有 Select、Poll、Epoll 等,Java NIO 库底层就是基于 Epoll 机制实现的。
不过,即使用了这两种技术,单机能处理的连接数还是有上限的。
第一个上限是操作系统的 FD 上限,如果连接数超过了 FD 的数量,连接会创建失败。
第二个限制是系统资源的限制,主要是 CPU 和内存。频繁创建、删除或者创建过多连接会消耗大量的物理资源,导致系统负载过高。
2. 如何快速处理高并发请求——Reactor模型(提高性能)
Reactor模型是一种事件驱动的并发编程模型,主要用于处理高并发I/O操作。它的核心思想是:当有事件发生时,才进行处理,而不是主动轮询。
(1)三个核心角色
Reactor(反应器/事件分发器)
- 职责:事件循环的核心,负责监听和分发事件
- 功能:
- 使用
select/epoll/kqueue
等系统调用监听多个文件描述符 - 当有事件发生时,将事件分发给对应的处理器
- 管理事件注册和注销
- 使用
- 特点:单线程运行,负责事件的分发,不处理具体业务逻辑
Acceptor(连接处理器)
- 职责:专门处理新连接事件
- 功能:
- 接受新的客户端连接
- 为每个新连接创建对应的 Handler
- 将新连接注册到 Reactor 的事件监听中
- 特点:只在有新连接时被调用
Handler(业务处理器)
- 职责:处理具体的业务逻辑
- 功能:
- 处理已建立连接的读写事件
- 实现具体的业务逻辑
- 处理数据编解码
- 特点:每个连接对应一个 Handler 实例
(2)单 Reactor 单线程模式
特点分析:
- 架构简单:只有一个 Reactor 线程,所有操作都在同一个线程中完成
- 无并发问题:不存在线程安全问题,不需要加锁
- 性能瓶颈:所有 Handler 都在同一个线程中执行,容易成为性能瓶颈
- 适用场景:连接数较少,业务逻辑简单的场景
优缺点对比:
优点 | 缺点 |
---|---|
实现简单,易于理解 | 单线程处理,性能有限 |
无线程安全问题 | 无法充分利用多核CPU |
资源消耗少 | 一个Handler阻塞会影响其他连接 |
适合小规模应用 | 不适合高并发场景 |
(3)单 Reactor 多线程模式
特点分析:
- 职责分离:Reactor 只负责事件分发,Handler 在独立线程中处理业务逻辑
- 并发处理:业务逻辑可以并发执行,提高处理能力
- 线程安全:需要处理线程安全问题,Handler 之间可能需要同步
- 资源管理:需要管理线程池,避免线程过多导致资源浪费
工作流程:
- Reactor 线程接收事件并分发
- Acceptor 处理新连接(仍在主线程)
- Handler 将业务逻辑提交到线程池
- 工作线程执行具体的业务处理
- 处理完成后,通过回调或消息队列返回结果
优缺点对比:
优点 | 缺点 |
---|---|
业务逻辑可以并发处理 | 需要处理线程安全问题 |
充分利用多核CPU | 线程切换有一定开销 |
适合CPU密集型业务 | 线程池管理复杂 |
响应性好 | 内存占用相对较高 |
(4)主从 Reactor 多线程模式
特点分析:
- 分层架构:主 Reactor 专门处理连接,子 Reactor 处理读写事件
- 负载均衡:多个子 Reactor 可以负载均衡处理连接
- 高并发:充分利用多核CPU,支持更高的并发连接数
- 复杂管理:需要管理多个 Reactor 和线程池
工作流程:
- 主 Reactor 监听连接事件
- Acceptor 接受新连接,分配给某个子 Reactor
- 子 Reactor 负责该连接的后续读写事件
- Handler 处理具体业务逻辑,可提交到业务线程池
- 工作线程 执行CPU密集型业务处理
负载均衡策略:
- 轮询分配:新连接轮流分配给子 Reactor
- 最少连接:分配给连接数最少的子 Reactor
- 哈希分配:根据客户端IP等特征哈希分配
优缺点对比:
优点 | 缺点 |
---|---|
支持超高并发连接 | 架构复杂,实现困难 |
充分利用多核CPU | 调试和问题排查复杂 |
连接处理和读写处理分离 | 内存占用较高 |
适合大规模应用 | 需要精心调优参数 |
3. Netty框架(提高稳定性)
在 Java 中,网络编程的核心是一个基础的类库——Java NIO 库,它的底层是基于 Linux/Unix IO 复用模型 Epoll 实现的。如果我们要基于 Java NIO 库开发一个 Server,需要处理网络的闪断、客户端的重复接入、连接管理、安全认证、编解码、心跳保持、半包读写、异常处理等等细节,工作量非常大。
所以在消息队列的网络编程模型中,为了提高稳定性或者降低成本,选择现成的、成熟的 NIO 框架是一个更好的方案。
Netty是一个基于Java NIO的高性能网络应用框架,采用异步非阻塞的事件驱动架构,支持多种网络协议(HTTP、WebSocket、TCP、UDP等)。它的核心优势在于高性能、低延迟和高度可扩展性,通过零拷贝技术、高效的线程模型和模块化设计,能够轻松处理大量并发连接。Netty广泛应用于RPC框架、游戏服务器、聊天应用、代理服务器、API网关等场景,已成为Java网络编程的事实标准,被众多知名项目如gRPC、Dubbo、Elasticsearch等采用。
4. 零拷贝
看这篇:https://blog.youkuaiyun.com/Tracycoder/article/details/148957098
三、Kafka网络模型(Java NIO)
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网络模型(Netty)
RocketMQ 采用 Netty 组件作为底层通信库,遵循 Reactor 多线程模型,同时又在 Reactor 模型上做了一些扩展和优化。
所以它的网络模型是 Netty 的网络模型,Netty 底层采用的是主从 Reactor 多线程模型,模型的原理逻辑跟前面讲到的主从 Reactor 多线程模型是一样的。
在主从 Reactor 多线程模型的理论基础上,我们来分析一下 RocketMQ 中 NettyRemotingServer 的具体实现形式。
- 具体流程上:
- 一个 Reactor 主线程负责监听 TCP 网络连接请求,建立好连接,创建 SocketChannel,并注册到 Selector 上。RocketMQ 的源码中会自动根据 OS 的类型选择 NIO 和 Epoll,也可以通过参数配置,监听真正的网络数据。
- 接收到网络数据后,会把数据传递给 Reactor 线程池处理。
- 真正执行业务逻辑之前,会进行 SSL 验证、编解码、空闲检查、网络连接管理,这些工作在 Worker 线程池处理(defaultEventExecutorGroup)。
- 处理业务操作,放在业务 Processor 线程池中执行。
五、Pulsar网络模型(Netty)
Pulsar基于Netty框架构建网络层,Netty底层使用操作系统的IO多路复用技术,底层也是基于I/O多路复用技术(自动选择最优,优先Epoll):
// Pulsar Broker 网络服务初始化
public class PulsarServer {
private final EventLoopGroup bossGroup;
private final EventLoopGroup workerGroup;
public PulsarServer(PulsarService pulsar) {
// 根据操作系统选择最优的 EventLoopGroup
if (Epoll.isAvailable()) {
// Linux: 使用 EpollEventLoopGroup (epoll)
this.bossGroup = new EpollEventLoopGroup(1);
this.workerGroup = new EpollEventLoopGroup(
pulsar.getConfiguration().getNumIOThreads());
} else {
// Windows/macOS: 使用 NioEventLoopGroup (select/kqueue)
this.bossGroup = new NioEventLoopGroup(1);
this.workerGroup = new NioEventLoopGroup(
pulsar.getConfiguration().getNumIOThreads());
}
}
}
与RocketMQ类似,也采用主从Reactor多线程模式(多Reactor多线程)。
六、RabbitMQ网络模型
RabbitMQ底层基于select/poll,以及Erlang的Actor网络模型,其中,轻量级进程切换开销极小:
┌─────────────────────────────────────────────────────────────┐
│ Erlang Actor Model │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Process │ │ Process │ │ Process │ │
│ │ (Actor) │ │ (Actor) │ │ (Actor) │ │
│ │ │ │ │ │ │ │
│ │ ┌─────────┐ │ │ ┌─────────┐ │ │ ┌─────────┐ │ │
│ │ │ Message │ │ │ │ Message │ │ │ │ Message │ │ │
│ │ │ Queue │ │ │ │ Queue │ │ │ │ Queue │ │ │
│ │ └─────────┘ │ │ └─────────┘ │ │ └─────────┘ │ │
│ │ │ │ │ │ │ │
│ │ ┌─────────┐ │ │ ┌─────────┐ │ │ ┌─────────┐ │ │
│ │ │ Process │ │ │ │ Process │ │ │ │ Process │ │ │
│ │ │ Logic │ │ │ │ Logic │ │ │ │ Logic │ │ │
│ │ └─────────┘ │ │ └─────────┘ │ │ └─────────┘ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Scheduler Thread Pool │ │
│ └────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
七、消息队列网络模型总结
特性 | RabbitMQ | Kafka | RocketMQ | Pulsar |
---|---|---|---|---|
语言 | Erlang | Java | Java | Java |
网络模型 | Actor | Reactor | Reactor | Reactor |
IO多路复用 | select/poll | epoll | epoll | epoll |
零拷贝 | 无 | 有 | 有 | 有 |
并发模型 | 轻量级进程 | 线程池 | 线程池 | 线程池 |
协议 | AMQP | 自定义 | 自定义 | 自定义 |