最近遇到了一个奇怪的问题,更换mysql db的连接地址之后,偶尔出现简单的sql查询语句报(2006,Mysql Server has gone away)错误。大概的排查过程记录如下。
根据Mysql官网的描述,可能的原因如下:
可通过show status like ‘uptime’;
来查询服务器运行时间:
排除服务器宕机问题。
通过show global variables like '%timeout';
查看超时参数:
可以看到,interactive_timeout和wait_timeout参数均为8h,可以排除超时问题。
这种情况一般由dba触发,主动kill慢查。通过show global status like 'com_kill';
查看:
排除连接进程被kill问题。
查询的结果集超过max_allowed_packet限制时也会报错。通过show global variables like 'max_allowed_packet';
查看:
该参数为64m,排除结果集过大问题。
排除以上原因后,还有可能的原因有:连接数过多,内存不足等。
根据stackOverflow上面看到的说法,有可能是内存不足导致的:
但这个内存指的是程序服务器内存还是db服务器内存呢? 通过free -h
查看应用服务器内存:
可供应用程序使用的内存为105G,完全是足够的。db服务器无法直接登录,也看不到内存使用,但是如果db服务器内存出现性能问题,dba肯定会有反应,因此基本也可以排除。
查看当前打开的连接数量和最大使用的连接数量如下:
可以看到,当前连接数为1178。最大的连接数为1631,出现的时间也不是最近的时间,可以排除连接数过多的问题。
其他参数也基本正常。而业务应用场景中,会话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 '%下面变量%'
[1]. https://stackoverflow.com/questions/7942154/mysql-error-2006-mysql-server-has-gone-away