chapter18 EventLoop和EventLoopGroup
来源:互联网 发布:淘宝界面 购物车代码 编辑:程序博客网 时间:2024/06/04 20:02
- chapter18 EventLoop和EventLoopGroup
- Reactor单线程模型
- Reactor多线程模型
- 主从Reactor多线程模型
- 4Netty的线程模型
- 5NioEventLoop源码分析
chapter18 EventLoop和EventLoopGroup
1. Reactor单线程模型:
- 异步非阻塞,理论上一个线程可以独立处理所有IO相关操作。
- 不适合高负载、高并发场景原因:
- 一个NIO线程同时处理成百上千的链路,性能无法支撑,即便NIO线程的cpu负荷达到100%,也无法满足海量消息的编码、解码、读取与发送。
- 当NIO线程负载过重之后,处理速度将变慢,这会导致大量客户端连接超时,超时重发导致消息积压和处理超时。
- 可靠性问题:一旦NIO线程意外跑飞,或者进入死循环,会导致整个系统通信模块不可用,造成节点故障。
2. Reactor多线程模型:
- 最大的区别就是有一组NIO线程来处理IO操作。
- 特点:
- 有专门一个NIO线程——Acceptor线程用于监听服务端,接收客户端的TCP连接请求。
- 网络IO操作——读、写等由一个NIO线程池负责,线程池可以采用标准的JDK线程池实现,它包含一个任务队列和N个可用的线程,由这些NIO线程负责消息的读取、解码、编码和发送。
- 一个NIO线程可以同时处理N条链路,但是一个链路只对应一个NIO线程,防止发生并发操作问题。
- 问题:
- 一个NIO线程负责监听和处理所有客户端连接,并发百万客户端连接或者服务端需要对客户端握手进行安全认证,此类场景下,单独一个Acceptor可能会存在性能问题。
3. 主从Reactor多线程模型
- 特点:服务端用于接收客户端连接的不再是一个单独的NIO线程,而是一个独立的NIO线程池。
- Acceptor线程池仅仅用于客户端的登陆、握手和安全认证,一旦链路建立成功,就将链路注册到后端subReactor线程池的IO线程上,由IO线程负责处理后续的IO操作。
4、Netty的线程模型
- 通过调整线程池个数、是否共享线程池等方式,Netty的Reactor线程模型可以在单线程、多线程和主从线程间切换。
- 服务启动的时候,创建了两个独立的Reactor线程池,一个用于接收客户端的TCP链接,一个用于处理IO相关的读写操作,或者执行系统Task、定时任务Task等。
Netty用于接收客户端请求的线程池职责:
- 接收客户端TCP链接,初始化Channel参数;
- 将链路状态变更事件通知给CHannelPipeline
Netty处理IO操作的Reactor线程池职责:
- 异步读取通信对端的数据报,发送读事件到ChannelPipeline
- 异步发送消息到通信对端,调用ChannelPipeline的消息发送接口
- 执行系统调用Task;
- 执行定时任务Task,例如链路空闲状态监测定时任务。
采用无锁化设计,如在IO线程内部进行串行操作,避免多线程竞争导致性能下降,相比一个队列多个工作线程的模型性能更优。
最佳实践:[总的来说Handler尽早释放,完成IO线程内的串行]
- 创建两个NioEventLoopGroup,用于逻辑隔离NIO Acceptor和NIO IO线程;
- 尽量不要在ChannelHandler中启动用户线程(解码后用于将POJO消息派发到后端业务线程的除外);
- 解码要放在NIO线程调用的解码Handler中机型,不要切换到用户线程中完成消息的解码;
- 如果业务逻辑操作非常简单,没有复杂业务逻辑计算,没有可能会导致线程被阻塞的磁盘操作等,可以直接在NIO线程上完成业务逻辑编排,不需要切换用户线程。
- 如果业务逻辑复杂,不要在NIO线程完成业务逻辑计算,建议将解码后的POJO消息封装成Task,派发到业务线程池中由业务线程执行,以保证NIO线程尽快释放,处理其他IO操作。
推荐线程数量计算公式:
- 线程数量 =(线程总时间/瓶颈资源时间)* 瓶颈资源的线程并行数
- QPS=1000/线程总时间*线程数
5、NioEventLoop源码分析
NioEventLoop设计原理
- 除了负责IO的读写外,还处理以下两类任务:
- 系统Task:通过调用NioEventLoop的execute(Runnable task)方法实现,Netty有很多系统Task,解决IO线程和用户线程同时操作网络资源时,防止并发操作导致资源竞争,将用户封装成Task放入消息队列中,由IO线程负责执行,实现局部无锁化。
- 定时任务:通过调用NioEventLoop的schedule(Runnable command,long dalay,TimeUnit unit)方法实现。
- 除了负责IO的读写外,还处理以下两类任务:
NioEventLoop
- 由于需要处理网络IO读写事件,因此必须聚合一个多路复用器对象(Selector)。Netty对Selector的selectedKeys进行了优化,用户可以通过io.netty.noKeySetOptimization开关决定是否启用该优化项。默认不打开。优化的好处,在于每次在轮询到nio事件的时候,netty只需要O(1)的时间复杂度就能将 SelectionKey 塞到 set中去,而jdk底层使用的hashSet需要O(lgn)的时间复杂度
- 所有的逻辑都在for循环体内运行。只有当NioEventLoop接收到退出指令的时候才退出循环体。
- Seletor空轮询导致的epoll bug使IO线程一直处于100%状态,Netty解决方案:
- 对Selector的select操作周期进行统计;
- 每完成一次空的select操作进行一次计数;
- 在某个周期(例如100ms)内如果连续发生N次空轮询,说明触发了epoll()死循环bug
- 监听到Selector处于死循环后,需要通过重建Selector的方式让系统恢复正常。
阅读全文
0 0
- chapter18 EventLoop和EventLoopGroup
- 第18章 EventLoop和EventLoopGroup
- EventLoop与EventLoopGroup
- Netty线程模型及EventLoop和EventLoopGroup源码解析
- netty(八)源码分析之eventLoop和eventLoopGroup
- netty源码学习二(EventLoopGroup、EventLoop)
- [netty源码分析]--EventLoopGroup与EventLoop 分析netty的线程模型
- EventLoop
- Netty 权威指南笔记(八):EventLoopGroup 和线程模型
- 【第07章】【EventLoop和线程模型】
- Netty:EventLoopGroup
- muduo网络库学习之EventLoop(二):进程(线程)wait/notify 和 EventLoop::runInLoop
- 从epoll构建muduo-6 加入EventLoop和Epoll
- 对EventLoop和性能问题处理的理解
- 16 从EventLoop取消注册和重新注册
- 从epoll构建muduo-6 加入EventLoop和Epoll
- 第十一篇:从EventLoop取消注册和重新注册
- Netty in action—EventLoop和线程模型
- synchronized的补充
- MySQL设计之三范式的理解
- 点亮人生中第一个发光二极管
- C++中简单的文本文件输入/输出
- Angular 控制器之间的通信
- chapter18 EventLoop和EventLoopGroup
- 一道切线和圆有关的几何证明题及解析解答
- 可控硅电路的电容电阻的作用
- 桥接模式(构造型设计模式)
- open函数的一些注意点及r,r+,w,w+,a,a+的区别
- VirtualBox-5.1.30.18389-Win安装包分享 百度云
- axios的一些常见用法
- 一个项目结尾:事务
- MySQL事务