线程模型Netty怎么用

线程模型Netty怎么用,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

创新互联建站主营环翠网站建设的网络公司,主营网站建设方案,重庆APP开发,环翠h5重庆小程序开发公司搭建,环翠网站营销推广欢迎环翠等地区企业咨询

一.前言

众所周知,netty是高性能的原因源于其使用的是NIO,但是这只是其中一方面原因,其IO模型上决定的。另一方面源于其线程模型的设计,良好的线程模型设计,能够减少线程上下文切换,减少甚至避免锁的竞争(无锁化设计)带来的开销。

二.Reactor模式

Reactor模式是一种软件程序设计模式,它由Jim Coplien和Douglas C. Schmidt在1995年发布,主要用于处理一个或者多个客户端发起请求。

从一个客户端连接到日志服务器,然后发送请求的两个流程来看Reactor模式。其中有三种组件:

  • Dispacther:分发客户端的请求事件

  • Acceptor:接受客户端连接事件

  • Handler:处理客户端发起的请求事件

1.客户端连接到日志服务器

线程模型Netty怎么用

  1. 日志服务端注册Acceptor至Dispatcher

  2. 日志服务端调用分发器内部的handle_events方法

  3. 分发器开始在多路监听器(一般为OS的select、epoll)上等待客户端请求

  4. 客户端连接至日志服务器

  5. 分发器通知Acceptor连接事件

  6. Accetor接受一个新的连接

2.客户端发送记录日志的请求

线程模型Netty怎么用

  1. 客户端使用上部分建立的连接发送记录日志的请求

  2. 客户端分发器将记录日志的时间通知给Handler

  3. Handler处理读请求然后内部在传递给下个Handler继续处理

  4. 最终Handler进行写响应

  5. 返回到分发器,分发器继续事件循环等待处理下个事件

以上的几种组件的作用和处理连接和请求事件的模式就是Reactor模式。

三.Scalable IO in Java

以上的Reactor模式只是简单的设计模型,对于每种程序语言设计而言,仍然需要做一些改变。基于Java的NIO如何使用该模式构建高性能可伸缩的服务,并发大神Doug Lea在他的网站上发布过一篇论文《Scalable IO in Java》。

这篇论文中主要谈及的话题是如何构建高性能可扩展的IO,其中就是基于Reactor模式进行了演进。

其中涉及到以下组件:

  • Reactor: 响应IO事件,分发至相应的Handlers

  • Handlers: 执行非阻塞的IO操作,

1.单线程Reactor模式

线程模型Netty怎么用

  1. 其中客户端发送请求至服务端,Reactor响应其IO事件。

  2. 如果是建立连接的请求,则将其分发至acceptor,由其接受连接,然后再将其注册至分发器。

  3. 如果是读请求,则分发至Handler,由其读出请求内容,然后对内容解码,然后处理计算,再对响应编码,最后发送响应

在整个过程中都是使用单线程,无论是Reactor线程和后续的Handler处理都只使用一个线程。

但是单线程无疑会降低性能,所以需要增加线程提供扩展。

2. 多线程Reactor模式

线程模型Netty怎么用

为了能够提高扩展性,需要在单线程的模型上增加线程,主要从两个方面利用多线程发挥多核的应用优势:

  1. Worker Threads,Reactor应该能够快速的触发事件,防止Handler处理的延迟Reactor的响应导致事件积累,最终导致客户端连接请求的积压,甚至服务端的句柄数耗尽,服务停止响应。所以在Handlers的处理中使用工作多线程

  2. Multiple Reactor Threads,使用多个Reactor线程用于响应客户端发起的事件,可以使用多个Reactor分担负载

以上多线程的Reactor处理模式中,Reactor线程仍然是单线程,负责acceptor和IO read/send。但是对于请求的解码以及业务处理和响应的编码都是有work thread pool负责。

3.多Reactor模式

上述的多线程模式解决了Handler降低Reactor的响应,同时也提升了Handler的处理效率。但是Reactor仍然是单线程,对于大量的网络事件,其仍然有负载压力。为了能够使用多线程分担压力,演进出多Reactor:

线程模型Netty怎么用

其中主Reactor响应用户的连接事件,然后分发给acceptor,由其创建新的子Reactor。多个子Reactor分别处理各自的IO事件,比如read/write,然后再将其交给work thread pool进行解码,业务处理,编码。

多Reactor的设计通过将TCP连接建立和IO read/write事件分离至不同的Reactor,从而分担单个Reactor的压力,提升其响应能力。

四.Netty中的线程模型

在认识了Reactor设计模式和基于Reactor构建高性能可扩展的IO后,再来看netty的线程模型就显得简单的多了。

netty的线程模型设计正是Reactor模式的变种。以上的三种Reactor模式,在netty中都能非常好的得到了支持。在netty中主要通过参数配置来切换以上的各种模式。

netty中有EventLoopGroup和EventLoop两个类,它们是实现Reactor的关键之所在。EventLoop正如其名,其中包包含一个Selector选择器和一段循环逻辑。通过不断循环获取Selector上的就绪事件然后进行处理。EventLoopGroup是包含一组EventLoop的组,通过其可以产生一个EventLoop。

在阅读了netty官网给出的Demo后,可以知道,在创建一个Server时都会创建两个EventLoopGroup,分别为boss和work。前者用户Main Reactor,后者用于Sub Reactor和WorkThreadPool。

每次Main Reactor通过Selector得到客户端建立连接的请求后,就从work EventLoopGroup中获取一个EventLoop,然后将建立的连接对应的Socket抽象SocketChannel绑定到EventLoop上,形成了新的Sub Reactor。

在了解了netty的线程模型后,下面首先看下各种模式下的netty的参数配置。

1.单线程Reactor配置

通过构造一个EventLoop,将其用作Reactor和WorkThread,即是单线程模式。

EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
EventLoop bossLoop = eventLoopGroup.next();
EventLoop workLoop = reactorLoop;
ServerBootstrap b = new ServerBootstrap();
b.group(reactorLoop, workLoop);

boss和work使用同一个EventLoop,可以实现单线程Reactor。

2.多线程Reactor配置

Reactor使用单线程,然后Work使用多线程,即是多线程模型。

EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
EventLoop bossLoop = eventLoopGroup.next();
EventLoopGroup workLoopGroup = new NioEventLoopGroup();
ServerBootstrap b = new ServerBootstrap();
b.group(reactorLoop, workLoopGroup);
3.多Reactor模式

以上的多线程Reactor模式,便是多Reactor模式。bossLoop是主Reactor,其通过事件循环创建TCP连接,然后将连接的SocketChannel抽象绑定到workLoopGroup中的EventLoop上,形成Sub Reactor。

只是Main Reactor是单线程进行事件循环。虽然也可以构造多线程,但是没有什么实际意义。因为netty中在绑定端口时只会使用Group中的一个EventLoop绑定到Selector上,即是使用了EventLoopGroup。

当然对于同个应用如果监听多个端口,使用多个ServerBootStrap共享一个boss,那样Main Reactor也是多线程模式,才有意义。

看完上述内容,你们掌握线程模型Netty怎么用的方法了吗?如果还想学到更多技能或想了解更多相关内容,欢迎关注创新互联行业资讯频道,感谢各位的阅读!


网站栏目:线程模型Netty怎么用
当前网址:http://scjbc.cn/article/pgcpsh.html

其他资讯