HttpClient异步调用引发的程序挂起问题排查及解决
在搭建搭建分布式系统时,基础组件与框架的重要性不言而喻。但是如果组件出现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异步调用引发的程序挂起问题排查及解决的更多相关文章
- Robotium调用getActivity()导致程序挂起的方法
1. 问题背景的叙述性说明 需要直接用在工作中没有项目的源代码robotium测试目标android平台launcher,该平台的基础上,当前日期的版本号android 4.4.2.之前我用来验证的可 ...
- 使用httpclient异步调用WebAPI接口
最近的工作需要使用Bot Framework调用原有的WebAPI查询数据,查找了一些方法,大部分都是使用HttpClient调用的,现时贴出代码供参考 using System; using Sys ...
- HttpClient异步调用WEB服务
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net ...
- Axis2(8):异步调用WebService
在前面几篇文章中都是使用同步方式来调用WebService.也就是说,如果被调用的WebService方法长时间不返回,客户端将一直被阻塞,直到该方法返回为止.使用同步方法来调用WebService虽 ...
- Axis2之异步调用
本章主要介绍axis2接口的异步调用方式. 一般情况下,我们使用同步方法(invokeBlocking)调用axis2接口,如果被调用的WebService方法长时间不返回,客户端将一直被阻塞,直到该 ...
- SpringBoot | 第二十一章:异步开发之异步调用
前言 上一章节,我们知道了如何进行异步请求的处理.除了异步请求,一般上我们用的比较多的应该是异步调用.通常在开发过程中,会遇到一个方法是和实际业务无关的,没有紧密性的.比如记录日志信息等业务.这个时候 ...
- SpringBoot的异步调用介绍
参考博客: https://www.cnblogs.com/jebysun/p/9675345.html https://blog.csdn.net/weixin_38399962/article/d ...
- SpringBoot:异步开发之异步调用
前言 除了异步请求,一般上我们用的比较多的应该是异步调用.通常在开发过程中,会遇到一个方法是和实际业务无关的,没有紧密性的.比如记录日志信息等业务.这个时候正常就是启一个新线程去做一些业务处理,让主线 ...
- [置顶] Ajax程序:处理异步调用中的异常(使用Asp.Net Ajax内建的异常处理方法)
无论在Window应用程序,还是Web应用程序以对用户友好的方式显示运行时的异常都是很有必要,尤其对于可能有很多不确定因素导致异常的Web应用程序;在传统的Web开发中,处理异常的方式——设计专门一个 ...
随机推荐
- tensorflow:验证码的识别(中)
三.训练识别模型 首先先拷贝一个nets文件夹,主要使用的是文件夹下的两个文件nets_factory.py.alexnet.py,用于导入训练使用的网络alexnet. nets_factory.p ...
- OS模块常用方法
#OS模块 #os模块就是对操作系统进行操作,使用该模块必须先导入模块: import os #getcwd() 获取当前工作目录(当前工作目录默认都是当前文件所在的文件夹) result = os. ...
- javascript 相关小的知识点集合
本文主要是列出一些javascript 相关的,不限于javascript的,容易记错或者遗忘的小知识,小技巧. 1.javascript中的false 在 JavaScript,常见的 false ...
- 【总结】瞬时高并发(秒杀/活动)Redis方案(转)
转载地址:http://bradyzhu.iteye.com/blog/2270698 1,Redis 丰富的数据结构(Data Structures) 字符串(String) Redis字符串能包含 ...
- Zabbix监控Nginx性能状态
Nginx在生产环境中的应用越来越广泛,所以需要对nginx的性能状态做一些监控,从而发现故障隐患,Ngnx的监控指标可分为:基本活动指标,错误指标,性能指标 监控Nginx思路: 1)首先,要想监控 ...
- root用户无法通过ssh连接Linux系统
ssh协议为了安全,有些版本默认禁止root用户的登陆 cd /etc/ssh 编辑sshd_config文件 cat sshd_config | grep PermitRootLogin Permi ...
- day70 cookie & session 前后端交互分页显示
本文转载自qimi博客,cnblog.liwenzhou.com 概要: 我们的cookie是保存在浏览器中的键值对 为什么要有cookie? 我们在访问浏览器的时候,千万个人访问同一个页面,我们只要 ...
- 在 Wiki 标记中添加无序列表
项目:在 Wiki 标记中添加无序列表在编辑一篇维基百科的文章时,你可以创建一个无序列表,即让每个列表项占据一行,并在前面放置一个星号.但是假设你有一个非常大的列表,希望添加前面的星号.你可以在每一行 ...
- html-div+span-4
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 队列queue实现线程的消费者和生产者
import threading import queue import random import time qq = queue.Queue(4) #实例化一个队列,因为是一个进程的线程,所以共资 ...