MySQL的一个麻烦事
1. 开启一个MySQL连接,在这个连接中发起一个事务,进行一些操作但不提交
2. 拔网线
3. 重连网线,再开启一个MySQL连接,执行delete操作,发现stpe 1中占用的资源没有被释放
4. 执行show processlist,发现step1中创建的连接依然存在而且处于sleep状态,并将一直存在,直到wait_timeout超时为止
原理
MySQL协议本身不含有心跳功能,一旦建立连接,这条连接线程就一直在server端存在,直到收到client发来的断开连接请求/连接sleep时间超过wait_timeout/手动杀死这条连接 为止
测试中,step 2直接拔了网线,那么这个线程就一直存在了,并且一直为sleep状态,从而一直占用资源
但是如果重连网线后,再次操作step 1中的那个连接,是可以成功commit/rollback未完成的事务的(估计cli保存了会话id,直接连到老的连接去了)
影响
如果网络环境差,会导致MySQL sever端存在大量无用的sleep线程,一个是占用有限的MySQL连接数,另一个是可能会锁住表记录,导致其他连接超时,这可能会引发雪崩的效果
解决
1. 设置wait_timeout为一个比较小的值(interactive_timeout是交互式连接,如cli使用的,一般无需调整),然后应用定时发送心跳来维护连接(一般的连接池都有相关的功能)
2. 应用将每次申请的连接对应的server线程id记录下来,然后定时的杀死自己曾经申请过的连接(kill -tid)以释放资源(很不合适,如果线程id重复了就有错杀的可能)