一次mysql执行超时问题的排查
起因
我们项目现网使用的数据库一直是自己运维的,现网就一个主备,如果主挂了需要手动去切换到从库,现网对外服务会有不可预知的不可用时间。公司内部有很多数据库自动化运维的工具,我们选择了接入GCS,实现数据库自动主从切换,加强现网数据库的监控,GCS的原理很简单,使用mysql-proxy做主从切换管理,对外提供域名的访问方式,理论上我们直接接入将现网直接切换成GCS就可以了,但是这么大的动作总是要做全量测试并长期观察一段时间才敢上的嘛,我们计划在IDC环境搭建好GCS服务后让我们的测试环境的数据库指向该环境,测试环境长期使用一段时间,确认稳定可靠后再切换到现网环境中去,然而问题出现了。
问题
我们将测试环境指向搭建好的IDC环境GCS,运行一段时间后,出现大量sql执行超时告警(这个是我们自己加的业务告警),测试抛出大量莫名其妙的bug,问题看上去很明显,公司dev环境(测试环境)和idc环境网络上做了隔离,初步判断是网络丢包的问题
问题分析
因为sql执行超时是偶现性的,抓包比较难抓,首先写了个循环发请求的脚本,不停的发触发sql超时告警的请求,然而发了大半天也没有再出现sql超时,经过重复重复再重复的折腾,复现触发sql超时的规律,如果长时间没有访问,再访问业务进程,sql超时必现,这里先介绍一下,我们的业务进程mysql访问层采用连接池长连接的方式,初步猜测这个问题和连接保活有关,先不管什么问题,有了必现的方法就方便抓包了, 通过tcpdump在业务进程机器和mysql-proxy机器两边抓包,结果如下:
业务进程抓包数据
mysql-proxy抓包数据
上图可以看出出现了大量的超时重传,确实是丢包,把这个问题抛给网平的人,网平给出说法说公司dev环境到idc环境转发通过一个防火墙,该防火墙设置的会话保持超时时间是30分钟,根据前面的总结,和我们触发sql超时的规律基本吻合,基本上判断就是墙上会话保持的问题了。
问题解决
改造我们测试环境的mysql连接池,之前的逻辑是每次先从空闲连接中取出一个连接使用,改成每次都新建连接使用,用完释放连接,使用改造后的程序测试,sql执行超时的问题解决。这里的解决方法比较简单粗暴,其实可以定时发个保活sql请求来保持墙上的会话不会过期,不过考虑到测试环境反正也不会有性能压力,先这样处理了。
总结
没有什么网络问题是抓包解决不了的-_-