在搭建搭建分布式系统时,基础组件与框架的重要性不言而喻。但是如果组件出现bug,真的很要命。虽然我们通过各种单元测试,拼命找bug,但是总有一些问题被盲目自信蒙蔽了双眼,很多时候我们认为这段代码100%没有问题,但是我想说,没有100%没有问题的代码,只有你没想到的应用场景。下面就说一下最近技术组件出现的一次离奇的故障。

开始之前,先看看这个服务的压力,大约每分钟3700左右的样子,折合成TPS也就不到100的样子。

问题现象是,当服务程序重启后,系统一直没有结束的任务,并且线程持续增长,直到线程数增长到最大。

通过Dump分析发现,所有的线程都被一个线程阻塞,阻塞线程18.

进一步分析18号线程的堆栈发现,SetDatabaseConfig方法创建了一个Task,一直等待没有返回。

OK,看到这里,立马看一下程序的代码吧。代码中一个web请求,并且没有超时时间。

分析了这点代码后,简单整理了一下整个逻辑的调用过程。大体如下:

说明一下,获取数据库连接时,有一个全局的程序锁,锁中的逻辑是通过HttpClient远程访问WebAPI获取连接信息,并缓存到本地,上面的源代码就是在请求配置数据。通过上图我们可以看出,在HttpClient返回前,所有线程池中执行的任务,如果与数据库访问有关,都会被挂起。并且此时RPC服务持续受到请求,收到请求很快会被RPC服务消费并创建线程后交给线程池。这样可以解释为什么TeldHost.exe的线程持续增长的原因了。

分析到这里,还是毫无头绪,第一次调用加锁了,没有并发请求,按理说很快就可以返回了。百思不得其解,干脆写个模拟程序测测获取数据库连接的方法吧。

通过模拟程序测得,10并发时1s左右所有调用都完成了,100并发时需要9秒多,1000并发时需要350s。尼玛,果然有问题。通过review里面的代码,极度怀疑是HttpClient搞的鬼。通过翻看HttpClient的源代码,我们会发现,后台是通过Task实现的异步请求。看到这里恍然大悟,典型的HttpClient发起请求后,创建的task ,但是task拿不到线程的执行权引起的线程资源竞争。因为来自前端的压力一直很大,一直没有空闲线程,HttpClient一直在处理阻塞等待状态。

果断把HttpClient异步调用改为同步调用,通过多次压测验证,问题得到解决。下面是修复后的代码。

HttpClient异步调用引发的程序挂起问题排查及解决的更多相关文章

  1. Robotium调用getActivity()导致程序挂起的方法

    1. 问题背景的叙述性说明 需要直接用在工作中没有项目的源代码robotium测试目标android平台launcher,该平台的基础上,当前日期的版本号android 4.4.2.之前我用来验证的可 ...

  2. 使用httpclient异步调用WebAPI接口

    最近的工作需要使用Bot Framework调用原有的WebAPI查询数据,查找了一些方法,大部分都是使用HttpClient调用的,现时贴出代码供参考 using System; using Sys ...

  3. HttpClient异步调用WEB服务

    using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net ...

  4. Axis2(8):异步调用WebService

    在前面几篇文章中都是使用同步方式来调用WebService.也就是说,如果被调用的WebService方法长时间不返回,客户端将一直被阻塞,直到该方法返回为止.使用同步方法来调用WebService虽 ...

  5. Axis2之异步调用

    本章主要介绍axis2接口的异步调用方式. 一般情况下,我们使用同步方法(invokeBlocking)调用axis2接口,如果被调用的WebService方法长时间不返回,客户端将一直被阻塞,直到该 ...

  6. SpringBoot | 第二十一章:异步开发之异步调用

    前言 上一章节,我们知道了如何进行异步请求的处理.除了异步请求,一般上我们用的比较多的应该是异步调用.通常在开发过程中,会遇到一个方法是和实际业务无关的,没有紧密性的.比如记录日志信息等业务.这个时候 ...

  7. SpringBoot的异步调用介绍

    参考博客: https://www.cnblogs.com/jebysun/p/9675345.html https://blog.csdn.net/weixin_38399962/article/d ...

  8. SpringBoot:异步开发之异步调用

    前言 除了异步请求,一般上我们用的比较多的应该是异步调用.通常在开发过程中,会遇到一个方法是和实际业务无关的,没有紧密性的.比如记录日志信息等业务.这个时候正常就是启一个新线程去做一些业务处理,让主线 ...

  9. [置顶] Ajax程序:处理异步调用中的异常(使用Asp.Net Ajax内建的异常处理方法)

    无论在Window应用程序,还是Web应用程序以对用户友好的方式显示运行时的异常都是很有必要,尤其对于可能有很多不确定因素导致异常的Web应用程序;在传统的Web开发中,处理异常的方式——设计专门一个 ...

随机推荐

  1. OpenCV-Python入门教程2-打开摄像头

    一.打开摄像头 import cv2 # 打开摄像头并灰度化显示 capture = cv2.VideoCapture(0) while(True): # 获取一帧 ret, frame = capt ...

  2. #Plugin 数字滚动累加动画插件

    数字滚动累加动画插件  NumScroll 1.使用前先引入jquery2.前端学习群:814798690 下载地址 https://github.com/chaorenzeng/jquery.num ...

  3. C#学习-面向对象

    封装:把客观事物封装成类,并将类内部的实现隐藏,以保证数据的完整性: 比如年龄赋值为负数,就是个例子.当我们把类的字段定义为公共类型时,外部对象可以直接对类内部的数据进行操作,此时无法对这些操作进行一 ...

  4. 移动端根据不同DPR加载大小不同的图片

    1.首先创建mixin.styl文件代码如下: bg-image($url) // 创建bg-image($url)函数 background-image: url($url + "@2x. ...

  5. python全栈开发day76-博客主页

    一.昨日内容 1. 注册 1. form组件 - 基于正则的校验规则(手机号和邮箱) - 基于全局钩子判断两次密码是否一致 2. $.each(遍历的对象, function(){ this --&g ...

  6. markdown 语法小结

    1 标题 # 一级标题 ## 二级标题 2  字体加粗和斜体 *斜体* **加粗** 3.引用 > 4.换行 空行 或两个空格+tab 5.无序列表 + 第一个 + 第二个 - 第一个 - 第二 ...

  7. mysql配置为半同步复制

    mysql 半同步插件是由谷歌提供,具体位置/usr/local/mysql/lib/plugin/下,一个是 master用的 semisync_master.so,一个是 slave 用的 sem ...

  8. BZOJ4556 [Tjoi2016&Heoi2016]字符串 SA ST表 二分答案 主席树

    原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ4556.html 题目传送门 - BZOJ4556 题意 给定一个长度为 $n$ 的字符串 $s$ . ...

  9. Codeforces 980F Cactus to Tree 仙人掌 Tarjan 树形dp 单调队列

    原文链接https://www.cnblogs.com/zhouzhendong/p/CF980F.html 题目传送门 - CF980F 题意 给定一个 $n$ 个节点 $m$ 条长为 $1$ 的边 ...

  10. 场景/故事/story——寻物者发布消息场景、寻失主发布消息场景、消息展示场景、登录网站场景

    1.背景:(1)典型用户:吴昭[主要]  尤迅[次要] 王丛[次要] 佑豪[次要](2)用户的需求/迫切需要解决的问题a.吴昭:经常在校园各个地方各个时间段,丢失物品需要寻找.b.吴昭:偶尔浏览一下最 ...