Kubernetes IPVS相关问题记录

RabbitMQ客户端频繁出现 rabbitmq Connection reset by peer

1
RabbitMQ Client -> K8S Service(IPVS Cluster IP) -> RabbitMQ Server

RabbitMQ Client连接K8S Service使用长连接(内部管理着连接池),客户端启动一段时间后,频繁出现rabbitmq Connection reset by peer错误。

原因如下:

ipvs tcp连接的失效时间默认是900s:

1
2
ipvsadm -l --timeout
Timeout (tcp tcpfin udp): 900 120 300

而操作系统的tcp连接失效时间默认是7200s :

1
net.ipv4.tcp_keepalive_time = 7200

当某些长连接超过900s都没有使用,会被ipvs给clear掉,这时候mq客户端还以为tcp连接还在,会继续使用这条tcp长连接,实际上tcp连接已经断开了,这时候就会出现rabbitmq Connection reset by peer。

不仅仅是MQ,例如MySQL之类的使用长连接的服务,都有可能出现这个问题。

有几种解决方案可供参考:

  1. 修改系统的tcp连接失效参数和ipvs的一致
  2. 修改ipvs tcp连接失效参数
  3. 使用headless service直连MQ(前提是无需做负载均衡)

参考文章:

IPVS ClusterIP建立连接超过1s问题

主要是IPVS连接复用(五元组相同的连接进行复用,实际上就是客户端的端口复用)产生的问题。IPVS对端口的复用策略主要由内核参数net.ipv4.vs.conn_reuse_mode决定。

  1. 当设置为0时,IPVS对端口复用的新连接不会进行重新负载,而是复用之前的负载结果,将新连接转发到原来的RS(Real Server,可以把Service看作是一个负载均衡,RS就是这个负载均衡的后端服务器)。这样可能会使得连接更不均衡。
    a. 设置为0导致的问题:对于端口复用的连接,IPVS不会主动进行新的调度,也并不会触发结束连接或DROP操作,新连接的数据包会被直接转发到之前使用的RS。如果此时后端pod已经被删除(例如滚动更新的时候)就会出现异常。只要不断的有端口复用的连接请求发来,RS就不会被kube-proxy删除。
  2. 当设置为1时,IPVS对端口复用的新连接进行重新负载。 让每个RS的连接分布更均衡,以提高性能。
    a. 设置为1导致的问题:高并发场景下发生源端口与之前链接重复的情况,不会复用链接,而是会重新进行调度。根据ip_vs_in()的处理逻辑,当开启了net.ipv4.vs.conntrack时,这种情况会先DROP掉第一个SYN包,导致SYN的重传,有1秒延迟。导致性能下降。