因此在 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示例代码进行分析:
- 定义了两个EventLoopGroup,其中bossGroup对应的就是主线程池,只接收客户端的连接(注册,初始化逻辑),具体的工作由workerGroup这个从线程池来完成 。可以理解为老板负责招揽接待,员工负责任务完成 。线程池和线程组是一个概念,所以名称里有group 。之后就采用ServerBootstrap启动类,传入这两个主从线程组 。
- 客户端和服务器建立连接后,NIO会在两者之间建立Channel,所以启动类调用channel方法就是为了指定建立什么类型的通道 。这里指定的是NioServerSocketChannel这个通道类 。
- 启动类还调用了handler()和childHandler()方法,这两个方法中提及的handler是一个处理类的概念,他负责处理连接后的一个个通道的相应处理 。handler()指定的处理类是主线程池中对通道的处理类,childHandler()方法指定的是从线程池中对通道的处理类 。
- 执行ServerBootstrap的bind方法进行绑定端口的同时也执行了sync()方法进行同步阻塞调用 。
- 关闭通道采用Channel的closeFuture()方法关闭 。
- 最终优雅地关闭两个线程组,执行shutdownGracefully()方法完成关闭线程组 。
如果需要在客户端连接前的请求进行handler处理,则需要配置handler();如果是处理客户端连接之后的handler,则需要配置在childHandler() 。option和childOption也是一样的道理 。boss线程池作用:
- 接收客户端的连接,初始化Channel参数 。
- 将链路状态变更时间通知给ChannelPipeline 。
- 异步读取通信对端的数据报,发送读事件到ChannelPipeline 。
- 异步发送消息到通信对端,调用ChannelPipeline的消息发送接口 。
- 执行系统调用Task 。
- 执行定时任务Task 。
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采用的是多进程(单线程)&多路IO复用模型 。
工作模型:
- Nginx在启动后,会有一个master进程和多个相互独立的worker进程 。
- 接收来自外界的信号,向所有worker进程发送信号,每个进程都有可能来处理这个连接 。
- master进程能监控worker进程的运行状态,当worker进程退出后(异常情况下),会自动启动新的worker进程 。
推荐阅读
- 搞懂CSS 字体单位
- 天窗只是用来开窗的?天窗的优点你没搞懂,就别买了!
- 一文彻底了解Hadoop的来龙去脉
- 一文搞懂MySQL的Join,聊一聊秒杀架构设计
- 2个实例搞懂Python循环嵌套——九九乘法表以及质数的索引
- 彻底解决"手机-电脑"互传大文件的难题 电脑-手机快捷互联互通
- 蛀牙本来是小事,为何补牙的时候反而要将牙洞磨大?看完算搞懂了
- 茶具养壶好方法
- 彻底搞懂JDBC的运行过程
- 彻底搞懂Redis的线程模型