Netty 线程模型:
图好:https://juejin.im/post/6844903712435994631
解析好:https://blog.csdn.net/y277an/article/details/98561000
Netty 采用基于主从 Reactors 多线程模型:
- mainReactor 负责客户端的连接请求,并使用队列转交给 subReactor
- subReactor 负责处理通道的 IO 读写请求
线程池:
- bossGroup:一个端口对应一个线程,同时对应一个 mainReactor
- workerGroup:被 subReactor 和 worker 线程充分利用
Reactor 线程模型:
https://www.jianshu.com/p/2965fca6bb8f
也叫 Dispatcher 模型,即 IO 多路复用统一监听事件,收到事件后分发。
组成:
- Reactor:单独的线程运行,负责监听和分发事件,分发给适当的处理程序
- Handler:处理 Reactor 派发的 IO 事件
根据 Reactor 和 Handler 线程数量,分为三种:
- 单 Reactor 单线程
- 单 Reactor 多线程
- 主从 Reactor 多线程
单 Reactor 单线程:
- Reactor 对象通过 select 监控连接事件,收到事件后通过 dispatch 进行转发。
- 如果是连接建立的事件,则由 acceptor 接受连接,并创建 handler 处理后续事件。
- 如果不是建立连接事件,则 Reactor 会分发调用 Handler 来响应。
- handler 会完成 read -> 业务处理 -> send 的完整业务流程。
缺点:**
- Reacor、Acceptor、Handler 都是一个线程处理,利用不了多核 CPU
- 单线程同时负责 Handler 的编码、解码、读取和发送,负载过重,吞吐量低
- 单线程发生故障后,会造成进程崩溃
主线程:
- Reactor:
- 调用 Acceptor.accept,创建 Handler
- dispatch,调用 Handler
- Handler:read、write、业务
单 Reactor 多线程:
- Reactor 对象通过 Select 监控客户端请求事件,收到事件后通过 dispatch 进行分发。
- 如果是建立连接请求事件,则由 acceptor 通过 accept 处理连接请求,然后创建一个 Handler 对象处理连接完成后续的各种事件。
- 如果不是建立连接事件,则 Reactor 会分发调用连接对应的 Handler 来响应。
- Handler 只负责响应事件,不做具体业务处理,通过 Read 读取数据后,会分发给后面的 Worker 线程池进行业务处理。
- Worker 线程池会分配独立的线程完成真正的业务处理,如何将响应结果发给 Handler 进行处理。
- Handler 收到响应结果后通过 send 将响应结果返回给 Client。
主线程:
- Reactor:
- 调用 Acceptor.accept,创建 Handler
- dispatch,调用 Handler
- Handler:read、write
work 线程:业务
缺点:
- 多线程数据共享和访问复杂。work 线程把数据给主线程发送,会涉及到共享数据的互斥和保护机制
- 主线程同时负责 Reactor 和 Handler,即 accept、read、write,存在性能问题
主从 Reactor 多线程:
- 从主线程池中随机选择一个 Reactor 线程作为 acceptor 线程,用于绑定监听端口,接收客户端连接
- acceptor 线程接收客户端连接请求之后创建新的 SocketChannel,将其注册到主线程池的其它 Reactor 线程上,由其负责接入认证、IP 黑白名单过滤、握手等操作
- 步骤 2 完成之后,业务层的链路正式建立,将 SocketChannel 从主线程池的 Reactor 线程的多路复用器上摘除,重新注册到 Sub 线程池的线程上,并创建一个 Handler 用于处理各种连接事件
- 当有新的事件发生时,SubReactor 会调用连接对应的 Handler 进行响应
- Handler 通过 Read 读取数据后,会分发给后面的 Worker 线程池进行业务处理
- Worker 线程池会分配独立的线程完成真正的业务处理,如何将响应结果发给 Handler 进行处理
- Handler 收到响应结果后通过 Send 将响应结果返回给 Client