springcloudAlibaba+dubbo线程拥堵Thread pool is EXHAUSTED

问题原因

1.由于dubbo服务的负载模式是轮询模式,导致每台机器上分配的任务数量是基本上相同的,但是由于服务部署并不是单机部署的(一台机器上面部署了多个服务),导致有些机器处理的速度较快,有些机器处理的较慢

2.由于dubbo的业务线程池设置的默认核心线程数量为200,线程池类型为fixed,并且线程队列为0(设置队列为0,目的也是为了防止队列堆积任务过多,导致上游调用超时),因此当机器处理任务缓慢时,任务一直占用线程未释放就会导致任务占用线程越来越多,最终导致线程池打满的问题。

解决过程

初步解决方案:增大线程数,增加实例数量(部署多个实例)

最开始,由于出现的问题是线程池被打满了,那么增大核心线程数量,减少每台机器的任务数量(增加实例)是不是可以解决问题呢,于是增加了每个dubbo服务的核心线程数量和部署的实例数量。发现增加到一定程度后确实可以解决dubbo线程池打满的问题,但是通过观察机器情况会发现有些机器处理任务的速度比较快,有些机器处理的则比较慢。于是进一步去分析机器情况,发现有些机器的cpu和内存存在基本打满的一个状态,于是就把部署在机器情况不是很良好的服务迁移到资源比较充足的机器上面,于是情况有了进一步改善。通过一系列操作后发现无脑增加线程数量可能并不是一个好的解决方案,因为更多线程数量意味着需要更多的内存(每个线程占用内存的大小取决于jvm参数中xss对每个线程栈大小的设置)和cpu切换的消耗。于是,接下来变尝试减小部署服务实例数和减少线程数。

改进方案:单机单实例部署,dubbo线程优化

既然多个服务部署在一台机器上会相互影响各个服务的机器资源分配问题,改成单机单实例呢。于是我们购买了几台8c16G的机器单独部署目标服务,发现情况有了进一步改善。单机单实例部署后进一步观察机器情况,发现随着机器能力的提升,任务处理速度和线程数量有了明显的降低(处理速度快,相应的就不会创建更多的线程)。于是发现可能服务根本用不了那么多线程,于是接下来开始对dubbo业务线程做进一步研究,看看有没有什么提升的地方。于是开始对dubbo业务线程模型进行分析结果如下:

  • 如果事件处理的逻辑能迅速完成,并且不会发起新的IO请求,比如只是在内存中记个标识。则直接在IO线程上处理更快,因为减少了线程池调度。
  • 但如果事件处理逻辑较慢,或者需要发起新的IO请求,比如需要查询数据库,则必须派发到线程池,否则IO线程阻塞,将导致不能接收其他请求。
  • 如果用IO线程处理事件,又在事件处理过程中发起新的IO请求,比如在连接事件中发起登录请求,会报“可能引发死锁”异常,但不会真死锁。

对于Dubbo集群中的Provider角色,有IO线程池(默认无界)和业务处理线程池(默认200,有界队列,队列大小为0)两个线程池,所以当业务的并发比较高,或者某些业务处理变慢,而且此时我们没给Provider的线程池配置等待Queue,业务线程池就很容易被“打满”,抛出“RejectedExecutionException: Thread pool is EXHAUSTED! ”异常。

既然Provider端已经抛出异常,表明自己已经受不了了,但线上我们却发现,Consumer无动于衷,发出的那笔请求还在一直等待直到超时。这样极其容易导致整个系统的“雪崩”,因为它违背了fail-fast原则。我们希望一旦Provider由于线程池被打满而无法收到请求,Consumer应该立即感知然后快速失败来释放线程。这是因为Dispatcher配置得不对,默认是all,我们应该配置成message。Dispatcher是dubbo线程池的分发策略:

all:所有消息都派发到线程池,包括请求,响应,连接事件,断开事件,心跳等。

direct:所有消息都不派发到线程池,全部在IO线程上直接执行。

message:只有请求响应消息派发到线程池,其他连接断开事件,心跳等消息,直接在IO线程上执行。

execution:只有请求消息派发到线程池,不含响应,响应和其他连接断开事件,心跳等消息,直接在IO线程上执行。

connection: 在IO线程上,将连接断开事件放入队列,有序逐个执行,其他消息派发到线程池。

于是我们根据业务类型将dubbo线程分发策略改为message,发现服务性能有了进一步提升,于是既然分发策略进行修改了,那么是不是可以对dubbo线程池类型做进一步优化呢?于是对dubbo中业务线程的类型做了进一步研究:dubbo线程池类型有:

fixed:固定大小的线程池,启动时建立线程,不关闭,一直持有。(缺省)

cached:缓存线程池,空闲一分钟自动删除,需要时重建。

limited:可伸缩线程池,但翅中线程数量只增长不会收缩。(为了避免大流量引起的性能问题)。

于是通过分析:我们将线程池类型切换为cached,因为我们业务类型为直播相关业务,有高峰期和空闲期,并且cached线程一分钟才会自动删除。再高峰期时也不会出现频繁重建的问题,并且相较于固定线程来索能减少对机器资源的消耗。

经过一系列改善后发现服务性能有了明显的提升。如果想做进一步的提升可以通过rpc通讯性能方面下手,这边给各位网友分享一遍网友写的关于rpc通讯协议性能的文章链接基于dubbo框架下的RPC通讯协议性能测试 - lengfo - 博客园

最后欢迎各位码友评论区交流沟通

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值