一起学netty(7)netty的线程模型

weblog 939 0 0

在上一节《一起学netty(6)》的文章中,简要说明了用nio原生代码写程序的一些不足和问题,以及netty在nio的基础上大致做了那些工作。其中提到一点就是当活跃客户端的数量太多,单线程处理时所带来的问题,那么netty就对解决这个问题提供了多线程的解决方案。

netty的线程模型

实际上Netty线程模型就是Reactor模式的一个实现,而Reactor模式又是什么呢?

Reactor模式是基于事件驱动开发的,核心组成部分包括Reactor和线程池,其中Reactor负责监听和分配事件,线程池负责处理事件,而根据Reactor的数量和线程池的数量,又将Reactor分为三种模型:

  • 单线程模型 (单Reactor单线程)
  • 多线程模型 (单Reactor多线程)
  • 主从多线程模型 (多Reactor多线程)

单线程模型

单线程模型

Reactor内部通过selector 监控连接事件,收到事件后通过dispatch进行分发,如果是连接建立的事件,则由Acceptor处理,Acceptor通过accept接受连接,并创建一个Handler来处理连接后续的各种事件,如果是读写事件,直接调用连接对应的Handler来处理Handler完成read->(decode->compute->encode)->send的业务流程,这种模型好处是简单,坏处却很明显,当某个Handler阻塞时,会导致其他客户端的handler和accpetor都得不到执行,无法做到高性能,只适用于业务处理非常快速的场景。这也和之前说的传统单线程nio程序是一样的。

多线程模型

多线程模型

主线程中,Reactor对象通过selector监控连接事件,收到事件后通过dispatch进行分发,如果是连接建立事件,则由Acceptor处理,Acceptor通过accept接收连接,并创建一个Handler来处理后续事件,而Handler只负责响应事件,不进行业务操作,也就是只进行read读取数据和write写出数据,业务处理交给一个线程池进行处理,线程池分配一个线程完成真正的业务处理,然后将响应结果交给主进程的Handler处理,Handler将结果send给client 。

单Reactor承当所有事件的监听和响应,而当我们的服务端遇到大量的客户端同时进行连接,或者在请求连接时执行一些耗时操作,比如身份认证,权限检查等,这种瞬时的高并发就容易成为性能瓶颈。

主从多线程模型

主从多线程模型

存在多个Reactor,每个Reactor都有自己的selector选择器,线程和dispatch,主线程中的mainReactor通过自己的selector监控连接建立事件,收到事件后通过Accpetor接收,将新的连接分配给某个子线程,子线程中的subReactor将mainReactor分配的连接加入连接队列中通过自己的selector进行监听,并创建一个Handler用于处理后续事件。Handler完成read->业务处理->send的完整业务流程。

Netty中的线程模型与Reactor的联系

Netty主要靠NioEventLoopGroup线程池来实现具体的线程模型的。

单线程模型

单线程模型就是只指定一个线程执行客户端连接和读写操作,也就是在一个Reactor中完成,对应在Netty中的实现就是将NioEventLoopGroup线程数设置为1,核心代码是:

 NioEventLoopGroup group = new NioEventLoopGroup(1);
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(group)
                .channel(NioServerSocketChannel.class)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.TCP_NODELAY, true)
                .option(ChannelOption.SO_BACKLOG, 1024)
                .childHandler(new ServerHandlerInitializer());
对应Reactor的单线程模型

多线程模型

多线程模型就是在一个单Reactor中进行客户端连接处理,然后业务处理交给线程池,核心代码如下:

NioEventLoopGroup eventGroup = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(eventGroup)
        .channel(NioServerSocketChannel.class)
        .option(ChannelOption.TCP_NODELAY, true)
        .option(ChannelOption.SO_BACKLOG, 1024)
        .childHandler(new ServerHandlerInitializer());

走进group方法可以发现我们平时设置的bossGroup和workerGroup就是使用了同一个group。

@Override
public ServerBootstrap group(EventLoopGroup group) {
    return group(group, group);
}
对应Reactor的多线程模型

主从多线程模型

主从多线程模型是有多个Reactor,也就是存在多个selector,所以我们定义一个bossGroup和一个workGroup,核心代码如下:

NioEventLoopGroup bossGroup = new NioEventLoopGroup();
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup,workerGroup)
        .channel(NioServerSocketChannel.class)
        .option(ChannelOption.TCP_NODELAY, true)
        .option(ChannelOption.SO_BACKLOG, 1024)
        .childHandler(new ServerHandlerInitializer());
主从多线程模型

参考:https://segmentfault.com/a/1190000007403873

最后

最后再截几张网上大牛总结的有关netty的线程模型的图,帮助大家理解和思考。

单线程
多线程
主从多线程
netty模型

 


猜你喜欢
official 857 、什么是bio?bio即:同步阻塞式IO。就是传统javaio网络。javabio有两个阻塞地方,第个地方是需要阻塞监听端口,等待客户端链接。第二个需要阻塞Socketread方法
official 1063 之前文章中提到过,单线nio任然有定缺点。在上节《netty(7)netty线》中也提到,netty出现,封装了nio复杂代码,并且介入多线来处理事件,最大限度
official 779 《操作系统》什么是线,为什么要引入线?还没引入进之前,系统中各个序只能串行执行。所以只能个进执行完才能执行另外个进。进入了进概念之后,多个进之间可以并行执行,从而实现了用户在计
official 1000 之前文章中提到了java中nio是同步非阻塞网络io,本文就主要说明下同步、异步、阻塞、非阻塞概念来帮助理解nio。io操作IO分两阶段(旦拿到数据后就变成了数据操作,不再是IO
official 773 、最简单nio序publicstaticvoidmain(String[]args)throwsException{ ListSocketChannellist=newArrayList
official 1573 篇《netty(2)nio及多路复用器》中已经简单介绍了nio,以及多路复用器概念,并了解nio是非阻塞网络,以及与bio区别。本篇将继续深入理解nio,以及select
java虚拟机(jvm) 4487 jvm内存分析(1)已经对内存进行了个宏观概括http://www.jiajiajia.club/weblog/blog/artical/82那么下边具体分析下方法执行还是以
official 932 netty包下ServerSocketChannel或SocketChannel和nio包下ServerSocketChannel或SocketChannel概念是。只不过netty中又重新对nio
目录
没有一个冬天不可逾越,没有一个春天不会来临。最慢的步伐不是跬步,而是徘徊,最快的脚步不是冲刺,而是坚持。