Netty — 线程模型
一.前言
众所周知,netty是高性能的原因源于其使用的是NIO,但是这只是其中一方面原因,其IO模型上决定的。另一方面源于其线程模型的设计,良好的线程模型设计,能够减少线程上下文切换,减少甚至避免锁的竞争(无锁化设计)带来的开销。
本篇文章将介绍netty的线程模型设计,主要从以下几个方面:
- Reactor模式
- Scalable IO in Java
- Netty中的线程模型
### 二.Reactor模式
Reactor模式是一种软件程序设计模式,它由Jim Coplien和Douglas C. Schmidt在1995年发布,主要用于处理一个或者多个客户端发起请求。
从一个客户端连接到日志服务器,然后发送请求的两个流程来看Reactor模式。其中有三种组件:
- Dispacther:分发客户端的请求事件
- Acceptor:接受客户端连接事件
- Handler:处理客户端发起的请求事件
1.客户端连接到日志服务器
- 日志服务端注册Acceptor至Dispatcher
- 日志服务端调用分发器内部的handle_events方法
- 分发器开始在多路监听器(一般为OS的select、epoll)上等待客户端请求
- 客户端连接至日志服务器
- 分发器通知Acceptor连接事件
- Accetor接受一个新的连接
2.客户端发送记录日志的请求
- 客户端使用上部分建立的连接发送记录日志的请求
- 客户端分发器将记录日志的时间通知给Handler
- Handler处理读请求然后内部在传递给下个Handler继续处理
- 最终Handler进行写响应
- 返回到分发器,分发器继续事件循环等待处理下个事件
以上的几种组件的作用和处理连接和请求事件的模式就是Reactor模式。
### 三.Scalable IO in Java
以上的Reactor模式只是简单的设计模型,对于每种程序语言设计而言,仍然需要做一些改变。基于Java的NIO如何使用该模式构建高性能可伸缩的服务,并发大神Doug Lea在他的网站上发布过一篇论文《Scalable IO in Java》。
这篇论文中主要谈及的话题是如何构建高性能可扩展的IO,其中就是基于Reactor模式进行了演进。
其中涉及到以下组件:
- Reactor: 响应IO事件,分发至相应的Handlers
- Handlers: 执行非阻塞的IO操作,
1.单线程Reactor模式
- 其中客户端发送请求至服务端,Reactor响应其IO事件。
- 如果是建立连接的请求,则将其分发至acceptor,由其接受连接,然后再将其注册至分发器。
- 如果是读请求,则分发至Handler,由其读出请求内容,然后对内容解码,然后处理计算,再对响应编码,最后发送响应
在整个过程中都是使用单线程,无论是Reactor线程和后续的Handler处理都只使用一个线程。
但是单线程无疑会降低性能,所以需要增加线程提供扩展。
2. 多线程Reactor模式
为了能够提高扩展性,需要在单线程的模型上增加线程,主要从两个方面利用多线程发挥多核的应用优势:
- Worker Threads,Reactor应该能够快速的触发事件,防止Handler处理的延迟Reactor的响应导致事件积累,最终导致客户端连接请求的积压,甚至服务端的句柄数耗尽,服务停止响应。所以在Handlers的处理中使用工作多线程
- Multiple Reactor Threads,使用多个Reactor线程用于响应客户端发起的事件,可以使用多个Reactor分担负载
以上多线程的Reactor处理模式中,Reactor线程仍然是单线程,负责acceptor和IO read/send。但是对于请求的解码以及业务处理和响应的编码都是有work thread pool负责。
3.多Reactor模式
上述的多线程模式解决了Handler降低Reactor的响应,同时也提升了Handler的处理效率。但是Reactor仍然是单线程,对于大量的网络事件,其仍然有负载压力。为了能够使用多线程分担压力,演进出多Reactor:
其中主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也是多线程模式,才有意义。
参考
Scalable IO in Java
Reactor Pattern
Netty — 线程模型的更多相关文章
- eventloop & actor模式 & Java线程模型演进 & Netty线程模型 总结
eventloop的基本概念可以参考:http://www.ruanyifeng.com/blog/2013/10/event_loop.html Eventloop指的是独立于主线程的一条线程,专门 ...
- Netty线程模型
一.Reactor模型 1.单线程模型 Reactor单线程模型,指的是所有的IO操作都在同一个NIO线程上面完成,NIO线程的职责如下: 1)作为NIO服务端,接收客户端的TCP连接: 2)作为NI ...
- Netty 线程模型
一.线程模型概述 线程模型表明了代码的执行方式.从最开始的使用单线程,后来出现了多线程,之后是线程池.当有要执行的任务时,任务会被传到线程池,从线程池中获得空闲的线程来执行任务,执行完了后会将线程返回 ...
- Netty系列之Netty线程模型
Reference: http://www.infoq.com/cn/articles/netty-threading-model 1. 背景 1.1. Java线程模型的演进 1.1.1. 单线程 ...
- 彻底搞懂 netty 线程模型
编者注:Netty是Java领域有名的开源网络库,特点是高性能和高扩展性,因此很多流行的框架都是基于它来构建的,比如我们熟知的Dubbo.Rocketmq.Hadoop等.本文就netty线程模型展开 ...
- Netty源码死磕一(netty线程模型及EventLoop机制)
引言 好久没有写博客了,近期准备把Netty源码啃一遍.在这之前本想直接看源码,但是看到后面发现其实效率不高, 有些概念还是有必要回头再细啃的,特别是其线程模型以及EventLoop的概念. 当然在开 ...
- Java后端进阶-网络编程(Netty线程模型)
前言 我们在使用Netty进行服务端开发的时候,一般来说会定义两个NioEventLoopGroup线程池,一个"bossGroup"线程池去负责处理客户端连接,一个"w ...
- Reactor三种线程模型与Netty线程模型
文中所讲基本都是以非阻塞IO.异步IO为基础.对于阻塞式IO,下面的编程模型几乎都不适用 Reactor三种线程模型 单线程模型 单个线程以非阻塞IO或事件IO处理所有IO事件,包括连接.读.写.异常 ...
- Netty核心概念(8)之Netty线程模型
1.前言 第7节初步学习了一下Java原本的线程池是如何工作的,以及Future的为什么能够达到其效果,这些知识对于理解本章有很大的帮助,不了解的可以先看上一节. Netty为什么会高效?回答就是良好 ...
- Netty源码学习(一)Netty线程模型
给你一台4路E7-4820V2(32核心64线程),512G内存的服务器,你该如何编程才能支持百万长连接? 最直接的想法是采用BIO的模式,为每个连接新建一个线程,在一一对应的线程中直接处理连接上的数 ...
随机推荐
- mysql DDL 锁表
mysql DDL 锁表 select trx_state, trx_started, trx_mysql_thread_id, trx_query from information_schema.i ...
- CTPN网络理解
本文主要对常用的文本检测模型算法进行总结及分析,有的模型笔者切实run过,有的是通过论文及相关代码的分析,如有错误,请不吝指正. 一下进行各个模型的详细解析 CTPN 详解 代码链接:https:// ...
- 使用 html2canvas 点击保存时把当前页面生成图片
style: #box{ background-image:url('./img/pone.png') } body: <div id="box" ...
- Thinkphp 5.1.24 parseKey缺陷导致聚合注入 分析
测试url: http://127.0.0.1/thinkphp/thinkphp_5.1.24/public/index.php/index/index/sqli2?id=2 控制器是获取id参数作 ...
- Git - Git版本库相关操作
创建Git版本库 如下命令实现在“E:\GitCode\01_TestGit”路径下,01_TestGit项目的Git版本库. $ cd E: #将当前目录转到E盘下 $ cd GitCode ...
- Tuple<T1,T2,.........T> 元组简单使用
元组:一个数据结构,逗号分隔,用于传递一个程序或者操作系统的一系列值得组合 NET Framework直接支持一至七元素得数组 Tuple<T1> Tuple<T1,T2> T ...
- requeests模块请求常用参数的写法整理
主要是针对写法 一.requests.get requests.get是调用了requests.request('get', url, params=params, **kwargs) 1.url 协 ...
- Linux介绍以及VMware和Centos的安装
一. Linux介绍 1 Linux诞生的故事 Unix篇: 为了进一步强化大型主机的功能,让主机的资源可以提供更多的使用者来利用,所以在1964年, 由AT&A公司的贝尔实验室(Bell). ...
- Flask 教程 第八章:粉丝
本文翻译自The Flask Mega-Tutorial Part VIII: Followers 这是Flask Mega-Tutorial系列的第八部分,我将告诉你如何实现类似于Twitter和其 ...
- MySQL逻辑控制语句的使用
一.IF语句 1). IF(expr1,expr2,expr3) 如果expr1为true则结果为expr2否则为expr3 -->相当于三元运算符 ...