linux shell apache wordpress 程序员 php centos 开源 HTML5 java 微软 Firefox Windows mysql Ubuntu Python nginx linux命令 Android google

MySQL5.1中频繁地无法连接mysqld实例问题

现象:

线上某实例从年前到现在,每天晚上0点-2点间至少hang一次。发现及时的话,马上处理掉。发现不及时的话,aurora就切换了。但即使切换了,新的slave(老的master)依然是hang状态,root也无法登陆,tcp里大量 close_wait off连接,也有established 连接。由于无法登进去mysql,所以不知道发生什么事情。然后该主机上凡是要连接该实例的鹰眼报警全部超时。

image

解决办法只有杀掉进程,然后重启实例。

初步分析:

close_wait是被动端收到FIN并发送ACK后切换的状态。此后按正常逻辑,再close并且FIN切换到LAST_ACK状态。CLOSE_WAIT的timer状态为off(0/0/0), 看起来没有什么问题。

现在MySQL用root帐号也无法登录,需要从mysqld抓些数据来分析。

第一次抓的pmp信息:

pmp-1

抓了pmp信息,由于此个mysqld编译时没有加-g,导致ha_innodb.so库中的符号是无法被识别,也就是看到的??。

从已有的信息中看,mysqld无法连接的原因是被卡住了:

正常的连接被阻塞于THD::init,等待LOCK_global_system_variables。

而此全局变量只可能会被执行set global 语句阻塞,此线程拥有LOCK_logger, 导致6个线程等待rdlock,同时此线程等待LOCK_open。与此同时等待LOCK_open的还有复制的SQL线程。

那么,哪个线程拥有LOCK_open呢?由于编译的问题,抓的backtrace不能反映完整信息,但可能的是最后一个DDL线程, ha_create时被阻塞。此线程很可能拥有LOCK_open。

至于执行DDL的线程被阻塞原因,我还要再跟踪下。

总之,从抓的backtrace看,我觉得很可能是mysqld内部某种死锁导致。

后续打算重新编译一个加编译信息的mysqld(其实是innodb.so),像这种负载较低的,如果是MySQL engine的问题,应该不难搞定。

第二次抓的pmp信息:

image

set global操作:

sys_var_log_state::update
—>占用LOCK_global_system_variables
LOGGER::activate_log_handler
activate_log
open_performance_schema_table
open_ltable
open_table ———>请求lock_open

本地DDL线程

mysql_alter_table->mysql_create_table_no_lock
—–>持有LOCK_open
rea_create_table
ha_create_table
ha_innodb::create
intern_sys_var_ptr —->回mysql层获取选项值,请求LOCK_global_system_variables

构成互相等待的死锁条件

这应该是一个Bug!

社区反馈:

@印风向社区反馈,社区确认这是一个已知的bug: bug68461.

但5.5已经确认fix,5.1不打算fix。官方对5.1的态度, 和我预想的一样,不死人就不用管,死人的话也要看死谁。

解决方法:

避免用于监控的频繁地 set global语句,以及调整业务代码中过于频繁的DDL。

延伸阅读

评论