网络相关

Lettuce RedisCommandTimeoutExcep

2023-08-04  本文已影响0人  Oliver_Li

一、排查过程:

  1. 从报错来看,猜测是单纯网络问题,但都是15分钟后自动恢复,所以猜测并不只是网络抖动,而且网络15分钟以内应该已经恢复,但是客户端没有及时重连,所以代码逻辑上也有问题
  2. 报错前客户端访问Redis正常,排除长时间闲置导致客户端断开,应该并没有达到本机Keepalive时间(猜测),如果Keepalive超时断连,客户端应该也会触发重连
  3. 分析Lettuce后,发现Lettuce内部Netty触发ChannelInactived后就会重连,ChannelInactived是客户端断开后的回调,所以猜测客户端15分钟后才断连,触发了重连
  4. 然后分析服务端,Redis并没有重启,就算进程退出,正常在结束时TCP也会触发close(),客户端收到后也会及时退出
  5. 猜测网络抖动服务端因为Keepalive关闭连接,FIN并没有到达客户端,导致了TCP半打开,这也能解释客户端并没有及时触发ChannelInactived
  6. 剩下2个问题,为什么是15分钟,还有重试时为什么客户会端超时,而不是服务端返回RST(我印象里半打开服务端恢复后客户端再发消息会返回RST,进而客户端收到后会断连!)
  7. 原文分享了一个issue:https://github.com/lettuce-io/lettuce-core/issues/1428

二、相关概念

  1. TCP半打开、半连接、半关闭:
  1. KeepAlive常用的探活机制:启用SO_KEEPALIVE进行探活,如果无法返回则认为对方宕机,后续可以采取重连或其他措施
  1. 这里有个问题,KeepAlive启动的场景是在一个正常响应后,就是说如果上一个数据包发送没有响应,这时是超时重试阶段,系统并不会启动KeepAlive进行探活,只是简单的认为卡了
  2. tcp_retries2:Linux配置,默认15次代表tcp请求重试次数,重试的时间从200ms指数增长,最大120s,总时长15.4min,如果15.4min还是超时则断开连接,重试次数和时间分布如下图,这个问题之前竟然没注意过!


    tcp_retries2重试次数和时间
  3. 关于服务端闪断后对客户端连接的影响(半打开):
  1. TCP_USER_TIMEOUT:代表数据包N秒没收到响应,触发超时,配置后tcp_retries2会失效!

三、代码调整:

四、总结:

五、后续:

上一篇 下一篇

猜你喜欢

热点阅读