先看现象。连接池最小空闲设了五十条,运维为了清闲连接把 wait_timeout 从 28800 改成 60,之后业务空闲几分钟后的第一批请求就报 MySQL server has gone away,重试一次又正常。
排查方向其实有限,先把可能性排一排。服务端先关掉空闲连接,池子里的连接已经失效,客户端并不知道。还有一种是连接池取连接时没做有效性检测,直接拿失效连接发 SQL。
少数情况下是wait_timeout 与连接池的空闲回收时间不匹配,前者明显更短。
不容易想到的是,中间的防火墙或负载均衡也会清空闲会话,表现和数据库超时一模一样。
上来先确认服务端的两个超时值
mysql -e 'show variables like "wait_timeout"; show variables like "interactive_timeout";'
随后把超时调到比连接池空闲时间更长
mysql -e 'set global wait_timeout=600; set global interactive_timeout=600;'
然后看应用侧有没有保活或检测
grep -rn 'ATTR_PERSISTENT\|PING\|validationQuery' /www/api/config | head
剩下的就是核对被服务端断开的计数
mysql -e 'show global status like "Aborted_clients";'
怎么算真的好了,看的是同一批现象。空闲十分钟后再发请求不再报 gone away,Aborted_clients 停止增长,接口错误日志里这条报错彻底消失。
提醒一点。改 wait_timeout 只影响新连接,已有连接要重连才生效;根治办法是连接池开检测,不要靠调大超时拖着。这类问题最好一次改到位,反复小改反而容易把原因搅混。
