我在 Debian 9 上使用 kubeadm 构建了一个裸机 Kubernetes 集群(没什么大不了的,只有三台服务器)。按照 Kubernetes 的要求,我禁用了 SWAP:
- 交换-a
- 删除 SWAP 行
/etc/fstab
- 添加
vm.swappiness = 0
到/etc/sysctl.conf
因此,我的服务器上不再有 SWAP。
$ free
total used free shared buff/cache available
Mem: 5082668 3679500 117200 59100 1285968 1050376
Swap: 0 0 0
一个节点用于运行一些微服务。当我开始使用所有微服务时,它们每个都使用了 10% 的 RAM。并且 kswapd0 进程开始使用大量 CPU。
如果我稍微强调一下微服务,它们就会停止响应,因为 kswapd0 占用了所有的 CPU。我尝试等待 kswapd0 是否停止工作,但这种情况从未发生过。即使过了 10 小时。
我读了很多资料,但没有找到任何解决方案。
我可以增加 RAM 数量,但这不能解决我的问题。
Kubernetes Masters如何处理此类问题?
更多细节:
- Kubernetes 版本 1.15
- Calico 版本 3.8
- Debian 版本 9.6
首先感谢您的宝贵帮助。
-- 编辑 1 --
根据@john-mahowald 的要求
$ cat /proc/meminfo
MemTotal: 4050468 kB
MemFree: 108628 kB
MemAvailable: 75156 kB
Buffers: 5824 kB
Cached: 179840 kB
SwapCached: 0 kB
Active: 3576176 kB
Inactive: 81264 kB
Active(anon): 3509020 kB
Inactive(anon): 22688 kB
Active(file): 67156 kB
Inactive(file): 58576 kB
Unevictable: 92 kB
Mlocked: 92 kB
SwapTotal: 0 kB
SwapFree: 0 kB
Dirty: 0 kB
Writeback: 0 kB
AnonPages: 3472080 kB
Mapped: 116180 kB
Shmem: 59720 kB
Slab: 171592 kB
SReclaimable: 48716 kB
SUnreclaim: 122876 kB
KernelStack: 30688 kB
PageTables: 38076 kB
NFS_Unstable: 0 kB
Bounce: 0 kB
WritebackTmp: 0 kB
CommitLimit: 2025232 kB
Committed_AS: 11247656 kB
VmallocTotal: 34359738367 kB
VmallocUsed: 0 kB
VmallocChunk: 0 kB
HardwareCorrupted: 0 kB
AnonHugePages: 0 kB
ShmemHugePages: 0 kB
ShmemPmdMapped: 0 kB
HugePages_Total: 0
HugePages_Free: 0
HugePages_Rsvd: 0
HugePages_Surp: 0
Hugepagesize: 2048 kB
DirectMap4k: 106352 kB
DirectMap2M: 4087808 kB
答案1
kswapd0 的这种行为是设计使然,并且是可以解释的。
尽管您已禁用并删除交换文件并将 swappiness 设置为零,但 kswapd 仍在关注可用内存。它允许您在不采取任何措施的情况下消耗几乎所有内存。但是,一旦可用内存降至极低值(区域 Normal 中的低页面,/proc/zoneinfo
在我的测试服务器上约为 4K 页面的 4000 个),kswapd 就会介入。这会导致 CPU 利用率过高。
您可以重现该问题并通过以下方式进行深入调查。您将需要一个允许您以受控方式消耗内存的工具,例如 Roman Evstifeev 提供的脚本:ramhog.py
该脚本用 100MB 的 ASCII 代码“Z”填充内存。为了实验公平起见,该脚本在 Kubernetes 主机上启动,而不是在 pod 中启动,以便不让 k8s 参与。此脚本应在 Python3 中运行。它经过了一些修改,以便:
- 兼容Python3.6之前的版本;
- 将内存分配块设置为小于 4000 个内存页(/proc/zoneinfo 中区域 Normal 的低页面;我设置为 10 MB),以便系统性能下降最终更加明显。
from time import sleep print('Press ctrl-c to exit; Press Enter to hog 10MB more') one = b'Z' * 1024 * 1024 # 1MB hog = [] while True: hog.append(one * 10) # allocate 10MB free = ';\t'.join(open('/proc/meminfo').read().split('\n')[1:3]) print("{}\tPress Enter to hog 10MB more".format(free), end='') input() sleep(0.1)
您可以与测试系统建立 3 个终端连接来观察正在发生的事情:
- 运行脚本;
- 运行top命令;
- 获取 /proc/zoneinfo
运行脚本:
$ python3 ramhog.py
在多次按下 Enter 键之后(由于我们设置的内存分配块较小(10MB)),你会注意到
越来越MemAvailable
低,你的系统响应也越来越慢:ramhog.py 输出
可用页面将落到低水位线以下:空闲页面
因此 kswapd 将会唤醒,k8s 进程也会唤醒,CPU 利用率将升至 100%:顶部
请注意,该脚本与 k8s 分开运行,并且 SWAP 已禁用。因此,在测试开始时,Kubernetes 和 kswapd0 都处于空闲状态。正在运行的 pod 未受到影响。尽管如此,随着时间的推移,第三个应用程序导致的可用内存不足会导致 CPU 利用率过高:不仅是 kswapd,还有 k8s。这意味着根本原因是内存不足,而不是 k8s 或 kswapd 本身。
从/proc/meminfo
您提供的 可以看出,MemAvailable
变得非常低,导致 kswapd 被唤醒。请/proc/zoneinfo
同时查看您服务器上的 。
其实根本原因不在于 k8s 与 kswap0 冲突或不兼容,而在于禁用 swap 与内存不足之间的矛盾,进而导致 kswapd 激活。系统重启可以暂时解决问题,但确实建议增加更多 RAM。
这里对 kswapd 行为进行了很好的解释: kswapd 占用了大量的 CPU 周期
答案2
Kubernetes 允许我们使用参数定义应为 Linux 系统保留多少 RAM evictionHard.memory.available
。此参数在名为的 ConfigMap 中设置kubelet-config-1.XX
。如果 RAM 超出配置允许的级别,Kubernertes 将开始终止 Pod 以减少其使用量。
在我的例子中,该evictionHard.memory.available
参数设置得太低(100Mi)。因此,Linux 系统没有足够的 RAM 空间,因此当 RAM 使用率过高时,kswapd0 就会开始混乱。
经过一些测试,为了避免 kswapd0 的出现,我将 设置evictionHard.memory.available
为800Mi
。kswapd0 进程不再混乱。