(2006,Mysql Server has gone away)问题处理

最近遇到了一个奇怪的问题,更换mysql db的连接地址之后,偶尔出现简单的sql查询语句报(2006,Mysql Server has gone away)错误。大概的排查过程记录如下。


原因分析

根据Mysql官网的描述,可能的原因如下:

1.Mysql服务宕机

可通过show status like ‘uptime’;来查询服务器运行时间:
(2006,Mysql Server has gone away)问题处理_第1张图片

排除服务器宕机问题。

2.Mysql连接超时

通过show global variables like '%timeout';查看超时参数:
(2006,Mysql Server has gone away)问题处理_第2张图片
可以看到,interactive_timeout和wait_timeout参数均为8h,可以排除超时问题。

3.mysql请求连接进程被主动kill

这种情况一般由dba触发,主动kill慢查。通过show global status like 'com_kill';查看:
(2006,Mysql Server has gone away)问题处理_第3张图片
排除连接进程被kill问题。

4.Your SQL statement was too large

查询的结果集超过max_allowed_packet限制时也会报错。通过show global variables like 'max_allowed_packet';查看:
(2006,Mysql Server has gone away)问题处理_第4张图片
该参数为64m,排除结果集过大问题。

其他原因

排除以上原因后,还有可能的原因有:连接数过多内存不足等。

内存不足

根据stackOverflow上面看到的说法,有可能是内存不足导致的:
在这里插入图片描述
但这个内存指的是程序服务器内存还是db服务器内存呢? 通过free -h查看应用服务器内存:
在这里插入图片描述
可供应用程序使用的内存为105G,完全是足够的。db服务器无法直接登录,也看不到内存使用,但是如果db服务器内存出现性能问题,dba肯定会有反应,因此基本也可以排除。

连接数太多

查看当前打开的连接数量和最大使用的连接数量如下:
(2006,Mysql Server has gone away)问题处理_第5张图片
可以看到,当前连接数为1178。最大的连接数为1631,出现的时间也不是最近的时间,可以排除连接数过多的问题。

继续查看其他参数:
(2006,Mysql Server has gone away)问题处理_第6张图片

  • threads_connected:创建用来处理连接的线程数
  • threads_running: 激活的处理连接的线程数

其他参数也基本正常。而业务应用场景中,会话session也是用完之后就关闭的,不存在超过8h的连接。至此,找不到问题原因。幸而这种情况只是偶尔出现,不影响服务的可用性。后面找到原因后,再来更新解决方案。


最终原因

后来再次追查原因,发现数据库连接池参数很有问题。用的是python的sqlAlchemy,如下所示:

mysql_engine = create_engine(settings.get('mysql', 'host'),
                             pool_size=settings.getint('mysql', 'pool_size'),
                             max_overflow=10,
                             echo=settings.getboolean('mysql', 'echo'),
                             encoding=settings.get('mysql', 'charset'),
                             pool_recycle=20000
                             )

Session = sessionmaker(bind=mysql_engine)

这里连接池大小为2,最大连接数为10,连接保活时间为20000s,约5.5h。而新的db有连接断开机制,因此会出现连接存在超过8小时,被db主动断开的情况。

将pool_size修改为2,max_overflow改为100,pool_recycle为60,修改后不再报错,问题解决!


附录

mysql数据库常用参数:
show status like '%下面变量%'

  • Aborted_clients 由于客户没有正确关闭连接已经死掉,已经放弃的连接数量。
  • Aborted_connects 尝试已经失败的MySQL服务器的连接的次数。
  • Connections 试图连接MySQL服务器的次数(累计数据,非当前)
  • Created_tmp_tables 当执行语句时,已经被创造了的隐含临时表的数量。
  • Delayed_insert_threads 正在使用的延迟插入处理器线程的数量。
  • Delayed_writes 用INSERT DELAYED写入的行数。
  • Delayed_errors 用INSERT DELAYED写入的发生某些错误(可能重复键值)的行数。
  • Flush_commands 执行FLUSH命令的次数。
  • Handler_delete 请求从一张表中删除行的次数。
  • Handler_read_first 请求读入表中第一行的次数。
  • Handler_read_key 请求数字基于键读行。
  • Handler_read_next 请求读入基于一个键的一行的次数。
  • Handler_read_rnd 请求读入基于一个固定位置的一行的次数。
  • Handler_update 请求更新表中一行的次数。
  • Handler_write 请求向表中插入一行的次数。
  • Key_blocks_used 用于关键字缓存的块的数量。
  • Key_read_requests 请求从缓存读入一个键值的次数。
  • Key_reads 从磁盘物理读入一个键值的次数。
  • Key_write_requests 请求将一个关键字块写入缓存次数。
  • Key_writes 将一个键值块物理写入磁盘的次数。
  • Max_used_connections 同时使用的连接的最大数目。
  • Not_flushed_key_blocks 在键缓存中已经改变但是还没被清空到磁盘上的键块。
  • Not_flushed_delayed_rows 在INSERT DELAY队列中等待写入的行的数量。
  • Open_tables 打开表的数量。
  • Open_files 打开文件的数量。
  • Open_streams 打开流的数量(主要用于日志记载)
  • Opened_tables 已经打开的表的数量。
  • Questions 发往服务器的查询的数量。
  • Slow_queries 要花超过long_query_time时间的查询数量。
  • Threads_connected 当前打开的连接的数量。
  • Threads_running 不在睡眠的线程数量。
  • Uptime 服务器工作了多少秒

参考资料

[1]. https://stackoverflow.com/questions/7942154/mysql-error-2006-mysql-server-has-gone-away

你可能感兴趣的:(工具,数据库与sql)