dubbo线程池为什么耗尽

文章概述

大家可能都遇到过DUBBO线程池打满这个问题,报错如下,本文我们就一起分析DUBBO线程池打满这个问题。
cause: org.apache.dubbo.remoting.RemotingException: Server side(10.0.0.100,20881) thread pool is exhausted, detail msg:Thread pool is EXHAUSTED! Thread Name: DubboServerHandler-10.0.0.100:20881, Pool Size: 800 (active: 800, core: 800, max: 800, largest: 800), Task: 50397601 (completed: 50396801), Executor status:(isShutdown:false, isTerminated:false, isTerminating:false), in dubbo://10.0.0.100:20881!

1 DUBBO线程模型

先看一张图大概了解
未命名文件 (5).png

** IO线程**

IO线程的工作实际上就是处理字节流的输入输出,对消息的读取,序列化,不涉及业务操作
NettyServer中启动netty服务端,初始化boss和work线程信息

  protected void doOpen() throws Throwable {bootstrap = new ServerBootstrap();bossGroup = NettyEventLoopFactory.eventLoopGroup(1, "NettyServerBoss");workerGroup = NettyEventLoopFactory.eventLoopGroup(getUrl().getPositiveParameter(IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS),"NettyServerWorker");final NettyServerHandler nettyServerHandler = new NettyServerHandler(getUrl(), this);channels = nettyServerHandler.getChannels();bootstrap.group(bossGroup, workerGroup).channel(NettyEventLoopFactory.serverSocketChannelClass()).option(ChannelOption.SO_REUSEADDR, Boolean.TRUE).childOption(ChannelOption.TCP_NODELAY, Boolean.TRUE).childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT).childHandler(new ChannelInitializer<SocketChannel>() {@Overrideprotected void initChannel(SocketChannel ch) throws Exception {// FIXME: should we use getTimeout()?int idleTimeout = UrlUtils.getIdleTimeout(getUrl());NettyCodecAdapter adapter = new NettyCodecAdapter(getCodec(), getUrl(), NettyServer.this);if (getUrl().getParameter(SSL_ENABLED_KEY, false)) {ch.pipeline().addLast("negotiation",SslHandlerInitializer.sslServerHandler(getUrl(), nettyServerHandler));}ch.pipeline().addLast("decoder", adapter.getDecoder()).addLast("encoder", adapter.getEncoder()).addLast("server-idle-handler", new IdleStateHandler(0, 0, idleTimeout, MILLISECONDS)).addLast("handler", nettyServerHandler);}});// bindChannelFuture channelFuture = bootstrap.bind(getBindAddress());channelFuture.syncUninterruptibly();channel = channelFuture.channel();}

这里分别看线程数量

    bossGroup = NettyEventLoopFactory.eventLoopGroup(1, "NettyServerBoss");workerGroup = NettyEventLoopFactory.eventLoopGroup(getUrl().getPositiveParameter(IO_THREADS_KEY, Constants.DEFAULT_IO_THREADS),"NettyServerWorker");
int DEFAULT_IO_THREADS = Math.min(Runtime.getRuntime().availableProcessors() + 1, 32);

boss线程设置为1
主要看work线程(IO线程)
从url中获取线程数,如果没设置的话,设置当前机器的线程数,最少设置为32个
这个配置是iothreads,如果配置的这样配置。但是线程池耗尽并不是io线程数量不够的原因

provider:iothreads: 100
@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {NettyChannel channel = NettyChannel.getOrAddChannel(ctx.channel(), url, handler);handler.received(channel, msg);}
  @Overridepublic void received(Channel channel, Object message) throws RemotingException {setReadTimestamp(channel);if (isHeartbeatRequest(message)) {Request req = (Request) message;if (req.isTwoWay()) {Response res = new Response(req.getId(), req.getVersion());res.setEvent(HEARTBEAT_EVENT);channel.send(res);if (logger.isInfoEnabled()) {int heartbeat = channel.getUrl().getParameter(Constants.HEARTBEAT_KEY, 0);if (logger.isDebugEnabled()) {logger.debug("Received heartbeat from remote channel " + channel.getRemoteAddress()+ ", cause: The channel has no data-transmission exceeds a heartbeat period"+ (heartbeat > 0 ? ": " + heartbeat + "ms" : ""));}}}return;}if (isHeartbeatResponse(message)) {if (logger.isDebugEnabled()) {logger.debug("Receive heartbeat response in thread " + Thread.currentThread().getName());}return;}handler.received(channel, message);}

消息的不同类型有不同的处理方式如果是心跳直接就发送回去了,
如果是业务请求那么交给业务线程池处理

  @Overridepublic void received(Channel channel, Object message) throws RemotingException {ExecutorService executor = getPreferredExecutorService(message);try {executor.execute(new ChannelEventRunnable(channel, handler, ChannelState.RECEIVED, message));} catch (Throwable t) {if(message instanceof Request && t instanceof RejectedExecutionException){sendFeedback(channel, (Request) message, t);return;}throw new ExecutionException(message, channel, getClass() + " error when process received event .", t);}}

业务线程池

初始化
不同线程池策略会创建不同特性的线程池:
dubbo提供了不同的线程池类型

fixed
包含固定个数线程cached
线程空闲一分钟会被回收,当新请求到来时会创建新线程limited
线程个数随着任务增加而增加,但不会超过最大阈值。空闲线程不会被回收eager
当所有核心线程数都处于忙碌状态时,优先创建新线程执行任务,而不是立即放入队列

一般实际使用的就是fixed

public class FixedThreadPool implements ThreadPool {@Overridepublic Executor getExecutor(URL url) {String name = url.getParameter(THREAD_NAME_KEY, DEFAULT_THREAD_NAME);int threads = url.getParameter(THREADS_KEY, DEFAULT_THREADS);int queues = url.getParameter(QUEUES_KEY, DEFAULT_QUEUES);return new ThreadPoolExecutor(threads, threads, 0, TimeUnit.MILLISECONDS,queues == 0 ? new SynchronousQueue<Runnable>() :(queues < 0 ? new LinkedBlockingQueue<Runnable>(): new LinkedBlockingQueue<Runnable>(queues)),new NamedInternalThreadFactory(name, true), new AbortPolicyWithReport(name, url));}}

这里主要看两个参数,分别是线程数,和队列长度。默认的线程数是200,queue默认使用SynchronousQueue
SynchronousQueue由于其独有的线程一一配对通信机制,由于内部没有使用AQS,而是直接使用CAS,其并没有存储任务的队列就是将任务与线程进行匹配,如果任务进来,没用可用线程,那么将直接拒绝,这也是我们碰到拒绝策略的原因
如果需要配置

dubbo:protocol:threads: 800queues: 10000

业务线程线程池拒绝

这里就可以看到线程池拒绝AbortPolicyWithReport

 @Overridepublic void rejectedExecution(Runnable r, ThreadPoolExecutor e) {String msg = String.format("Thread pool is EXHAUSTED!" +" Thread Name: %s, Pool Size: %d (active: %d, core: %d, max: %d, largest: %d), Task: %d (completed: "+ "%d)," +" Executor status:(isShutdown:%s, isTerminated:%s, isTerminating:%s), in %s://%s:%d!",threadName, e.getPoolSize(), e.getActiveCount(), e.getCorePoolSize(), e.getMaximumPoolSize(),e.getLargestPoolSize(),e.getTaskCount(), e.getCompletedTaskCount(), e.isShutdown(), e.isTerminated(), e.isTerminating(),url.getProtocol(), url.getIp(), url.getPort());logger.warn(msg);dumpJStack();throw new RejectedExecutionException(msg);}

也就是开头的那个报错,这里在发生问题会自动dump stack信息

线程池中的 getTaskCount 和 getCompletedTaskCount 是两个重要的方法,它们用于获取线程池的任务和已完成任务的统计信息。

  1. getTaskCount: 这个方法返回线程池中的当前任务数。它包括正在执行的任务和等待执行的任务。换句话说,它返回的是线程池中所有任务的总数,包括那些尚未开始执行的任务。
  2. getCompletedTaskCount: 这个方法返回线程池已完成的任务数量。它只计算那些已经完成执行的任务,而不包括正在执行或等待执行的任务。

再回头我们的那个报错。
Pool Size: 800 (active: 800, core: 800, max: 800, largest: 800), Task: 50397601 (completed: 50396801)

2、估算合适的线程数,寻找慢业务

我们知道DUBBO会选择线程池策略进行业务处理,那么如何估算可能产生的线程数呢?我们首先分析一个问题:一个公司有7200名员工,每天上班打卡时间是早上8点到8点30分,每次打卡时间系统耗时5秒。请问RT、QPS、并发量分别是多少?
RT表示响应时间,问题已经告诉了我们答案:
RT = 5

QPS表示每秒查询量,假设签到行为平均分布:
QPS = 7200 / (30 * 60) = 4

并发量表示系统同时处理的请求数量:
并发量 = QPS x RT = 4 x 5 = 20

根据上述实例引出如下公式:
并发量 = QPS x RT

如果系统为每一个请求分配一个处理线程,那么并发量可以近似等于线程数。基于上述公式不难看出并发量受QPS和RT影响,这两个指标任意一个上升就会导致并发量上升。
但是这只是理想情况,因为并发量受限于系统能力而不可能持续上升,例如DUBBO线程池就对线程数做了限制,超出最大线程数限制则会执行拒绝策略,而拒绝策略会提示线程池已满,这就是DUBBO线程池打满问题的根源。下面我们分别分析RT上升和QPS上升这两个原因。
注意上面仅仅是一个例子,实际上一个服务远比例子复杂,实践往往需要不断的调参数。才能找到合理的值
线程池耗尽,往往是因为某个业务慢导致,我们应该寻找执行缓慢的堆栈,例如使用arthas来监控。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/319087.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

手把手教你写DI_0_DI是什么?

DI是什么&#xff1f;Dependency Injection 常常简称为&#xff1a;DI。它是实现控制反转&#xff08;Inversion of Control – IoC&#xff09;的一个模式。fowler 大大大神 “几十年”前的经典文章 https://www.martinfowler.com/articles/injection.html 说的很清楚。“几十…

C++顺序创建txt文件

今天下午在对拍数据的时候感觉好麻烦。。 一次次手调文件名称&#xff0c;突然想起可以直接写段程序集中操作 顺序输出 #include <iostream> #include <fstream> #include<string> using namespace std;int main () {ofstream File;for(int i0;i<3;i){str…

使用Visual Studio Code开发.NET Core看这篇就够了

在本文中&#xff0c;我将带着大家一步一步的通过图文的形式来演示如何在Visual Studio Code中进行.NET Core程序的开发&#xff0c;测试以及调试。尽管Visual Studio Code的部分功能还达不到Visual Studio的水平&#xff0c;但它实际上已经足够强大来满足我们的日常开发。而且…

手把手教你写DI_3_小白徒手支持 Singleton 和 Scoped 生命周期

在上一节&#xff1a;手把手教你写DI_2_小白徒手撸构造函数注入浑身绷带的小白同学&#xff1a;我们继续开展我们的工作&#xff0c;大家都知道 Singleton是什么&#xff0c;就是全局只有一个呗&#xff0c;我们就先从它开始&#xff0c;这个多简单&#xff0c;我们找个字典放这…

手把手教你写DI_2_小白徒手撸构造函数注入

在上一节&#xff1a;手把手教你写DI_1_DI框架有什么&#xff1f;我们已经知道我们要撸哪些东西了那么我们开始动工吧&#xff0c;这里呢&#xff0c;我们找小白同学来表演下小白同学 &#xff1a;我们先定义一下我们的广告招聘纸有什么&#xff1a;好&#xff0c;我们实现两种…

服务器win2008 R2 x64 部署ASP.net core到IIS 并解决 HTTP Error 502.5 的问题

1、发布网站 &#xff1b;2、安装 vc_redist.x64 (Visual C Redistributable for Visual Studio 2015) 新装的系统没装的补丁&#xff0c;装过略过&#xff1b;3、安装WindowsHosting &#xff1a;如&#xff1a; dotnet-hosting-2.1.3-win &#xff1b;4、安装.Net Core SDK&…

Data Structure Problem

试题链接 题目描述 题意&#xff1a; 有两个序列&#xff0c; 操作1是将a序列的第x位改成y 操作2是将b序列的第x位改成y 操作3是找到一个cx&#xff0c;满足递推式c00&#xff0c;ci max(ci-1bi&#xff0c;ai) 题解&#xff1a; 官方题解 说实话我没大看懂。。。 题是我同…

定制Ocelot来满足需求

这篇文章&#xff0c;我们将从Ocelot的中间件源码分析&#xff0c;目前Ocelot已经实现那些功能&#xff0c;还有那些功能在我们实际项目中暂时还未实现&#xff0c;如果我们要使用这些功能&#xff0c;应该如何改造等方面来说明。一、Ocelot源码解读在使用一个组件前&#xff0…

【.NET Core项目实战-统一认证平台】第一章 功能及架构分析

从本文开始&#xff0c;我们正式进入项目研发阶段&#xff0c;首先我们分析下统一认证平台应该具备哪些功能性需求和非功能性需求&#xff0c;在梳理完这些需求后&#xff0c;设计好系统采用的架构来满足已有的需求和未来的扩展应用。1 功能性需求统一认证平台应该具备以下基本…

Shift and Reverse

题目链接 题意&#xff1a; 一个序列a1&#xff0c;a2&#xff0c;a3…an 选择一个i&#xff0c;然后将序列改成ai,ai-1,…a1,an,an-1,…ai1 可以进行无数次这样的操作 问&#xff1a;最多有多少不同的序列产生&#xff1f;&#xff08;答案mod1e97&#xff09; 题解&#xf…

Redis基本使用及百亿数据量中的使用技巧分享

作者&#xff1a;依乐祝原文地址&#xff1a;https://www.cnblogs.com/yilezhu/p/9941208.html作者&#xff1a;大石头时间&#xff1a;2018-11-10 晚上20&#xff1a;00地点&#xff1a;钉钉群&#xff08;组织代码BKMV7685&#xff09;QQ群&#xff1a;1600800内容&#xff1…

Subsequence Pair

题目 题目描述 题意&#xff1a; X和Y两个字符串&#xff0c;两个字符串各取子序列X1和Y1&#xff0c;问X1<Y1的情况下X1和Y1的长度和最长是多少&#xff1f; 比如例子&#xff1a; zazxwabzczazazd abcaa 第一个字符串选取子序列为azxwabzczazazd 第二个为bcaa azxwabzc…

【.NET Core项目实战-统一认证平台】第三章 网关篇-数据库存储配置(1)

本篇将介绍如何扩展Ocelot中间件实现自定义网关&#xff0c;并使用2种不同数据库来演示Ocelot配置信息存储和动态更新功能&#xff0c;内容也是从实际设计出发来编写我们自己的中间件&#xff0c;本文内容涵盖设计思想内容和代码内容&#xff0c;我希望园友们最好跟着我这个文章…

一个技术管理者的苦逼【技术管理漫谈】

希望给你3-5分钟的碎片化学习&#xff0c;可能是坐地铁、等公交&#xff0c;积少成多&#xff0c;水滴石穿&#xff0c;谢谢关注。角色转变 从工程师转技术管理这两年&#xff0c;好比头马变成车夫&#xff0c;除了角色认知的转变&#xff0c;还要看方向&#xff0c;定计划。不…

[机器翻译]参与 Microsoft 开放源代码软件项目的方式

下面是一个事实&#xff1a;Microsoft 托管在 GitHub&#xff0c;包括.NET 编译器平台&#xff0c;也称为"Roslyn"具有多达 4 万行代码等一些相当大的大约 2,000 开放源代码软件 (OSS) 存储库。很多开发人员的代码将更改提交到数以百万计的计算机运行的项目可能会令人…

【蓝桥杯】 2018年国赛 矩阵求和

题目 题目&#xff1a; 经过重重笔试面试的考验&#xff0c;小明成功进入 Macrohard 公司工作。 今天小明的任务是填满这么一张表&#xff1a; 表有 n 行 n 列&#xff0c;行和列的编号都从1算起。 其中第 i 行第 j 个元素的值是 gcd(i, j)的平方&#xff0c; gcd 表示最大公…

被低估的.net(上) - 微软MonkeyFest 2018广州分享会活动回顾

前天, 2018年11月10日, 广州图书馆\微软云开发者社区\广东职业教育信息化研究会\珠三角技术沙龙在广州图书馆负一层1号报告厅搞了一场”微软最有价值专家(MVP)广州分享会 - MonkeyFest 2018广州分享会”. 这是在广州图书馆官方微信公众号上的活动报名链接: https://mp.weixin.q…

C#的RSA加密解密签名,就为了支持PEM PKCS#8格式密钥对的导入导出

差点造了一整个轮子.Net Framework 4.5 里面的RSA功能&#xff0c;并未提供简单对PEM密钥格式的支持&#xff08;.Net Core有咩&#xff1f;&#xff09;&#xff0c;差点&#xff08;还远着&#xff09;造了一整个轮子&#xff0c;就为了支持PEM PKCS#8、PKCS#1格式密钥对的导…

福州首届.NET开源社区技术交流会圆满成功

活动总结2018年11月10日周六的下午&#xff0c;在福州蒲公英创新工场举办了福州首届.NET开源社区技术交流会&#xff0c;来自福建省各大科技公司的技术小伙伴齐聚一堂&#xff0c;为了就是能在现场学习到微软跨平台技术.NET Core、微服务以及Azure云服务。在交流会现场&#xf…

.NET Core开发者的福音之玩转Redis的又一傻瓜式神器推荐

引子为什么写这篇文章呢&#xff1f;因为.NET Core的生态越来越好了&#xff01;之前玩转.net的时候操作Redis相信大伙都使用过一些组件&#xff0c;但都有一些缺点&#xff0c;如ServiceStack.Redis 是商业版&#xff0c;免费版有限制&#xff1b;StackExchange.Redis 是免费版…