目录

容器网络的怪问题

案例太多,一次写完有点太难为我,我就想到哪写到哪,保持更新。

长连接报文重传失败

有个客户来找,说他们的应用Server端日志里经常有长连接中断的消息,需要我们定位中断的原因。

接到这个问题时属实挠头,看了客户的错误日志,一般中断发生的频率极低,一天只出现个位数,我们尝试复现问题未果。但是客户就是上帝,接了问题单就要定位,我们的SRE比较有毅力,一连抓了3天的报文,根据报错日志,把有问题的报文挑了出来,我们进行分析。

通过wireshark工具分析TCP流,我们发现有问题的报文都是连接时间超过2小时没有报文,然后Server端突然发送了一个报文,但是客户端并没有收到这个报文,重发几次后连接就中断了。定位到这儿问题已经很明显了,客户没有使用TCP keepalive,导致连接长时间没报文,最后报文在发出去后在 VPC 中被丢了。

VPC 一般只会在安全组位置进行丢包,这很可能是安全组导致的丢包。查看了安全组规则,确实没有放通Server到Client端的规则,只放通了Client到Server的规则,也就是说只能由Client主动连接Server端,反之不行。

安全组的实现一般会使用连接跟踪表,当Client端发起连接,和Server端建立TCP连接时,连接跟踪表会记录这条连接,允许Client和Server在这条连接上传输数据。但是连接跟踪表是有超时时间的,一般就2小时,当两小时没有报文命中时,就老化掉该规则,这时Server端再发送报文时,就被安全组拒绝了。客户的问题应该就是这个原因。

这种情况一般建议客户开启TCP keepalive,这个问题并不是容器网络特有的问题,普通网络都会遇到。

长连接出现连接拒绝

容器网络还遇到一个客户来找我们,说他们POC测试的时候发现测试多轮大量长连接访问容器中的Server时会有一定几率出现Connect Refused错误。

接到问题后祭出tcpdump神器进行抓包,先简单描述下网络路径:

1
2
        访问NodePort                         DNAT成Pod IP        SNAT成GW IP
Client --------------> VM1 -----------> DNAT ------------> SNAT -------------> Server Pod

我们抓两个位置的包 VM1 和 Server Pod,当出现Connect Refused时,Server Pod确实收到了报文,但是却回了一个RST报文。面对这种情况,头脑风暴分析了下可能的原因:

  1. nginx 有问题
  2. 连接数满了
  3. 连接被占用了
  • 原因1不太可能
  • 原因2我们查看了系统参数,连接数并没有达到上限,也排除
  • 原因3我们在抓包的同时继续用netstat查看当前连接状态,发现当出现Connect Refusted报文时,果然连接仍然被占用着。

为什么会连接冲突呢,问题肯定出在SNAT的过程中,SNAT挑选的源端口有问题。通过分析报文,突然发现这些长连接也有一个特点,连接建立后并没有数据的传输,只是一直占用的通道,看到这里心中已经对问题的根因有了大致的猜想,肯定和连接跟踪超时有关。查看了主机和容器的 tcp_keepalive_time 的值,果然主机配置了1800,容器是7200,不同的timeout值,使得主机在1800后释放了tcp连接,重新分配的源端口给新的连接,而容器并未释放,最终导致访问Server返回Connect Refused错误。

这种情况我们自然建议可以将主机的 tcp_keepalive_time 改回成 7200,和容器保持一致,基本避免了该错误的发生。