解决kubernetes网络在高负载下抖动
背景
业务团队反馈说k8s的网络在高压下不稳定。平时都很正常,但是高压下延迟会升很高。我们的基础设施都很新,操作系统和k8s以及CNI都是当前的最新版。
排查过程
追溯历史
先看基础指标,查看node-exporter的指标,看到虽然机器的确高压,但是也没到100%占用。再看cilium的连接信息,虽然有大量短连接占用资源,但是也不至于瓶颈。历史指标看不出特别奇怪的,再简单地测试工况下,网络质量都很好,想办法制造现场重现。
重现
让业务团队配合提供高压环境, 然后我们持续监控网络的质量,在不确定是哪边出问题的情况下,只能添加更多的实验组。检测方式就采取最简单的长ping,我们都在这儿持续盯着,抖动的时候特征也比较明显,所以这儿也不需要更复杂的工具。 先后进行过两次测试。
第一次测试
| 实验组 | 特征 |
|---|---|
| my pod -> public IP | 稳定 |
| 业务 pod -> public IP | 抖动 |
当时也感觉挺奇怪,也怀疑是否是不同的容器的cgroup的CPU throttling,当然也可能是抖动没有被观测到,毕竟有很大的随机性。
第二次测试
第二次测试全程在高负载环境下运行,果然复现了抖动,大多数时候延迟都< 1ms, 但偶尔就是会飘高到数十毫秒。 第二次测试着重观察了 pod -> pod 的情况,并且开始怀疑节点差异,于是手工构造了my pod -> pod on another node 实验组用于对照,果然发现,跨节点的pod就会抖动。
| 实验组 | 特征 |
|---|---|
| my pod -> public IP | 抖动 |
| 业务 pod -> public IP | 抖动 |
| pod -> pod on same node | 稳定 |
| pod -> pod on another node | 抖动 |
为了避免其他的干扰, 直接进入node,在node上ping pod和其他node, 都复现了抖动。
| 实验组 | 特征 |
|---|---|
| node -> pod on another node | 抖动 |
| node -> another node | 抖动 |
这儿就能确定,网络抖动发生在节点网络上,与CNI都无关了。进一步发现只要是高压的节点,无论访问什么都抖动。
进一步排查节点之间的网络问题。我们的k8s节点是PVE上的虚拟机,节点间的网络就有比较长: k8s node -> bridge on PVE -> switch -> bridge on another PVE -> another k8s node。
为了排查瓶颈是否出在switch,虚拟网桥还是k8s节点上,设计了三组实验。通过k8s node -> bridge on PVE -> vm, 这样可以避开硬件干扰。再测试同一个PVE上的其他vm之间的网络,也就是other vm -> another vm on the same PVE,这样可以测试虚拟网桥。再测试跨物理机的其他vm之间的网络,也就是other vm -> another vm on the another PVE, 可以测试硬件switch。
| 实验组 | 特征 |
|---|---|
| k8s node -> vm on the same PVE | 抖动 |
| other vm -> another vm on the same PVE | 稳定 |
| other vm -> another vm on the another PVE | 稳定 |
结果显示,other vm -> another vm on the another PVE 跨物理机稳定,问题不在硬件交换机上。发现other vm -> another vm on the same PVE的网络畅通,虚拟网桥不太可能有瓶颈,同一个PVE上的其他节点之间都没问题。 k8s node -> vm on the same PVE的网络会抖动,而这一过程中的网络完全在同一台物理机上。最终得出只是k8s node自身的网络有问题。
出问题的节点虽然压力挺高,但是CPU使用率没到100%,怀疑是CPU的网络中断不均衡。
处理IRQ均衡
# cat /proc/softirqs | grep NET_
NET_TX: 0 38 ...
NET_RX: 0 9746189470 ...
看到NET_TX分布极不均衡, 我们的node有上百个CPU,网络操作却集中于一两个CPU上。虽然消耗资源的是soft irq, 但是背后的根本原因是hard irq, 因为软中断默认在硬中断所在的CPU上运行。
# cat /proc/interrupts
CPU0 CPU1 ...
34: 0 0 ... PCI-MSIX-0000:06:xx.0 0-edge virtio1-config
35: 0 0 ... PCI-MSIX-0000:06:xx.0 1-edge virtio1-input.0
36: 0 9835320695 ... PCI-MSIX-0000:06:xx.0 2-edge virtio1-output.0
看到网卡设备的IRQ基本集中于某个CPU. 而MSIX会把IRQ绑定到某个核心上,所以要进行CPU的负载均衡就需要增加IRQ。确认一下设备.
# lspci -s 06:xx.0
06:xx.0 Ethernet controller: Red Hat, Inc. Virtio network device
是virtio网卡设备,看一下网卡的队列
# ethtool -l eth0
Channel parameters for eth0:
...
Current hardware settings:
RX: n/a
TX: n/a
Other: n/a
Combined: 1
网卡只有一个队列,怪不得压力都到那一两个CPU上了。解决方式也很简单,将网卡配置上Multiqueue即可。配置之后
# ethtool -l eth0
...
Current hardware settings:
RX: n/a
TX: n/a
Other: n/a
Combined: 8
大功告成
修改PVE上node的virtio虚拟网卡,根据node的CPU数量,设置多个队列分散网络压力。