版本:MySQL 5.7.25

现象:

        通过过 telnet ip port测试连接成功有时成功,有时直接报错connect失败,报错:got packets out of order 和 connection closed by foreign host,业务怀疑数据库server有问题。

第一次测试业务认为没问题,第二次没连接上被Ctrl+c中止了,业务认为有问题。 

分析:

        数据库中报 Got packets out of order,是收到的包乱序,或者包内容截断丢失等,相关源码如下:

        客户端和服务端的net->pkt_nr都从0开始, 接受包时比较packet number和net->pkt_nr是否相等,不相等就报错本次看到的这个错误。相等pkt_nr自增,发送包时把net->pkt_nr作为packet number发送,然后对net->pkt_nr进行自增保持客户端服务端一致,新查询会清0这个值。数据库这边就是对收到的包做简单校验,比方一个新查询开始,数据库和客户端都清0,为了保证顺序,客户端把每个包按次序编号1、2、3、4放在包里面,数据库每收一个包就+1,和收到的包里的次序做比较,相等就认为没问题,不相等就会报错退出了,数据库后端不编排次序。

结合代码分析可能有以下情况导致报这个错:

1,乱序了,后面的包被先到了,校验不过报错。

2,多发了,这种可能性小,得符合协议。

3,少发了,这有可能,客户端发了5个,后端收了3之后直接收到了第5个,少了一个就会报错。

4,mysql本身协议有bug,这可能性小,毕竟大范围验证过,也不会在这上面有改动。

5,客户端没有发,MySQL认为少发了。

        tcp协调可以保证1、3不会出现,关联上下代码继续分析,只要朝MySQL端口发送数据包,就一定会尝试建立连接,就一定会connect成功,然后再解析数据库包,有问题就报错断开,理论上不存在无法建立连接情况,协议不对也会尝试直到报错,与前面无法connect成功的表现存在冲突。

        抓包分析发现,telnet每次都是能连上的,TCP链接建立没有问题。telnet连上以后,每次MySQL都发了server端信息,但telnet有时候会不显示在前端,大多数都显示,但不管显示还是没显示,从抓包来看,都连上了,而没显示的时候会让人误以为没连上,按ctrl+c强制中止,或等MySQL端超时结束这个tcp连接。

结论:

        所以是每次都连上了,这也符合的MySQL源码中的逻辑,但是不知道为什么telnet偶尔没提示连上,这时候不管是按ctrl + c,还是按回车,都会发一些数据给MySQL,由于不是MySQL协议,MySQL会报错。再进一步分析需要深入telnet源码,此处不再发散深入。

         telnet探测MySQL服务端并不准确,应该用MySQL 客户端,或者符合MySQL通信协议的方式来探测。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐