k8s优化之关闭swap
在 Kubernetes(k8s)集群中,默认要求关闭 Swap,主要原因涉及 调度准确性、性能稳定性 和 容器隔离性。以下是具体影响和底层逻辑分析:
1. Kubernetes 官方明确要求禁用 Swap
- 官方文档说明:
Kubernetes 从设计上假设节点资源(CPU、内存)是完全可分配的,而 Swap 的引入会打破这一假设,导致调度器(kube-scheduler)无法准确评估 Pod 的资源使用情况。
2. Swap 对 Kubernetes 性能的具体影响
(1) 调度器(kube-scheduler)失效
- 问题:
Kubernetes 调度器依赖节点的Allocatable Memory
(可分配内存)决定 Pod 的放置。如果开启 Swap:- 节点可能过度承诺(Overcommit)内存资源,导致多个 Pod 被调度到同一节点。
- 当物理内存不足时,Swap 的 I/O 延迟会拖慢所有 Pod,而调度器无法预判这种性能波动。
- 表现:
Pod 看似调度成功,但实际运行时因 Swap 频繁读写导致性能骤降。
(2) 容器隔离性被破坏
- 问题:
Linux Cgroups 的内存限制(memory.limit_in_bytes
)默认仅限制物理内存,不限制 Swap 使用。- 若开启 Swap,容器可能通过 Swap 绕过内存限制,导致:
- 一个贪婪的 Pod 占用大量 Swap,挤占其他 Pod 的磁盘 I/O 带宽。
- 节点整体性能下降(磁盘 I/O 成为瓶颈)。
- 若开启 Swap,容器可能通过 Swap 绕过内存限制,导致:
- 表现:
docker stats
或kubectl top pod
显示内存未超限,但节点响应缓慢。
(3) 性能波动不可预测
- 问题:
Swap 的触发依赖内核的内存回收机制(如kswapd
),而 Kubernetes 的 QoS(服务质量等级)无法与之协调。- Burstable Pod 可能因 Swap 频繁换入换出(
si/so
)导致延迟飙升。 - Guaranteed Pod 的 SLA 无法保证(预期独占的资源被 Swap 间接共享)。
- Burstable Pod 可能因 Swap 频繁换入换出(
- 表现:
应用延迟(P99)出现长尾现象,尤其影响数据库、实时计算等场景。
3. 为什么老师会说“Swap 影响性能”?
这里的“性能”是广义的,包括:
- 调度性能:kube-scheduler 无法正确决策。
- 运行时性能:Swap I/O 延迟导致应用响应变慢。
- 集群稳定性:OOM Killer 可能误杀关键容器。
4. 如何正确关闭 Swap?
(1) 永久禁用 Swap
# 临时关闭
sudo swapoff -a
# 永久关闭(注释 /etc/fstab 中的 Swap 行)
sudo sed -i '/swap/s/^/#/' /etc/fstab
# 验证
free -h # Swap 行应全为 0
(2) 修改 kubelet 参数(旧版本)
- Kubernetes 1.22+ 已默认禁止 Swap,但旧版本需显式配置:
# 在 /etc/default/kubelet 中添加 KUBELET_EXTRA_ARGS="--fail-swap-on=false"
5. 特殊情况:如果必须使用 Swap?
极少场景下(如开发测试环境内存不足),可通过以下方式妥协:
(1) 调整内核参数
# 降低 Swappiness,减少 Swap 使用倾向
echo 1 | sudo tee /proc/sys/vm/swappiness
(2) 使用 Kubernetes Alpha 特性(不推荐生产)
- Kubernetes 1.22+ 实验性支持 Swap,但需手动启用:
# kubelet 配置 featureGates: NodeSwap: true
总结:Swap 在 K8s 中的影响
维度 | 开启 Swap 的后果 | 关闭 Swap 的收益 |
---|---|---|
调度准确性 | 资源过度承诺,Pod 调度失效 | 调度器精确判断节点可用资源 |
性能稳定性 | 磁盘 I/O 瓶颈,延迟波动大 | 避免不可预测的 Swap I/O 延迟 |
隔离性 | 容器可能通过 Swap 突破内存限制 | Cgroups 限制严格生效 |
运维复杂度 | 需监控 Swap 使用,调试困难 | 问题排查更直接(OOM 即内存不足) |
结论:
- 生产环境:严格禁用 Swap,确保 Kubernetes 的调度和资源隔离机制正常工作。
- 开发环境:如果内存不足,建议扩容节点而非依赖 Swap。
对limits/request的影响
Pod 中的 limits
和 requests
资源请求/限制会直接受到 Swap 的影响,因为 Kubernetes 的资源管理模型默认基于物理内存(RAM),而 Swap 的引入会打破这一假设。以下是具体影响和机制分析:
1. requests
和 limits
的本质
-
requests
:- 调度器(kube-scheduler)根据
requests
判断节点是否有足够的物理内存可供分配。 - 例如:
requests: memory: 1Gi
表示调度器会选择一个至少有 1Gi 物理内存可用的节点。
- 调度器(kube-scheduler)根据
-
limits
:- 通过 Linux Cgroups 限制容器实际使用的物理内存(默认不限制 Swap)。
- 例如:
limits: memory: 2Gi
表示容器最多占用 2Gi 物理内存,超限时会被 OOM Killer 终止。
2. Swap 如何破坏 requests
和 limits
的语义?
(1) 对 requests
的影响
-
问题:
调度器认为节点有Allocatable Memory = 物理内存 - kube-reserved - system-reserved
,但开启 Swap 后:- 节点可能过度承诺(Overcommit)资源(即调度器分配的总
requests
超过物理内存)。 - 实际运行时,依赖 Swap 的 Pod 性能会因磁盘 I/O 严重下降,但调度器无法预判。
- 节点可能过度承诺(Overcommit)资源(即调度器分配的总
-
示例:
- 节点物理内存:4Gi,Swap:2Gi。
- 两个 Pod 的
requests.memory: 3Gi
可能被调度到该节点(因调度器只检查物理内存)。 - 运行时,两个 Pod 争抢物理内存,触发 Swap,导致性能暴跌。
(2) 对 limits
的影响
-
问题:
Cgroups 的memory.limit_in_bytes
默认仅限制物理内存,不限制 Swap 使用。- 容器可能通过 Swap 绕过内存限制,导致:
- 一个 Pod 占用大量 Swap,挤占其他 Pod 的磁盘 I/O 带宽。
- 节点整体性能下降(尽管
kubectl top pod
显示内存未超限)。
- 容器可能通过 Swap 绕过内存限制,导致:
-
示例:
- 容器设置
limits.memory: 1Gi
,但通过 Swap 实际占用 1.5Gi(物理内存 + Swap)。 - 其他 Pod 因磁盘 I/O 被抢占而延迟飙升。
- 容器设置
3. Kubernetes 的应对机制
(1) 默认行为(禁用 Swap)
- 调度器:严格基于物理内存判断
requests
。 - kubelet:强制
limits
限制物理内存,超限时触发 OOM Killer。
(2) 启用 Swap 的实验性支持(Kubernetes 1.22+)
- 需显式配置
featureGates: NodeSwap: true
,并设置--fail-swap-on=false
。 - 行为变化:
limits
会包含 Swap 使用量(需配合memory.swap.max
Cgroups v2 参数)。- 但仍不推荐生产环境使用,原因:
- 调度器仍无法感知 Swap,
requests
的语义被破坏。 - 性能波动难以控制。
- 调度器仍无法感知 Swap,
4. 用户需要做什么?
(1) 确保节点禁用 Swap
# 检查 Swap
free -h # 确认 Swap 行全为 0
sudo swapoff -a # 临时关闭
sudo sed -i '/swap/s/^/#/' /etc/fstab # 永久关闭
(2) 合理设置 requests
和 limits
requests
:- 应接近容器的常态内存需求(调度依据)。
limits
:- 设置硬性上限(略高于
requests
以容忍峰值)。 - 示例:
resources: requests: memory: "1Gi" limits: memory: "1.5Gi"
- 设置硬性上限(略高于
(3) 监控与调优
- 使用
kubectl top pod/node
监控实际内存使用。 - 若需避免 OOM,可调整容器内存需求或扩容节点。
总结:Swap 对资源请求/限制的影响
场景 | 禁用 Swap(默认) | 启用 Swap |
---|---|---|
requests 调度依据 |
严格依赖物理内存 | 物理内存 + Swap,调度器无法感知 |
limits 限制范围 |
仅限制物理内存 | 可能绕过限制(依赖 Cgroups 配置) |
性能表现 | 稳定,OOM 可预测 | 不可控的 Swap I/O 延迟 |
推荐场景 | 生产环境(K8s 设计初衷) | 仅开发测试(非关键负载) |
结论:
- 务必禁用 Swap 以保障
requests
和limits
的语义准确性。 - 若节点内存不足,应通过垂直扩容(增大节点内存)或水平扩容(增加节点数)解决,而非依赖 Swap。