磁盘输入和输出作成本高昂,大多数作系统都实施缓存策略,用于将数据读取和写入文件系统。 Linux 内核通常使用页面缓存等策略来提高整体性能。 页面缓存的主要目标是在缓存中存储从文件系统读取的数据,使其在内存中可用于将来的读取作。
本文可帮助识别和避免磁盘密集型应用程序中由于 Kubernetes Pod 上的 Linux 内核行为而占用大量内存。
先决条件
用于连接到 Kubernetes 群集的工具,例如 kubectl
。 若要使用 Azure CLI 进行安装kubectl
,请运行 az aks install-cli 命令。
症状
当 Pod 上运行的磁盘密集型应用程序执行频繁的文件系统作时,可能会出现高内存消耗。
下表概述了高内存消耗的常见症状:
症状 | DESCRIPTION |
---|---|
工作集的度量值太高。 | 当 Kubernetes 指标 API 报告的工作集指标与应用程序使用的实际内存之间存在显著差异时,会出现此问题。 |
内存不足(OOM)强制终止。 | 此问题表示 Pod 上存在内存问题。 |
在大量磁盘活动后,内存使用量增加。 | 执行备份、大型文件读取/写入或数据导入等作后,内存消耗将增加。 |
内存使用量无限期增长。 | 即使应用程序本身没有内存泄漏,Pod 的内存消耗仍然会随时间推移不断增加,就像存在内存泄漏一样。 |
故障排除清单
步骤 1:检查 Pod 工作集
若要检查 Kubernetes 指标 API 报告的工作 Pod 集,请运行以下 kubectl top pods 命令:
$ kubectl top pods -A | grep -i "<DEPLOYMENT_NAME>"
NAME CPU(cores) MEMORY(bytes)
my-deployment-fc94b7f98-m9z2l 1m 344Mi
有关如何确定哪个 Pod 占用过多内存的详细步骤,请参阅 排查 AKS 群集中的内存饱和问题。
步骤 2:检查 Pod 内存统计信息
若要检查占用过多内存的 Pod 上的 c 组 的内存统计信息,请执行以下步骤:
注释
Cgroups 可帮助对 Pod 和容器强制实施资源管理,包括 CPU/内存请求和容器化工作负荷的限制。
连接到 pod:
$ kubectl exec <POD_NAME> -it -- bash
导航到
cgroup
统计信息目录并列出与内存相关的文件:$ ls /sys/fs/cgroup | grep -e memory.stat -e memory.current memory.current memory.stat
-
memory.current
:当前由cgroup
及其后代使用的内存总量。 -
memory.stat
:这会将 cgroup 的内存占用分解为不同类型的内存、特定于类型的详细信息,以及有关内存管理系统的状态和过去事件的其他信息。
这些文件中列出的所有值都以字节为单位。
-
大致了解如何在 Pod 上分配内存消耗:
$ cat /sys/fs/cgroup/memory.current 10645012480 $ cat /sys/fs/cgroup/memory.stat anon 5197824 inactive_anon 5152768 active_anon 8192 ... file 10256240640 active_file 32768 inactive_file 10256207872 ... slab 354682456 slab_reclaimable 354554400 slab_unreclaimable 128056 ...
cAdvisor
使用memory.current
和inactive_file
计算工作集指标。 可以使用以下公式复制计算:working_set = (memory.current - inactive_file) / 1048576 = (10645012480 - 10256207872) / 1048576 = 370 MB
步骤 3:确定内核和应用程序内存消耗
下表描述了一些内存段:
细分市场 | DESCRIPTION |
---|---|
anon |
匿名映射中使用的内存量。 大多数语言使用此段来分配内存。 |
file |
用于缓存文件系统数据的内存量,包括 tmpfs 和共享内存。 |
slab |
用于在 Linux 内核中存储数据结构的内存量。 |
结合 步骤 2, anon
表示 5,197,824 字节,这与工作集指标报告的总量不接近。
slab
Linux 内核使用的内存段表示 354,682,456 字节,这几乎是 Pod 上工作集指标报告的所有内存。
步骤 4:在调试器 Pod 上删除内核缓存
注释
此步骤可能会导致可用性和性能问题。 避免在生产环境中运行它。
获取运行 Pod 的节点:
$ kubectl get pod -A -o wide | grep "<POD_NAME>" NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES my-deployment-fc94b7f98-m9z2l 1/1 Running 0 37m 10.244.1.17 aks-agentpool-26052128-vmss000004 <none> <none>
使用 kubectl debug 命令创建调试器 Pod,并创建
kubectl
会话:$ kubectl debug node/<NODE_NAME> -it --image=mcr.microsoft.com/cbl-mariner/busybox:2.0 $ chroot /host
删除内核缓存:
echo 1 > /proc/sys/vm/drop_caches
通过重复 步骤 1 和 步骤 2 验证上一步中的命令是否会导致任何影响:
$ kubectl top pods -A | grep -i "<DEPLOYMENT_NAME>" NAME CPU(cores) MEMORY(bytes) my-deployment-fc94b7f98-m9z2l 1m 4Mi $ kubectl exec <POD_NAME> -it -- cat /sys/fs/cgroup/memory.stat anon 4632576 file 1781760 ... slab_reclaimable 219312 slab_unreclaimable 173456 slab 392768
如果您观察到工作集和 slab
内存段的显著减少,那么您可能遇到了 Linux 内核在 Pod 上占用大量内存的问题。
解决方法:配置适当的内存限制和请求
Kubernetes Pod 上高内存消耗的唯一有效解决方法是设置实际的资源 限制和请求。 例如:
resources:
requests:
memory: 30Mi
limits:
memory: 60Mi
通过在 Kubernetes 或规范中配置适当的内存限制和请求,可以确保 Kubernetes 更有效地管理内存分配,从而缓解过度内核级缓存对 Pod 内存使用情况的影响。
谨慎
配置错误的 Pod 内存限制可能会导致 OOMKilled 错误等问题。
参考文献
第三方信息免责声明
本文讨论的第三方产品由独立于微软的公司制造。 Microsoft对这些产品的性能或可靠性不作任何明示或暗示的保证。
第三方联系人免责声明
为了帮助您获取有关此主题的更多信息,Microsoft 提供了第三方的联系信息。 该联系信息可能会在不通知的情况下更改。 微软不保证第三方联系信息的准确性。