本文已发布一年以上。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已变得不正确。
Kubernetes 内存管理器移至 Beta
这篇博客文章解释了 Kubernetes 1.22 的测试版功能内存管理器的一些内部原理。在 Kubernetes 中,内存管理器是一个 kubelet 子组件。内存管理器为 Guaranteed
QoS 类中的 Pod 提供有保证的内存(和巨页)分配。
这篇博客文章涵盖了
你为什么需要它?
一些 Kubernetes 工作负载运行在具有非均匀内存访问 (NUMA) 的节点上。假设你的集群中有 NUMA 节点。在这种情况下,你将了解当计算资源需要访问不同 NUMA 区域中的内存时,可能会出现额外的延迟。
为了使你的工作负载获得最佳性能和延迟,容器 CPU、外围设备和内存都应与相同的 NUMA 区域对齐。在 Kubernetes v1.22 之前,kubelet 已经提供了一组管理器来对齐 CPU 和 PCI 设备,但是你无法对齐内存。Linux 内核能够尽最大努力从容器执行所在的同一个 NUMA 节点为任务分配内存,但是不能保证这种放置。
它是如何工作的?
内存管理器主要做两件事
- 向拓扑管理器提供拓扑提示
- 为容器分配内存并更新状态
Kubelet 下内存管理器的整体序列
在准入阶段
- 在第一次处理新 Pod 时,kubelet 会调用 TopologyManager 的
Admit()
方法。 - 拓扑管理器会为包括内存管理器在内的每个提示提供程序调用
GetTopologyHints()
。 - 内存管理器会计算 Pod 内每个容器的所有可能的 NUMA 节点组合,并将提示返回给拓扑管理器。
- 拓扑管理器会为包括内存管理器在内的每个提示提供程序调用
Allocate()
。 - 内存管理器会根据拓扑管理器选择的提示在状态下分配内存。
在 Pod 创建期间
- kubelet 会调用
PreCreateContainer()
。 - 对于每个容器,内存管理器会查找为该容器分配内存的 NUMA 节点,然后将该信息返回给 kubelet。
- kubelet 会通过 CRI 使用包含内存管理器信息的容器规范来创建容器。
让我们来谈谈配置
默认情况下,内存管理器使用 None
策略运行,这意味着它只会放松并且不做任何事情。要使用内存管理器,你应为 kubelet 设置两个命令行选项
--memory-manager-policy=Static
--reserved-memory="<numaNodeID>:<resourceName>=<quantity>"
--memory-manager-policy
的值很简单:Static
。决定为 --reserved-memory
指定什么需要更多的思考。要正确配置它,你应遵循两个主要规则
memory
资源的预留内存量必须大于零。- 资源类型的预留内存量必须等于该资源的 NodeAllocatable (
kube-reserved + system-reserved + eviction-hard
)。你可以在 为系统守护程序预留计算资源中阅读有关内存预留的更多信息。
当前的局限性
1.22 版本和晋升为测试版带来了增强功能和修复,但是内存管理器仍然存在一些局限性。
单个与跨 NUMA 节点分配
NUMA 节点不能同时具有单个和跨 NUMA 节点分配。当容器内存固定到两个或多个 NUMA 节点时,我们无法知道容器将从哪个 NUMA 节点消耗内存。
container1
在 NUMA 节点 0 上启动,并请求 5Gi 的内存,但目前仅消耗 3Gi 的内存。- 对于 container2,内存请求为 10Gi,并且没有单个 NUMA 节点可以满足它。
container2
从 NUMA 节点 0 消耗 3.5Gi 的内存,但是一旦container1
需要更多内存,它将没有足够的内存,并且内核将使用 OOM 错误终止其中一个容器。
为防止此类问题,内存管理器将拒绝 container2
的准入,直到机器有两个没有单个 NUMA 节点分配的 NUMA 节点。
仅适用于保证的 Pod
内存管理器无法保证对 Burstable Pod 的内存分配,即使 Burstable Pod 指定了相等的内存限制和请求也是如此。
假设你有两个 Burstable Pod:pod1
具有具有相等内存请求和限制的容器,而 pod2
仅具有设置了内存请求的容器。你想要保证 pod1
的内存分配。对于 Linux 内核,任一 Pod 中的进程都具有相同的 *OOM 分数*,一旦内核发现它没有足够的内存,它可能会终止属于 Pod pod1
的进程。
内存碎片
启动和停止的 Pod 和容器的序列会使 NUMA 节点上的内存碎片化。内存管理器的 alpha 实现没有任何机制来平衡 Pod 并使内存恢复碎片化。
内存管理器的未来工作
我们不想停留在内存管理器的当前状态,并正在寻求改进,包括以下领域。
使内存管理器分配算法更智能
当前的算法在计算分配时会忽略 NUMA 节点之间的距离。如果无法进行同节点放置,通过更改内存管理器以优先选择最近的 NUMA 节点进行跨节点分配,我们仍然可以提供比当前实现更好的性能。
减少准入错误的数量
默认的 Kubernetes 调度程序不了解节点的 NUMA 拓扑,这可能是 Pod 启动期间出现许多准入错误的原因。我们希望添加一个 KEP(Kubernetes 增强提案)来涵盖这方面的改进。请关注 kube-scheduler 中的拓扑感知调度程序插件,以了解此想法的进展情况。
结论
随着 1.22 中内存管理器晋升为测试版,我们鼓励每个人都尝试一下,并期待你可能有的任何反馈。虽然仍然有一些局限性,但我们计划了一系列增强功能来解决这些问题,并期待在即将发布的版本中为你提供许多新功能。如果你有其他增强功能的想法或需要某些功能,请告知我们。该团队始终乐于接受建议,以增强和改进内存管理器。我们希望你觉得这篇博客内容丰富且有帮助!如果你有任何问题或意见,请告诉我们。
你可以通过以下方式联系我们
- Slack 中的 Kubernetes #sig-node 频道(如果需要,请访问 https://slack.k8s.io/ 获取邀请)
- SIG Node 邮件列表,[email protected]