k8s环境增加实例,其它实例延迟变高(1)

k8s环境通常会在一台物理机上部署各种服务,各服务通过cgroup限制自身CPU、内存的使用,保障隔离性。 在线上发现一台机器,一旦启动其它实例,原有实例的延迟就会升高。 此时整机的CPU使用率不足30%,IO也很少,传统视角看,整机的负载非常低。

1 实例部署现状

这台机器有2个socket,每个socket 26个core,开启了超线程,整机看有104个CPU。 我们把延迟升高的那个实例称作A。

  1. socket0的CPU使用率在32%左右,socket1在15%左右,两个socket的CPU使用率非常不均衡;
  2. 实例A做了numa亲和,运行在socket0,CPU使用率在30%左右(1500%-1700% 按照52个CPU折算)。

2 实例A受影响的情况

  1. 实例A的IPC之前稳定在0.75左右,新增实例后在0.5-0.6间波动;
  2. 实例A的CPU使用率之前稳定在1200,新增实例后在1300-1800%间波动;

实例A CPU使用率的变化解释了实例A延迟的上升,也表明受到了新增实例的干扰。 但是从整机层面看,新增加实例后,CPU使用率上升不到1%,变化非常小,所以实例A受到的干扰,应该不是来自CPU的争用。

3 内存带宽

在讨论机器负载时,内存带宽通常是一个被忽略的因素。当内存带宽超过某个值(通常在50%左右),内存延迟会急剧上升,则IPC下降,CPU使用率升高。

内存带宽的变化:

  1. socket0的单通道带宽从7G上升到12G;
  2. socket1的单通道带宽几乎没有变化,在4G左右。

socket0的单通道带宽12G,差不多50%左右,应该是它导致了实例A延迟的上升。

前面提到socket1 CPU使用率低,新增加的实例,如果没有numa亲和,内核通常会调度到socket1运行,保证两个socket CPU使用的均衡,理论上socket1的带宽应该上升才对。

4 内存分配的均衡

numactl -H 观察两个socket的内存情况,socket1的free内存极少,socket0则较多。 一个合理的猜测是,因为socket0的free内存较多,新增实例的内存分配总是发生在socket0,无论新增实例运行在socket0,还是socket1,内存带宽的消耗总是发生在socket0。(内核可能为了避免跨socket访问内存,而牺牲掉CPU使用的均衡)

因为使用的内存中pagecache很多,通过 echo 3 | tee /proc/sys/vm/drop_caches 释放pagecache,增加socket1的free内存,可用避免跨socket分配内存。

这个操作后的变化:

  1. socket0的单通道带宽恢复到7G,socket1的单通道带宽上升到6G;
  2. 实例A的CPU使用率恢复到1200%,业务延迟恢复;
  3. 两个socket的cpu使用率变得均衡。

疑惑 socket0的单通道带宽下降5G,而socket1的单通道带宽只上升2G,这两个值有点对不上。

如何保证socket的内存均衡呢?一个可行的方法是,机器的所有组件都放到cgroup中,限制每个cgroup的内存,这样可以保证pagecache的隔离。

5 总结

因为pagecache导致socket间free内存不均衡,出现了跨socket分配(使用)内存的情况,导致socket间内存带宽不均衡,其中一个socket内存带宽饱和,影响了业务可用性。

Author: zhengzhiyong

Created: 2023-10-29 日 21:42

Validate