目录
Netty 的线程模型设计初衷是为了高效处理并发的连接和请求,其中运用了多种优化技术,如 reactor 模式、线程池和事件循环等。
一、Netty 线程模型概述
Netty 服务端主要有两个大的线程组,分别是 boss group 和 worker group。
(一)boss group
boss group 相当于老板线程组,主要用于与客户端建立连接,负责处理 accept 事件。当有连接 IO 的连接事件时,这个线程组会将连接建立好,然后把连接交给后面的干活线程组。
以下是用 Java 代码初始化 boss group 线程池的示例:
EventLoopGroup bossGroup = new NioEventLoopGroup();
(二)worker group
worker group 是工作线程组,它从 WORKGROUP 中也有线程池,里面有很多事件循环的线程。worker group 会把连接分配给不同的事件循环线程,这些线程用来处理连接建立好之后的各种 IO 的读写事件。
以下是用 Java 代码初始化 worker group 线程池的示例:
EventLoopGroup workerGroup = new NioEventLoopGroup();
此外,Netty 除了 boss group 和 worker 线程池外,还有用户自定义的线程。当 IO 读写事件把数据读过来之后,可能需要做一些业务处理,为了提高整个程序的性能,可以把这些业务处理的线程交给用户自定义的线程去处理,这样可以把真正的事件循环的线程空出来,让它继续处理其他连接的一些事件。
二、Netty 线程模型提升性能的内部机制
(一)非阻塞 IO(NIO)
Netty 内部使用了非阻塞 IO(NIO),即多路复用机制。内部有一个 select 多路复用器,可以让一个线程同时处理很多 IO 事件,而不像阻塞 IO(BIO)那样一个线程只能一次处理一个事件,并且会因为等待 IO 通道里面是否发数据而一直阻塞等着,效率低很多。
(二)事件循环
Netty 内部由事件循环(even loop)去轮询事件,最底层是基于 Linux 的 epoll 机制实现。事件循环的线程通过不断循环检查事件队列,去执行相应的 IO 操作,对 CPU 的利用率非常充分,也不会因为 IO 操作而被阻塞。
(三)线程与通道绑定
Netty 将每一个连接后续的通道数据处理绑定到一个特定的事件循环线程上面来,这样就不存在多个线程同时处理一个连接的情况,避免了涉及并发问题控制时需要加锁的情况,对程序性能有提升。
(四)线程池复用
Netty 线程池中的线程可以复用,避免了线程频繁的创建以及销毁的开销,对整个程序的性能有提升。
(五)工作线程分离
Netty 的连接由 boss group 处理,具体的 IO 操作由 worker group 处理,职责划分清晰。如果单搞一个线程来处理,连接比较多或者 IO 操作比较密集时,可能会对系统造成瓶颈。
总之,Netty 的线程模型设计得非常好,对整个程序的性能提升有非常大的帮助