玩转processlist,高效追溯MySQL活跃连接数飙升根因

一、引言

在运维MySQL时,经常遇到的一个问题就是活跃连接数飙升。一旦遇到这样的问题,都根据后台保存的processlist信息,或者连上MySQL环境,分析MySQL的连接情况。处理类似的故障多了,就萌生了一种想法,做个小工具,每次接到这种报警的时候,能够快速地从各个维度去分析和统计当前MySQL中的连接状态。比如当前连接的分布情况、活跃情况等等。

另外,真实故障处理时,光知道连接分布情况往往还不够,我们需要知道当前MySQL的正在忙于做什么,也就是正在执行一些什么样的SQL。而且,有时候即使我们知道了当前执行的SQL情况,也很难找到根因,因为如果活跃连接一旦飙升,这是的CPU基本上是处于被打满的状态,IO的负载也非常高,即使平时很快的SQL也变成了慢SQL,更不用说本身就很慢的SQL了。那我们怎么去甄别这些SQL里,哪些是导致问题的罪魁祸首,哪些仅仅是受害者呢?

带着这些需求和问题,本文逐渐展开并一一做分析和解答,展示我们这个小工具的功能。

二、连接分析

想知道当前MySQL的连接信息,最直观的方法是看MySQL的processlist,如果希望看到完整的SQL,可以执行show full processlist,或者直接查information_schema中的processlist这个表。当MySQL中连接数比较少的时候,还能够人肉分析出来,可是如果连接数比较多,那就很难考肉眼看processlist去分析问题了。

最开始,我们的做法是写个脚本,用MySQL客户端在命令行登录MySQL,并执行show full processlist,然后将输出作为一个文本分析。本来这种实现方式在MySQL5.5和MariaDB上运行得很好,可是,当在MySQL5.6环境上运行时,出现了问题,在控制台输出中会多出一行Warning: Using a password on the commandline interface can be insecure,相信很多运行orzdba的同学也遇到过这种情况。这个是MySQL5.6本身的安全提示,输入明文密码时,没有办法避免,阿里的同学还分享过他们为此做过源码改造,因为他们很多任务都依赖于命令行执行MySQL命令并捕获结果。

还有另外一种方式规避这个问题就是用mysql_config_editor这个工具,但是这个需要做额外的一些配置,同时也有安全上的隐患。我们没有能力改造源码,但是也不想使用mysql_config_editor,所以我们使用了另外的方式,不从命令行登录,而是用information_schema的表processlist作为数据源,在上面做查询,得到processlist的信息。还有另外一张表performance_schema.threads,也包含了同样的结果,甚至更丰富的后台线程信息,而且相比information_schema.processlist,在查询的时候不用申请mutex,对系统系能影响小,不过这要求打开perfomance schema,感兴趣的同学可以自己尝试。

确定了连接信息来源,下面就开始分析信息统计维度。查看processlist这个表,表结构如下(以MySQL5.6为例,MariaDB可能有额外的信息):

ID:线程ID,这个信息对统计来说没有太大作用

USER:连接使用的账号,这个是一个统计维度,用于统计来自每个账号的连接数

HOST:连接客户端的IP/hostname+网络端口号,这也是一个统计维度,用于确定发起连接的客户端

DB:连接使用的default database,DB通常对应具体服务,可以用于判断服务的连接分布,这算一个统计维度

COMMAND:连接的动作,实际上是说连接处于哪个阶段,常见的有Sleep、Query、Connect、Statistics等,这也是一个统计维度,主要用于判断连接是否处于空闲状态

TIME:连接处于当前状态的时间,单位是s,这个在后面进行分析,暂不算在连接状态的统计维度中

STATE:连接的状态,表示当前MySQl连接正在做什么操作,这算一个统计维度,可能的值也比较多,详细可以查阅官方文档

INFO:连接正在执行的SQL,这个在下一节分析,暂不算在连接状态的统计维度中

通过上面的分析,总结出了5个连接的统计维度:user、host、db、command和state。有了这5个统计维度,我们就可以开始着手写小工具了。

最基本的功能需求就是,查询information_schema.processlist这个表,然后按刚才总结的5个统计维度,对MySQL中的连接进行分组统计,按照统计个数排序。processlist这个表的host字段需要做一些细节上的处理,因为它的值实际上是IP/hostname+网络端口号的组合,我们需要把端口号裁剪掉,这样才能按照客户端进行统计,否则每个客户端连接的端口号都是不一样的,没法进行分组统计。

最后的输出如下:

有了最基本的功能,能满足最基本的统计需求。可是在实际排查和处理线上问题时,可能并不关心所有的统计维度,只需要按照上述5个维度中的部分进行统计;另外,可能希望host出现在user的前面,优先按照客户端的IP或者是hostname进行统计。所以,这就要求这个工具具有增加灵活地添加或者删除统计维度的功能,而且能够对统计维度的出现顺序进行动态调整。

最后的示例输出如下:

最开始说了,我们造这个工具的初衷是分析活跃连接,可是统计出来的结果中,包含了空闲连接,那么需要将空闲连接从统计结果中排除出去。当然,除了空闲连接,可能还有一些MySQL本身的一些连接,例如slave线程,binlog dump线程等,也希望从结果排除出去。这就要求有个按照任意统计维度进行排除的功能。既然有了排除功能,那同样也可以增加包含功能,即按照任意统计维度进行过滤,包含固定条件的连接才能出现在统计结果之中。

有了这个连接统计信息,我们就清楚当前MySQL内部的连接状态,大致判断出是哪个业务或者模块有问题。

三、SQL分析

分析到业务或者模块的粒度还不够,到底是哪个接口或者是哪个功能有问题呢?根据上面的连接状态信息,还没有办法准确地回答这个问题。我们继续深入,分析processlist中的SQL,回去看到上节中被我们暂时忽略的information_schema.processlist这个表的INFO字段,里面就保存了每个活跃连接上正在执行的SQL信息。通过分析和统计SQL,我们才真正清晰地掌握MySQL当前的内部活动,活跃连接都在干些什么事。通过这种方式,我们可以协助RD同学快速地定位问题,找到有问题的接口或者是功能模块。

其实,要统计SQL并不容易,因为SQL千变万化,每一条SQL都不是一样的,即使是统一功能模块的SQL,参数也可能不一样。那这种情况下,如何统计SQL呢?这里借鉴了pt-toolkit中的设计思想。在pt-query-digest的分析结果中,有一个fingerprint的字段,它其实是一个hash值,这个hash值代表了一类SQL,这类SQL除了参数不一样之外,其它的SQL结构都是完全一致的。所以我们把这种思路引入到具体实现中,通过正则,将SQL中的具体条件都去掉,然后将正则之后的SQL结构相同的SQL都算作同一条SQL,然后就可以进行分组统计了。举个例子,比如现在应用里有2条SQL,分别如下:

SELECT * FROM `xxxxxxxxxxxxxxxxxxxx` `t` WHERE `t`.`ucid`='1000000020018048' LIMIT 1

SELECT * FROM `xxxxxxxxxxxxxxxxxxxx` `t` WHERE `t`.`ucid`='1000000020281039' LIMIT 1

这2条SQL除了最后where条件中ucid字段的值不一样之外,其他的SQL结构是完全一致的。通过正则匹配之后,将ucid的值和limit的行数去掉,在最终的统计结果中,这2条SQL都变成了下面的SQL:

SELECT * FROM `xxxxxxxxxxxxxxxxxxxx` `t` WHERE `t`.`ucid`=? LIMIT ?

这样,就实现了SQL的分组统计。

示例输出如下:

当然,还可以根据需要,添加一些附加信息,便于定位和分析问题,例如user、Host等。

四、事务分析

有了SQL分析和统计,在某些场景下,基本能定位到问题所在,比如高频的执行计划良好的SQL。可是如果是由于慢SQL导致整个系统响应变慢的场景,上面单纯的SQL统计是否还能够有效地快速定位出问题呢?肯定不能,因为此时,单纯地从统计结果,无法分辨出哪些是导致系统响应变慢的慢SQL,哪些是被影响的SQL。当然,统计结果中,次数多的SQL可能会是慢SQL,但是也可能本身就是一些高频的接口调用,因为系统响应变慢,导致请求堆积。所以,最好的办法就是能够加入一些其它的辅助信息,帮助判断哪些请求可能是慢查询。那加入哪些辅助信息呢?有两种选择。

首先,我们回去看第一节被我们忽略的information_schema.processlist这个表的Time字段,可以用于大概判断连接的上SQL的执行,和实际时长的差异取决于SQL执行时每个阶段所消耗的时间。其次,因为线上表都是InnoDB表,所以可以和InnoDB的事务统计信息进行关联。InnoDB的事务分为只读事务和读写事务,信息都保存在information_schema.INNODB_TRX这张表里。对于某些大事务的场景下,一个事务包含多个操作,这种方式得出的结果会有偏差。如果是非InnoDB的引擎,这种方式不适用。

此处分析时,以只读事务,也就是select语句为例。在实现上,我们将问题简化,通过processlist中time字段的值或者事务的执行时间,去预估一条SQL的执行时间,进而判断在processlist中,积压的大量连接中,哪些请求本身就是慢查询,哪些是受影响变慢的查询。利用事务判断时,将processlist中ID字段和information_schema.INNODB_TRX中trx_MySQl_thread_id字段做关联,具体的SQL为select p.*, now() - t.trx_started as runtime frominformation_schema.processlist p, information_schema.INNODB_TRX t where p.id =t.trx_MySQl_thread_id。最后,统计正则之后每一类SQL总的执行时间,以及平均执行时间。执行时间越长的,我们更倾向于认为是导致问题的罪魁祸首。

示例输出如下:

RT:这一类SQL截止当前,总的执行时间,单位是S(秒)

AVGRT:这一类SQL截止当前,每个事务平均执行时间,单位是S(秒)

加入user、Host等附加信息之后,输出如下:

五、结语

通过上面的3个维度,把MySQL的processlist中的可用信息基本上都挖掘得差不多了。我们在实际问题排查和处理时,也经常使用这个工具,经过实践检验,问题定位效率还是比较高效的。

但是,也还存在很多改进的地方。比如SQL语句分析中,limit值不同的,严格来说其实应该算不同的SQL,因为执行时间可能相差非常大。另外,SQL执行时间分析中,对于单条select语句的只读事务分析结果非常准确,但是对于读写事务,怎么减少结果的误差,因为读写事务相比只读事务会更复杂,因为可能涉及锁等待等一些额外的情况。所有的这些已经在我们的改进计划中,如果大家有好的思路或者是想法,欢迎交流。

我们自己做这些事情,其实日常运维经验的积累和沉淀,如果刚好某位同学的思路和实现有雷同,实属必然。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • 1.A simple master-to-slave replication is currently being...
    Kevin关大大阅读 5,945评论 0 3
  • 什么是数据库? 数据库是存储数据的集合的单独的应用程序。每个数据库具有一个或多个不同的API,用于创建,访问,管理...
    chen_000阅读 4,028评论 0 19
  • 作为一个DBA, 常常实际工作中遇到各种稀奇八怪的问题。这里重点说一说长事务和锁等待。 长事务 简单来说就是长时...
    wGrow阅读 6,024评论 1 2
  • MySQL不权威总结 欢迎阅读 本文并非事无巨细的mysql学习资料,而是选择其中重要、困难、易错的部分进行系统地...
    liufxlucky365阅读 2,572评论 0 26
  • MySQL运维实践 5.1-MySQL日志系统 什么是日志 日志(log)是一种顺序记录事件流水的文件 记录计算机...
    极客圈阅读 1,401评论 1 11