一次Mysql连接池卡死导致服务无响应问题分析(.Net Mysql.Data 6.9.9)
问题:
进程启动后,线程数迅速上升至最小线程数后,缓慢上升(线程池限制)到数千,然后由于线程过多,CPU飙升到90%。
对外表现为Api无响应或连接超时。
背景
有些数据存在于另一个机房,通过内网专线连接。一个服务程序有4个数据库,其中3个在本地机房,1个在外地。
各种排查,没有解决。
最终的处理方法
Dump进程
- 使用进程管理器,创建进程Dump文件。
- 使用VisualStudio打开该Dump文件并进行托管调试
- 查看并行堆栈,发现大部分线程均处于MySql.Data.MySqlClient.MySqlPoolManager.GetPool这个函数的调用中。并在此处进入了本机代码。处于其他调用堆栈的线程屈指可数。
代码分析
- 由于Mysql.Data.dll没有对应的pdb文件(Oracle没有提供),所以在Visual Studio中不能进入其中的代码,因此直接反编译,找到该函数,代码如下:
函数中,第一句的GetKey函数如下,其中有一个lock。其中代码仅仅是赋值,或是在集成认证的情况下才执行。所以卡住的可能性不大。
第二句是个赋值,且MysqlPoolManager.pools是个字段(field),理论上不会卡住。
第二个lock中,如果指定key对应的缓存已存在,则lock会很快返回。如果不存在,则执行new MysqlPool(setttings);函数代码如下:
其主要功能有
- 创建一个事件,用于获取连接时的异步等待
- 根据settings持久化设置
- 初始化池驱动列表、队列
- 按照配置的minSize创建指定数量的连接。
- 创建一个过程缓存,代码如下
这5个步骤中,最可能耗时较久的是步骤d。其他步骤理论上不会有问题。
步骤d中的代码,虽然就一个函数,但是代码很多。
经过不停的查看代码,发现其主要功能是根据连接字符串中的设置,创建一个指定类型的连接。其底层创建代码如下:
可以看到,任何创建Stream失败的情况都会抛出异常,最终导致连接池创建失败。
其中第一句,GetStream的底层代码如下:
开始连接(BeginConnect)后,即开始了等待。等待的超时默认值如下:
2147483s,即596h。如果有连接到数据库服务器的网络有问题或其他原因导致连接不成功,而也未触发其他导致失败的情况,则会一直等下去。如果推断正确,那么所有线程中,一定有线程的调用堆栈在如下位置:
对Dump文件中的所有线程堆栈排序,有且仅有一个线程处于该调用堆栈处。高亮行正是上述堆栈的函数名CreateSocketStream。上面一行就是WaiteOne。之后进入本机代码。
那么根本原因也就清楚了:一个连接的创建卡住了数据库连接创建,间接卡住了连接池的锁,又间接卡住了其他连接池的使用和创建。导致所有数据库连接不可用。所以,所有进入的请求经过运行,全部堆在GetPool这里。
解决方法:
- 保证网络正常(跨机房专线稳定性不可控,有人摇晃光纤玩 o(∩_∩)o 或者其他原因导致流量堵塞)
- 容易卡的数据库连接分离出去到单独的进程。这样由于不共享锁,所以不会卡住其他线程池的使用和创建。
- 需要跨机房的业务,在数据所在机房单独提供api,内网失效时可以走外网。
- 容易卡住的线程池连接字符串中设置minPoolSize=0。这样创建连接池时,不预创建连接而影响其他连接池。但是,对于突发流量增长的情况,响应可能不够及时。
- 设置一个合理的ConnectionTimeout。可以有效避免连接创建时卡住,导致api无响应和其他副作用。
其他在源代码中发现的需要注意的地方
- 连接池中空闲连接的空闲时间是180s。
- 清理周期第一次是188s,之后保持180s。
- 如果连接池中的空闲连接数大于设置的minPoolSize,则清理空闲连接直到minPoolSize。
- ConnectionTimeout用于几个地方
- ) 连接socket时的等待超时
- ) 连接之后,连接上的读写超时。
- ) 从已空且总数达上限的连接池中,等待可用连接时的等待超时
以上所有信息基于.Net版本Mysql.Data 6.9.9版本反编译分析。
一次Mysql连接池卡死导致服务无响应问题分析(.Net Mysql.Data 6.9.9)的更多相关文章
- tomcat服务无响应堆栈分析
tomcat服务突然无响应了,导出内存堆栈和线程堆栈,分析后发现是同步锁使用不合理导致的. [root@prd-dtb-web-01 ~]# [root@prd-dtb-web-01 ~]# jmap ...
- ArcGIS Server浏览地图服务无响应原因分析说明
1.问题描述 从4月17号下午5时起,至18号晚9点,客户单位部分通过ArcGIS Server发布的地图服务(该部分地图服务的数据源为数据库SJZX)无法加载浏览,表现为长时间无响应.同时,通过Ar ...
- mysql连接池模块
如果不想程序在查询数据时卡死或等待过长时间,一般不推荐在node中开启一个连接后全部查询都用这个链接并且不关闭.因为node里面的mysql不像php里的那样会在完成查询后断开,只要不主动断开,连接一 ...
- 连接池设置导致的“血案” 原创: 一页破书 一页破书 5月6日 这个问题被投诉的几个月了,一直没重视——内部客户嘛😿 问题现象: 隔几周就会出现 A服务调用B服务超时 脚趾头想就是防火墙的问题,A、B两服务之间有防火墙 找运维查看防火墙日志确实断掉了tcp连接,但是是因为B服务5分钟没有回包,下面这个表情就是我当时的心情——其实我们在防火墙、A服务、B服务都抓包了,几十个G的t
连接池设置导致的“血案” 原创: 一页破书 一页破书 5月6日 这个问题被投诉的几个月了,一直没重视——内部客户嘛
- Java Mysql连接池配置和案例分析--超时异常和处理
前言: 最近在开发服务的时候, 发现服务只要一段时间不用, 下次首次访问总是失败. 该问题影响虽不大, 但终究影响用户体验. 观察日志后发现, mysql连接因长时间空闲而被关闭, 使用时没有死链检测 ...
- .Net中如何使用MySql连接池
提供一份官方的译文.翻译也挺辛苦的!! 6.4 Using Connector/Net with Connection Pooling 6.4在Connector/Net中使用连接池 The Conn ...
- workerman如何写mysql连接池
首先要了解为什么用连接池,连接池能为你解决什么问题 连接池主要的作用1.减少与数据服务器建立TCP连接三次握手及连接关闭四次挥手的开销,从而降低客户端和mysql服务端的负载,缩短请求响应时间2.减少 ...
- 解决Mysql连接池被关闭 ,hibernate尝试连接不能连接的问题。 (默认mysql连接池可以访问的时间为8小时,如果超过8小时没有连接,mysql会自动关闭连接池。系统发布第二天访问链接关闭问题。
解决Mysql连接池被关闭 ,hibernate尝试连接不能连接的问题. (默认MySQL连接池可以访问的时间为8小时,如果超过8小时没有连接,mysql会自动关闭连接池. 所以系统发布第二天访问会 ...
- nodejs + redis/mysql 连接池问题
nodejs + redis/mysql 连接池问题 需不需要连接池 连接池的作用主要是较少每次临时建立连接所带来的开销.初步一看,nodejs运行单线程上,它不能同时使用多个连接,乍一看是不需要连接 ...
随机推荐
- 使用淘宝的npm代理下载模块
npm install node-sass --registry=http://registry.npm.taobao.org
- Python学习札记(九) Basic6 dict and set
参考:dict and set Note: A.dict Hint:注意最后三点. 1.Python内置字典dict,全称directory,在别的语言如C++中称为map,使用键值-value存储, ...
- CALL_AND_RETRY_LAST Allocation failed node打包报错
全局安装increase-memory-limit: npm install -g increase-memory-limit 进入工程目录,执行: increase-memory-limit
- IIS服务器管理学习
工欲善其事必先利其器 首先给服务器配上强力的软件,用于安全防护和监控. 公司服务器用的阿里云的ECS,已经有防护和监控了,之后又选择额外加了一个安全狗 为了监控服务器上系统的各项运行指标,又买了听云平 ...
- ColKang v1.0
/* *2015.3.31 14:00更新 *上午刚写完这篇博客,下午就读到迭代器了.C++ primer中讲迭代器那节说道了->符号的意思,即(*ptr). 及将指针解引用之后再调用成员函数 ...
- head first python选读(5)
python web 开发 犯了低级错误,这本书看了一半了才知道书名应为<head first python>,不是hand first.. 现在开始一个web应用. 总算是熟悉的内容了. ...
- are only available on JDK 1.5 and higher
根本原因是项目中的一些配置包括jar包什么的根当前jdk版本(我刚开始用的是1.8的,好像是不支持低版本的springjar包),反正正确的思路是更改jdk版本是最合理的,叫我去把所有spring版本 ...
- 格雷码C++实现
格雷码C++实现 题目 给定一个整数n,请返回n位的格雷码,顺序从0开始,要求递归实现. 格雷码: 在一组数的编码中,若任意两个相邻的代码只有一位二进制数不同,则称这种编码为格雷码(Gray Code ...
- SecureCRT 7.0破解
激活步骤如下: 1)准备工作:安装好SecureCRT软件,下载并得到该注册机. 2)保持SecureCRT软件关闭(运行的话会提示你正在运行的,关闭就好). 3)将注册机拷贝到你的CRT软件的安装的 ...
- IE中的if语句--实现不同版本IE浏览器不同html代码 (转)
在很多html代码中常常可以看到很多的IE的条件语句,有时候很不明白他们的意思,其实这是为了能与低版本浏览器实现更好的兼容,例如在制作纯CSS的级联菜单时,由于在IE6中只有<a>支持伪类 ...