pod连接外部数据库超时分析和处理方法
1、错误日志
关键日志:Caused by: java.net.SocketTimeoutException: connect timed out
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server.
at sun.reflect.GeneratedConstructorAccessor122.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:990)
at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:342)
at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2188)
at com.mysql.jdbc.ConnectionImpl.connectWithRetries(ConnectionImpl.java:2037)
... 21 common frames omitted
Caused by: java.net.SocketTimeoutException: connect timed out
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at com.mysql.jdbc.StandardSocketFactory.connect(StandardSocketFactory.java:211)
at com.mysql.jdbc.MysqlIO.<init>(MysqlIO.java:301)
... 23 common frames omitted
2、分析
1、检查配置的db host是否有误,检查结果:host正确
2、在容器内ping数据库的host是否能ping通,检查结果:能ping通
3、检查calico网络组件日志是否正常,检查结果:日志正常,要是calico有故障,影响的是所有的项目
4、联系网络同事检查网络是否有问题或有对该机房网络是否有进行过调整,反回结果是没有变更操作
5、联系dba同事查看数据库是否有慢查询和数据库连接数是否高,反回结果都是正常
6、检查pod使用内存情况,检查结果:正常
7、咨询成都侧有没有遇到类似的问题,反回结果检查下数据库服务器和node节点服务器的时间戳参数
8、受成都侧的提醒,加上联想到之前北京db侧有个自动化系统在职场访问时好时坏,于是找dba查看故障业务所用数据库的系统参数,发现开启了net.ipv4.tcp_tw_recycle这个参数,而且通过netstat -s|grep rejected查看,被拒绝的包一直在增加,于是建议dba修改net.ipv4.tcp_tw_recycle为0,表示关闭该参数
3、定位问题
改完参数net.ipv4.tcp_tw_recycle为0后,大概过了10分钟,在db服务器上通过命令查看netstat -s|grep rejected这个值没有再增加,业务侧在改完参数后,也没有反馈系统无法使用,日志方面,也没有再出现无法连接数据库的报错日志,通过在网上查询资料定位到问题原因:由于pod内连接数据库经过了一次NAT转换,客户端TCP请求到达数据库,修改目的地址(IP+端口号)后便转发给数据库服务器,而客户端时间戳数据没有变化。对于数据库来说,请求的源地址是node节点IP,所以从数据库的角度看,原本不同客户端的请求经过NAT的转发,就可能会被认为是同一个连接,加之不同客户端的时间可能不一致,所以就会出现时间戳错乱的现象,于是后面的数据包就被丢弃了,具体的表现通常是是客户端明明发送的SYN,但服务端就是不响应ACK,还可以通过下面命令来确认数据包不断被丢弃的现象:netstat -s|grep rejected
4、问题解决
在故障业务所在数据库上设置net.ipv4.tcp_tw_recycle为0,其实这个参数默认是关闭的,开启net.ipv4.tcp_tw_recycle的目的,就是希望能够加快TIME_WAIT状态的回收,但其实linux官方是不建议开启这个参数,可以通过在服务上通过man tcp查看:
tcp_tw_recycle (Boolean; default: disabled; since Linux 2.4) Enable fast recycling of TIME_WAIT sockets. Enabling this option is not recommended since this causes problems when working with NAT (Network Address Translation).
并且该参数在内核4.10内核后彻底没有了用武之地,并且在4.12内核中被移除,生产k8s node节点都有升级过内核至4.18,通过命令查看会发现已找不到该值
[root@ser10-13 ~]# sysctl net.ipv4.tcp_tw_recycle
sysctl: cannot stat /proc/sys/net/ipv4/tcp_tw_recycle: 没有那个文件或目录
5、思考
通过抓包发现为什么pod注册dubbo是pod的IP,连接数据库和redis以及mq就通过了NAT转换成node节点的IP?
6、参考链接
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=4396e46187ca5070219b81773c4e65088dac50cc #net.ipv4.tcp_tw_recycle参数被移除的文章
https://www.iyunw.cn/archives/xie-lin-lin-jiao-xun-sheng-cheng-huan-jing-bu-yao-luan-xiu-gai-net-ipv4-tcp-tw-recycle/ #血淋淋教训,生产环境不要乱修改net.ipv4.tcp_tw_recycle
https://blog.csdn.net/zhuyiquan/article/details/68925707 #tcp_tw_recycle参数引发的系统问题
https://blog.csdn.net/wireless_tech/article/details/6405755 #【经验总结】tcp_tw_recycle参数引发的故障
天天向上,空杯心态。