彻底搞懂Reactor模型和Proactor模型( 三 )

因此在 Linux 下实现高并发网络编程都是以Reactor模型为主 。
常见架构的进程/线程模型Netty的线程模型
Netty采用的是主从线程模型 。下面是Netty使用中很常见的一段代码 。
public class Server {
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NIOServerSocketChannel.class)
.childOption(ChannelOption.TCP_NODELAY, true)
.childAttr(AttributeKey.newInstance("childAttr"), "childAttrValue")
.handler(new ServerHandler())
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) {
}
});
ChannelFuture f = b.bind(8888).sync();
f.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
对Netty示例代码进行分析:

  1. 定义了两个EventLoopGroup,其中bossGroup对应的就是主线程池,只接收客户端的连接(注册,初始化逻辑),具体的工作由workerGroup这个从线程池来完成 。可以理解为老板负责招揽接待,员工负责任务完成 。线程池和线程组是一个概念,所以名称里有group 。之后就采用ServerBootstrap启动类,传入这两个主从线程组 。
  2. 客户端和服务器建立连接后,NIO会在两者之间建立Channel,所以启动类调用channel方法就是为了指定建立什么类型的通道 。这里指定的是NioServerSocketChannel这个通道类 。
  3. 启动类还调用了handler()和childHandler()方法,这两个方法中提及的handler是一个处理类的概念,他负责处理连接后的一个个通道的相应处理 。handler()指定的处理类是主线程池中对通道的处理类,childHandler()方法指定的是从线程池中对通道的处理类 。
  4. 执行ServerBootstrap的bind方法进行绑定端口的同时也执行了sync()方法进行同步阻塞调用 。
  5. 关闭通道采用Channel的closeFuture()方法关闭 。
  6. 最终优雅地关闭两个线程组,执行shutdownGracefully()方法完成关闭线程组 。
如果需要在客户端连接前的请求进行handler处理,则需要配置handler();如果是处理客户端连接之后的handler,则需要配置在childHandler() 。option和childOption也是一样的道理 。
boss线程池作用:
  1. 接收客户端的连接,初始化Channel参数 。
  2. 将链路状态变更时间通知给ChannelPipeline 。
worker线程池作用:
  1. 异步读取通信对端的数据报,发送读事件到ChannelPipeline 。
  2. 异步发送消息到通信对端,调用ChannelPipeline的消息发送接口 。
  3. 执行系统调用Task 。
  4. 执行定时任务Task 。
通过配置boss和worker线程池的线程个数以及是否共享线程池等方式,Netty的线程模型可以在以上三种Reactor模型之间进行切换 。
Tomcat的线程模型
Tomcat支持四种接收请求的处理方式:BIO、NIO、APR和AIO
  • NIO
  • 同步非阻塞,比传统BIO能更好的支持大并发,tomcat 8.0 后默认采用该模型 。
  • 使用方法(配置server.xml):<Connector port="8080" protocol="HTTP/1.1"/> 改为 protocol="org.Apache.coyote.http11.Http11NioProtocol"
  • BIO
  • 阻塞式IO,tomcat7之前默认,采用传统的java IO进行操作,该模型下每个请求都会创建一个线程,适用于并发量小的场景 。
  • 使用方法(配置server.xml):protocol =" org.apache.coyote.http11.Http11Protocol"
  • APR
  • tomcat 以JNI形式调用http服务器的核心动态链接库来处理文件读取或网络传输操作,需要编译安装APR库 。
  • 使用方法(配置server.xml):protocol ="org.apache.coyote.http11.Http11AprProtocol"
  • AIO
  • 异步非阻塞 (NIO2),tomcat8.0后支持 。多用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,JDK7开始支持 。
  • 使用方法(配置server.xml):protocol ="org.apache.coyote.http11.Http11Nio2Protocol"
Nginx的进程模型
Nginx采用的是多进程(单线程)&多路IO复用模型 。
工作模型:
  1. Nginx在启动后,会有一个master进程和多个相互独立的worker进程 。
  2. 接收来自外界的信号,向所有worker进程发送信号,每个进程都有可能来处理这个连接 。
  3. master进程能监控worker进程的运行状态,当worker进程退出后(异常情况下),会自动启动新的worker进程 。


    推荐阅读