业务线程池阻塞分析

本文探讨了如何避免Netty Nio线程因业务处理阻塞而挂死,重点介绍了正确使用CallerRunsPolicy策略、合理设计业务线程池以及Netty多线程最佳实践,包括创建独立的NIO线程组、解码策略和任务调度。
摘要由CSDN通过智能技术生成
在一些业务处理ChannelHandler中执行一些耗时任务或者其他任务时,通常不会使用Nio线程来做,而是调度到其他的业务线程池去做。
线程池ThreadPoolExecutor的 CallerRunsPolicy策略:如果当前线程池任务队列满了,新增的任务交由调度前的线程来执行
如果后端业务逻辑处理慢,则会导致业务线程池阻塞队列积压,当积压达到容量上限时,JDK会抛出RejectedExecutionException异常,由于业务设置了CallerRunsPolicy策略,就会由调用方的线程NioEventLoop执行业务逻辑,最终导致 NioEventLoop线程被阻塞,无法读取请求消息
造成的现象就是,如果NioEventLoop线程阻塞,则一段时间内客户端的网络消息IO会丢失,这段时间服务端接收不到消息。从阻塞状态恢复后就又可以接收到消息了。
除了JDK线程池异常处理策略使用不当,有些业务人员喜欢自己写阻塞队列,当队列满时,向队列加入新的消息会阻塞当前线程,直到消息能够加入队列。案例中的车联网服务端真实业务代码就有此类问题:当转发到下游系统发生某些故障时,会导致业务定义的阻塞队列无法弹出消息进行处理,当队列积压满时,就会阻塞Netty的NIO线程,而且无法自动恢复。

【防止NioEventLoop挂死】

防止Nio线程挂死的方法就是,NioEventLoop只处理网络I/O,业务消息调度给业务线程池处理。

【netty内多线程最佳实践】

(1) 创建两个NioEventLoopGroup,用于逻辑隔离NIO Acceptor和 NIOI/O线程
(2)尽量不要在ChannelHandler中启动用户线程(解码后用于将POJO消息派发到后端业务线程的除外)。
(3) 解码要放在NIO线程调用的解码Handler中进行,不要切换到用户线程完成消息的解码,相对于切换线程的开销收益更大
(4) 如果业务逻辑操作非常简单(纯内存操作),没有复杂的业务逻辑计算,也没有可能会导致线程被阻塞的磁盘操作、数据库操作、网络操作等,可以直接在NIO线程上完成业务逻辑编排,不需要切换到用户线程,相对于切换线程的开销收益更大
(5)如果业务逻辑复杂,不要在 NIO线程上完成,建议将解码后的POJO消息封装成任务, 派发到业务线程池中由业务线程执行,以保证NIO线程尽快被释放,处理其他的1/O操作
推荐的线程数量计算公式有以下两种。
(1)公式1:线程数量=(线程总时间/瓶颈资源时间)x瓶颈资源的线程并行数。
(2)公式2:QPS= 1000/线程总时间×线程数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0x13

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值