问题现象:
测试环境中某业务平台的api访问不定时会失败,查看日志发现抛出了redis连接异常的信息。
问题分析思路:
1. 检查redis服务端,发现各个指标正常,日志也未打印任何的异常
2. 初步怀疑可能是网络不稳定,编写脚本长时间连续访问api,并尝试登录redis看是否异常,运行一段时间并未复现问题现象
3. 把测试脚本停止后,不定时测试反馈api报错,发现一个规律为api长时间没有调用后,则会触发该问题
通过问题现象排查:
1. 每隔一段时间不访问api则会出现该问题,说明应该是连接的会话异常了
2. 修改业务的pod为1个,等待一段时间后,检查redis服务端的已连接会话的客户端ip,比对客户端已连接redis服务端的会话,发现2边不一致,说明客户端与服务端的会话数确实是不一致的,可能是该问题引起的
3. 重启redis服务,断开所有连接,在redis服务端和客户端分别启动捉包,调用一次api后触发redis连接,查看redis服务端会话,约100多秒后发现已断开,客户端仍能看到该tcp连接,真相慢慢浮出水面
4. 使用wireshark查看捉包后发现是服务端主动断开连接,但是客户端并未收到断开的消息包,服务端尝试重发仍然失败后断开了该会话。
5. 初步怀疑是redis设置的超时断开参数导致,查看redis的配置timeout时间为300秒,把它改成0后(不断开),尝试模拟问题现象,未出现问题。
6. redis的超时配置和实际模拟复现大概100多秒不是很符合,怀疑可能是其它原因造成的,尝试将redis超时时间改成60秒,尝试模拟问题现象,并未出现该问题
7. 从现象得出结论并非是redis超时主动断开连接导致丢包,而是tcp层就已经断开了,查看内核参数,发现内核默认的tcp超时时间为120秒,和实际观察到的现象很接近
8. 尝试将redis时间超时改成90秒,未出现问题,尝试将redis超时时间改成150秒,复现问题现象
结论:
1. 该问题现象应该是tcp主动断连后丢失了fin包导致,临时解决方法,将redis的超时断开时间改为60秒
2. 后续咨询相关专家猜测可能k8s的网络中间经过了snat表,snat在tcp断连时已失效,所以导致客户端无法收到fin包,就出现了该现象