MySQL的max_user_connections拒绝连接的一次踩雷经验

  近期线上的数据遇到一个问题,最终原因为max_user_connections和max_connections的一个bug导致,具体过程如下

 

现象

  前端页面不断的出现错误页面。

 

排查处理过程

  按照数据库的标准排查流程,首先看延迟,慢查询,连接数,这三个最容易出现问题的地方。

  第一时间发现有较大的延迟超过800s,经过分析慢查询日志发现是一条DELETE SQL没有使用索引导致全表查询引发的对服务器IO性能消耗过多导致的。

  同事前端的兄弟们也发现这个业务的调用量徒增几百倍,从一个没什么访问量的业务变为每秒上万访问量的业务。

  故,我们初步推断,这是由于访问量激增引发的平时不明显的问题暴露出来导致的故障。

  但是,第二天我们将索引添加之后,效果很好,慢查询日志已经看不到问题SQL了,但是故障现象还在发生,只不过频次降低。

  基于以上的信息,我们认为不是数据库的问题,而是突增的流量已经超过系统承载范围,需要进行限流。于是就对接口API做了修改。但是经过一天的观察之后,问题的现象仍在稳步增加,并没有消失。这时候,通过添加细粒度的应用日志才得以发现,有很多的more than max_user_connections的报错。而我们的配置是max_user_connections=1024,max_connections=4096。从监控看,从来没有超限的现象发生。为了处理故障,先临时将max_user_connections提高到2048,问题得以解决,经过观察也不再复现,看来问题就出现在连接数上。但是为什么从监控上看连接数并没有超过max值呢?

 

问题定位

  经过后续的排查,发现这是由于MySQL5.5.12的一个bug导致,具体详见:http://bugs.mysql.com/bug.php?id=65104

  基本的意思是,当max_user_connections设置一个非0的数值时,在一些情况下,这个数值并不会被MySQL Server认可,就算连接数还有空闲,也会拒绝掉部分连接请求。

  这样,上述的情况就可以得到解释了。那么如何进行处理呢? 官方的解释是需要升级MySQL版本,在5.5.25以下的版本都会发生,最好就直接升级到MySQL5.5的最终版本5.5.31最好。(又要各种切换主库了,头疼,这是题外话)

  同时,后期看历史数据,其实已经有很明显的现象表明当时数据库连接有异常,只是被我们忽略了,这是需要检讨的地方。

  从下图可以看出,我们出现问题的时间段上,有比较明显的abort_connectioning的曲线,当我们解决完毕之后又消失了,这就说明在大量abort出现的时候,一定是存在连接数的问题,有可能是MySQL自身,也有可能是程序段没有close()导致的连接数浪费。这都需要具体分析。

 

经验总结

  首先,从技术层面,对abort_connections的理解程度和重视程度都需要提高。

  其次,从流程和问题定位方案,监控和日志的重要性就不必细说了,只是在多强调2点。第一,监控的点要覆盖全面,如果监控只有连接数二没有abort的数值,那么下次出现诡异的bug问题,仍然还会茫然无头绪。第二,错误日志才是问题定位的根本,除了MySQL,apache,php的错误日志外,应用程序的错误日志同样重要,需要提高重视程度。只有日志反应的问题才是真实存在的问题,而不能光靠经验就推测,运维确实是个吃经验的活,但是也不能犯经验主义的错误。

  最后,从这个故障上来说,关于透明代理、反垃圾等等限流和安全措施方面其实还是有很多地方可以做的,但是不涉及数据库,不再详细分析了。

posted @ 2013-11-05 12:53  billy鹏  阅读(3127)  评论(0编辑  收藏  举报