k8s网络延迟排查与优化实战分享

引言

    在Kubernetes环境中,网络性能和稳定性对于确保服务的正常运行至关重要。然而,conntrack问题常常被忽视,导致网络连接异常,从而影响应用的正常运行。本文通过一个实际案例,详细介绍了如何发现和解决Kubernetes环境中的conntrack问题,以引起大家对这一问题的重视。 

背景 

    这是早前的一个案例,那时候随着微服务数量的增加和请求量的上涨,我们当时从监控注意到业务高峰时线上接口的慢请求越来越多,原本毫秒级响应的接口偶尔会出现请求延迟超过1秒的现象,严重影响了用户体验。为了解决这一问题,我们在非生产环境通过压测工具进行复现,如下是具体排查和优化过程。 

请求链路 

    当时采用的是nginx作为流量网关反向代理微服务网关,微服务和其网关跑在k8s集群上,微服务网关通过NodePort的形式暴露,为了方便问题复现和排查,我们把复现环境的Pod设置为单副本,访问链路大致如下。 

排查与分析过程 

1、起初怀疑是节点带宽满了,经查看监控,流量都很正常,所以暂时排除;

2、查看skywalking调用链监控,发现这些请求都有一个共同点,在nginx upstream这个环节耗时较长,难道问题在nginx?

 

3、看了一下nginx的各项监控指标都很正常,远远没达到其性能瓶颈,那就抓个包呗?不抓还好,一抓下一跳,有大量的 TCP Retransmission(TCP 重传) ,插播知识点:

当发送方的 TCP 在一定时间内没有收到确认(ACK)响应时,会认为数据包可能丢失或未成功传输,因此会重新发送相同的数据包,这个过程称为 TCP 重传。简单来说,TCP 重传是为了确保数据可靠传输的一种机制。

在 Wireshark 中,你可以看到标记为 "TCP Retransmission" 的事件。这表示发送方多次发送了同一个序列号的数据包,因为之前的传输没有得到确认。每次重传,发送方都会等待一段时间,称为超时重传时间(RTO),如果还没有收到 ACK,就会再次发送数据包。

通过这种机制,TCP 能够确保数据即使在网络状况不佳时,也能最终到达目的地,保证了数据传输的可靠性。

 

 4、抽一个看了下跟踪流(TCP Stream),可以看到这个请求与上游服务重传了大约1s才建立了连接,难怪nginx upstream耗时那么长了,好的,我们在找到原因后,我们需要继续探索这些请求为什么会发生TCP重传呢?让我们继续往下看。

 5、为了搞清楚TCP重传的原因,我们需要分别在nginx、pod和pod所在的node节点上进行抓包,如下图,我们在pod的抓包结果中发现,pod侧没有收到第一个syn报文 ,所以猜测包可能是在node和pod之间丢了。

6、节点连接数满了?通过下面指令查看,连接数并不是很多,很正常。 

netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

7、难道是conntrack表满了?之所以想起conntrack,是因为NodePort模式在将报文转发给 Pod 的过程中,报文会经历五元组(源 IP、源端口、目的 IP、目的端口、协议)的转换。由于请求量较大,可能会撑爆conntrack表,果不其然,如下图,我们捕获到conntrack丢包和插入失败的信息,罪魁祸首终于找到了。 

# 打印conntrack统计信息
conntrack -S
# 其实也可以通过`dmesg|grep conntrack`查看异常日志,但当时直接用的上面指令,所以没有截图

 

问题优化 

好了,在确定根本问题后,优化和避免问题重复发生至关重要。以下是几种优化思路:

  1. 增加NodePort节点:在nginx的upstream中多挂几个NodePort节点分摊负载,这种方式改动最小。

  2. 修改service为LoadBalancer:将service的访问方式修改为LoadBalancer可以直接将流量引导到Pod,避免了通过NodePort和Node的转发,减少了五元组转换带来的瓶颈。

  3. 使用Ingress进行负载均衡:去掉nginx,使用Ingress进行service的负载均衡。

Q&A

Q1:conntrack的最大值是多少?

A1:conntrack的最大值(内核参数 net.netfilter.nf_conntrack_max )是根据kube-proxy配置的参数--conntrack-max-per-core * 节点cpu核数进行计算的,假设--conntrack-max-per-core的值设置为65536,节点有32核的CPU,则conntrack的最大值为65536 * 32 = 2097152,下图是kube-proxy官方的参数解释。

 

Q2:conntrack的最大值在哪里看?

A2:可以查看nf_conntrack_max文件,指令如下

cat /proc/sys/net/netfilter/nf_conntrack_max

Q3:conntrack的最大值如何修改?

A3:可以修改kube-proxy的启动参数,或者修改节点的内核参数,一般推荐后者,这是修改的方法

# 临时生效
sudo sysctl -w net.netfilter.nf_conntrack_max=2097152
# 永久生效
echo 'net.netfilter.nf_conntrack_max=2097152' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

总 结 

    conntrack监控真的太重要了,为了尽可能避免conntrack表满的情况,在高并发的场景建议使用ingress的方案,本期分享就到这里,谢谢!

参考链接:

https://kubernetes.io/zh-cn/docs/reference/command-line-tools-reference/kube-proxy/

欢迎订阅我的公众号「SRE运维手记」,可扫下方二维码,或者微信搜“SRE运维手记”

 

  • 12
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值