问题:

进程启动后,线程数迅速上升至最小线程数后,缓慢上升(线程池限制)到数千,然后由于线程过多,CPU飙升到90%。

对外表现为Api无响应或连接超时。

背景

有些数据存在于另一个机房,通过内网专线连接。一个服务程序有4个数据库,其中3个在本地机房,1个在外地。

各种排查,没有解决。

最终的处理方法

Dump进程

  1. 使用进程管理器,创建进程Dump文件。
  2. 使用VisualStudio打开该Dump文件并进行托管调试
  3. 查看并行堆栈,发现大部分线程均处于MySql.Data.MySqlClient.MySqlPoolManager.GetPool这个函数的调用中。并在此处进入了本机代码。处于其他调用堆栈的线程屈指可数。

代码分析

  1. 由于Mysql.Data.dll没有对应的pdb文件(Oracle没有提供),所以在Visual Studio中不能进入其中的代码,因此直接反编译,找到该函数,代码如下:

函数中,第一句的GetKey函数如下,其中有一个lock。其中代码仅仅是赋值,或是在集成认证的情况下才执行。所以卡住的可能性不大。

第二句是个赋值,且MysqlPoolManager.pools是个字段(field),理论上不会卡住。

第二个lock中,如果指定key对应的缓存已存在,则lock会很快返回。如果不存在,则执行new MysqlPool(setttings);函数代码如下:

其主要功能有

  1. 创建一个事件,用于获取连接时的异步等待
  2. 根据settings持久化设置
  3. 初始化池驱动列表、队列
  4. 按照配置的minSize创建指定数量的连接。
  5. 创建一个过程缓存,代码如下

这5个步骤中,最可能耗时较久的是步骤d。其他步骤理论上不会有问题。

步骤d中的代码,虽然就一个函数,但是代码很多。

经过不停的查看代码,发现其主要功能是根据连接字符串中的设置,创建一个指定类型的连接。其底层创建代码如下:

可以看到,任何创建Stream失败的情况都会抛出异常,最终导致连接池创建失败。

其中第一句,GetStream的底层代码如下:

开始连接(BeginConnect)后,即开始了等待。等待的超时默认值如下:

2147483s,即596h。如果有连接到数据库服务器的网络有问题或其他原因导致连接不成功,而也未触发其他导致失败的情况,则会一直等下去。如果推断正确,那么所有线程中,一定有线程的调用堆栈在如下位置:

对Dump文件中的所有线程堆栈排序,有且仅有一个线程处于该调用堆栈处。高亮行正是上述堆栈的函数名CreateSocketStream上面一行就是WaiteOne。之后进入本机代码。

那么根本原因也就清楚了:一个连接的创建卡住了数据库连接创建,间接卡住了连接池的锁,又间接卡住了其他连接池的使用和创建。导致所有数据库连接不可用。所以,所有进入的请求经过运行,全部堆在GetPool这里。

解决方法:

  1. 保证网络正常(跨机房专线稳定性不可控,有人摇晃光纤玩 o(∩_∩)o 或者其他原因导致流量堵塞)
  2. 容易卡的数据库连接分离出去到单独的进程。这样由于不共享锁,所以不会卡住其他线程池的使用和创建。
  3. 需要跨机房的业务,在数据所在机房单独提供api,内网失效时可以走外网。
  4. 容易卡住的线程池连接字符串中设置minPoolSize=0。这样创建连接池时,不预创建连接而影响其他连接池。但是,对于突发流量增长的情况,响应可能不够及时。
  5. 设置一个合理的ConnectionTimeout。可以有效避免连接创建时卡住,导致api无响应和其他副作用。

其他在源代码中发现的需要注意的地方

  1. 连接池中空闲连接的空闲时间是180s。
  2. 清理周期第一次是188s,之后保持180s。
  3. 如果连接池中的空闲连接数大于设置的minPoolSize,则清理空闲连接直到minPoolSize。
  4. ConnectionTimeout用于几个地方
    1. ) 连接socket时的等待超时
    2. ) 连接之后,连接上的读写超时。
    3. ) 从已空且总数达上限的连接池中,等待可用连接时的等待超时

以上所有信息基于.Net版本Mysql.Data 6.9.9版本反编译分析。

一次Mysql连接池卡死导致服务无响应问题分析(.Net Mysql.Data 6.9.9)的更多相关文章

  1. tomcat服务无响应堆栈分析

    tomcat服务突然无响应了,导出内存堆栈和线程堆栈,分析后发现是同步锁使用不合理导致的. [root@prd-dtb-web-01 ~]# [root@prd-dtb-web-01 ~]# jmap ...

  2. ArcGIS Server浏览地图服务无响应原因分析说明

    1.问题描述 从4月17号下午5时起,至18号晚9点,客户单位部分通过ArcGIS Server发布的地图服务(该部分地图服务的数据源为数据库SJZX)无法加载浏览,表现为长时间无响应.同时,通过Ar ...

  3. mysql连接池模块

    如果不想程序在查询数据时卡死或等待过长时间,一般不推荐在node中开启一个连接后全部查询都用这个链接并且不关闭.因为node里面的mysql不像php里的那样会在完成查询后断开,只要不主动断开,连接一 ...

  4. 连接池设置导致的“血案” 原创: 一页破书 一页破书 5月6日 这个问题被投诉的几个月了,一直没重视——内部客户嘛😿 问题现象: 隔几周就会出现 A服务调用B服务超时 脚趾头想就是防火墙的问题,A、B两服务之间有防火墙 找运维查看防火墙日志确实断掉了tcp连接,但是是因为B服务5分钟没有回包,下面这个表情就是我当时的心情——其实我们在防火墙、A服务、B服务都抓包了,几十个G的t

    连接池设置导致的“血案” 原创: 一页破书 一页破书 5月6日 这个问题被投诉的几个月了,一直没重视——内部客户嘛

  5. Java Mysql连接池配置和案例分析--超时异常和处理

    前言: 最近在开发服务的时候, 发现服务只要一段时间不用, 下次首次访问总是失败. 该问题影响虽不大, 但终究影响用户体验. 观察日志后发现, mysql连接因长时间空闲而被关闭, 使用时没有死链检测 ...

  6. .Net中如何使用MySql连接池

    提供一份官方的译文.翻译也挺辛苦的!! 6.4 Using Connector/Net with Connection Pooling 6.4在Connector/Net中使用连接池 The Conn ...

  7. workerman如何写mysql连接池

    首先要了解为什么用连接池,连接池能为你解决什么问题 连接池主要的作用1.减少与数据服务器建立TCP连接三次握手及连接关闭四次挥手的开销,从而降低客户端和mysql服务端的负载,缩短请求响应时间2.减少 ...

  8. 解决Mysql连接池被关闭 ,hibernate尝试连接不能连接的问题。 (默认mysql连接池可以访问的时间为8小时,如果超过8小时没有连接,mysql会自动关闭连接池。系统发布第二天访问链接关闭问题。

    解决Mysql连接池被关闭  ,hibernate尝试连接不能连接的问题. (默认MySQL连接池可以访问的时间为8小时,如果超过8小时没有连接,mysql会自动关闭连接池. 所以系统发布第二天访问会 ...

  9. nodejs + redis/mysql 连接池问题

    nodejs + redis/mysql 连接池问题 需不需要连接池 连接池的作用主要是较少每次临时建立连接所带来的开销.初步一看,nodejs运行单线程上,它不能同时使用多个连接,乍一看是不需要连接 ...

随机推荐

  1. [Pytorch]Pytorch 保存模型与加载模型(转)

    转自:知乎 目录: 保存模型与加载模型 冻结一部分参数,训练另一部分参数 采用不同的学习率进行训练 1.保存模型与加载 简单的保存与加载方法: # 保存整个网络 torch.save(net, PAT ...

  2. Python学习札记(五) Basic2 字符串和编码

    参考:字符串和编码 Note A.字符编码 1.计算机处理文本 == 将文本转换为二进制 => 处理 2.8 bit(比特) = 1 byte(字节) 一个字节所能表示的最大的十进制整数是255 ...

  3. HttpGet/HttpPost请求方法

    /// <summary> /// HttpGet请求 /// </summary> /// <param name="url">HttpGet ...

  4. LeetCode第[91]题(Java):Decode Ways(解码方法数)

    题目:解码方法数 难度:Medium 题目内容: A message containing letters from A-Z is being encoded to numbers using the ...

  5. 【Python】简单实现爬取小说《天龙八部》,并在页面本地访问

    背景 很多人说学习爬虫是提升自己的一个非常好的方法,所以有了第一次使用爬虫,水平有限,依葫芦画瓢,主要作为学习的记录. 思路 使用python的requests模块获取页面信息 通过re模块(正则表达 ...

  6. Java接受键盘输入

    import java.util.Scanner;//方法1 import java.io.BufferedReader;//方法2 import java.io.IOException;//方法3 ...

  7. A4纸网页打印 html网页页面的宽度设置成多少

    A4纸竖向打印,html网页页面的宽度设置成多少?这个问题是我们大家所疑惑的,于是网上搜集整理下,希望可以帮助你们 最近开发项目时遇到了网页打印的问题,这是问题之二,打印宽度设置 在公制长度单位与屏幕 ...

  8. hdu3544找规律

    如果x>1&&y>1,可以简化到其中一个为1的情况,这是等价的,当其中一个为1(假设为x),另一个一定能执行y-1次, 这是一个贪心问题,把所有的执行次数加起来比较就能得到 ...

  9. IOS-CocoaPods进阶篇

    一.Podfile.lock文件 上文讲过,在开始使用CocoaPods,执行完pod install之后,会生成一个Podfile.lock文件.这个文件看起来跟我们关系不大,实际上绝对不应该忽略它 ...

  10. Vue.directive使用注意

    首先,Vue.directive要在实例初始化之前,不然会报错,还有,定义的指令不支持驼峰式写法,也会报下面同样的错,虽然在源码中没有找到在哪里统一处理大小写,但是在有关directive的方法中捕捉 ...