代码改变世界

“MySQL Server Has Gone Away”错误诊断

2020-10-15 09:11  abce  阅读(603)  评论(0编辑  收藏  举报

我们都喜欢错误消息具有描述性,并且可以清楚地了解正在发生的事情。但是,在某些情况下,由于多种可能的原因而导致出现一条错误消息。其中之一就是“ MySQL server has gone away”。发生错误的大多数情况在MySQL文档中都有所描述,但可能会有些棘手。本文我想谈谈这个“棘手”的问题。

主要有几种场景会发生这种错误:

1.MySQL线程被管理员或者类似pt-kill工具kill了

手动干预一般都是间歇性的,并且由于它在某些情况下是一次性的(例如,长时间运行的糟糕查询),DBA都会知道的。pt-kill可能不太明显,因为它通常可以作为一种变通办法来运行,以防止那些不好的长时间查询增加系统资源的负担。

检查系统进程列表可以看到pt-kill命令:

$ ps xauf | grep pt-kill
taras 6069 0.1 0.1 111416 29452 pts/29 S+ 10:57 0:00 | | \_ perl /usr/bin/pt-kill --interval 1s --busy-time 5s --match-info (SELECT) h=127.0.0.1 --print --kill
taras 6913 0.0 0.0 21532 1112 pts/30 S+ 11:00 0:00 | \_ grep --color=auto pt-kill

一种非常方便的方法是使用Percona为MySQL提供的审计插件来确定pt-kill命令的来源:

<AUDIT_RECORD>
  <NAME>Query</NAME>
  <RECORD>624484743_2020-06-30T17:38:14</RECORD>
  <TIMESTAMP>2020-06-30T17:57:35 UTC</TIMESTAMP>
  <COMMAND_CLASS>kill</COMMAND_CLASS>
  <CONNECTION_ID>17</CONNECTION_ID>
  <STATUS>0</STATUS>
  <SQLTEXT>KILL QUERY 16</SQLTEXT>
  <USER>taras[taras] @ localhost []</USER>
  <HOST>localhost</HOST>
  <OS_USER></OS_USER>
  <IP></IP>
  <DB></DB>
</AUDIT_RECORD>

会显示主机名、用户名、已经执行kill的时间。

2.大数据块(chunk)传输

例如,当使用BLOB字段将二进制数据存储在表中时,或者存在包含很多行的INSERT语句。使用MySQL CLI客户端时可能会发生这种情况(加载SQL转储的情况之一),或者尝试存储BLOB数据时(例如,文件上传),它可能会在应用程序内发生。

MySQL对每个查询可以传输的数据量施加了限制,并且max_allowed_packet变量定义了它。

因此,在两种情况下,我们都需要确定将数据写入哪个表,例如,查询INSERT INTO语句的SQL文件并在应用程序端实现日志记录。这样,该语句将与阻止其完成的错误一起存储。可以捕获部分语句(因为BLOB可能会成为日志的负担),但是只要有表名,就可以检查表结构并查看其是否包含二进制数据。

带有二进制数据(被截断)的INSERT语句的示例:

INSERT INTO t1 VALUES (1, x'89504....82’)

为了允许更大的查询执行,变量需要调整:

SET GLOBAL max_allowed_packet = 128M ;

该变量可以在会话级别或者全局级别设置。

3.连接因为超时被关闭

应用程序可以重用已经建立的连接。在不活跃或通信量较低的时间内,某些连接可能会暂时不使用,并在MySQL端被关闭。最好通过应用程序日志进行跟踪。

如果在晚上发生了一个事件,随后一段时间会话不活跃,然后在早晨发生了错误,则很有可能MySQL关闭了连接。

mysql> SET SESSION wait_timeout = 5 ;
Query OK, 0 rows affected (0.00 sec)

超时等待设置为五分钟。

mysql> select 1 ;
ERROR 2006 (HY000): MySQL server has gone away
No connection. Trying to reconnect...
Connection id: 16
Current database: *** NONE ***

+---+
| 1 |
+---+
| 1 |
+---+
1 row in set (0.01 sec)

通常,连接重新建立,应用程序继续正常操作;但总是可能会扩展MySQL超时配置:

SET GLOBAL wait_timeout = 57600 ;

变量的默认值为28800秒(8小时),在大多数情况下足够了。

此外,经过一段时间的不活动后,从应用程序端彻底关闭连接可以消除此问题。

4.MySQL Server已经停掉了

当MySQL在查询中崩溃或由于其他原因(例如,OOM杀死该进程)时,这可能是最糟糕的情况。但是,它也可能是由干净的重新启动引起的。

在这种情况下,应该检查MySQL的启动时间以及日志,MySQL错误日志和syslog。这些地方应该能找出服务器是否发生了重启以及是否存在导致重启的错误。

万一服务器确实崩溃了,需要找到实际原因了。检查bug跟踪清单,因为该问题可能已经报告过并且可能已经解决; 如果需要,升级MySQL。 如果是干净的重启,请检查是否启用了自动更新,或者其他人是否以交互方式重启了服务(是的,缺少沟通也件事情)。