4. 内存资源配额实战:内存 Requests/Limits 配置策略,OOM Killer 机制,内存压力与 Swap 管理

内存是 Kubernetes 集群中最敏感的稀缺资源之一。与 CPU 不同,内存不可压缩:一旦 Pod 超出限制,系统无法像 CPU 节流那样平滑降频,而是直接触发 OOM Killer 终止进程。本章从 Requests/Limits 配置策略出发,深入 OOM Killer 工作机制,并分析 Swap 对内存隔离的影响,帮助你在生产环境中建立稳健的内存资源管理体系。

4.1 内存 Requests 与 Limits 配置策略

Kubernetes 通过 requests.memory 和 limits.memory 控制 Pod 的内存行为。Requests 用于调度决策,Limits 用于运行时约束。两者配置不当会导致资源浪费、调度失败或频繁 OOM。

4.1.1 核心配置模型

参数 作用域 调度影响 运行时行为
requests.memory Pod 级别 节点必须满足该值才能调度 cgroup memory.soft_limit_in_bytes,尽力保障
limits.memory Pod 级别 不影响调度 cgroup memory.limit_in_bytes,硬限制,超限即 OOM
最佳实践:生产环境建议 requests.memory 等于 limits.memory,即 Guaranteed QoS 类。这能避免 Burstable Pod 在节点内存紧张时被优先驱逐,同时让 cgroup 硬限制精确保护节点稳定性。

4.1.2 配置策略对比

策略 Requests Limits QoS 类 适用场景
严格保障 等于 Limits 等于 Requests Guaranteed 数据库、有状态服务、延迟敏感应用
弹性超卖 小于 Limits 大于 Requests Burstable 批处理、离线任务、可降级服务
无限制 未设置 未设置 BestEffort 仅测试环境,生产禁止
避坑:不要将 limits.memory 设置得远大于 requests.memory。当节点内存不足时,Burstable Pod 会先被驱逐,且 OOM 分数更高。如果应用存在内存泄漏,过大的 Limits 只会延迟问题暴露,最终导致节点级 OOM。

4.1.3 配置示例

apiVersion: v1
kind: Pod
metadata:
  name: memory-demo
spec:
  containers:
  - name: app
    image: nginx:alpine
    resources:
      requests:
        memory: "256Mi"
      limits:
        memory: "512Mi"
    env:
    - name: GOMEMLIMIT
      value: "480MiB"   # 为 Go 应用预留 32MiB 余量
关键指标:建议为应用运行时(如 JVM、Go runtime)预留 10%-15% 的内存余量,避免 cgroup 硬限制与 GC 触发时机冲突导致频繁 OOM。

4.2 OOM Killer 机制与调优

当 Pod 内存使用超过 limits.memory 或节点整体内存不足时,Linux 内核 OOM Killer 介入。Kubernetes 通过 cgroup 和 oom_score_adj 控制 OOM 优先级,但运维人员仍需理解其触发链路与调优手段。

4.2.1 OOM Killer 触发流程

  1. 内存分配失败:进程通过 malloc() 或 mmap() 申请内存,内核发现物理内存 + Swap 不足。
  2. 内核唤醒 OOM Killer:遍历所有进程,根据 oom_score 选择“最坏”进程。
  3. 计算 oom_score:基于进程内存占用、CPU 时间、运行时长、oom_score_adj 等。
  4. 发送 SIGKILL:终止目标进程,释放内存。
  5. Kubelet 响应:检测到 Pod 容器退出,根据重启策略决定是否重建。
OOM Killer 触发与响应流程 内存分配失败 内核 OOM Killer 计算 oom_score 发送 SIGKILL Kubelet 检测退出 Pod 重建决策 说明:Kubelet 通过 cgroup 感知容器 OOM 事件,并根据 Pod 的 restartPolicy 决定是否重建。 如果 Pod 属于 StatefulSet 或 Deployment,控制器会确保副本数恢复。

4.2.2 oom_score_adj 调优

Kubernetes 自动为不同 QoS 类设置 oom_score_adj,但你可以通过 Pod 注解或 Admission Controller 进一步调整。

QoS 类 默认 oom_score_adj 含义
Guaranteed -998 几乎不会被 OOM Killer 选中
Burstable min(max(2, 1000 - (1000 * memory_request_bytes) / machine_memory_bytes), 999) 根据内存请求比例动态调整
BestEffort 1000 最容易被 OOM Killer 选中
调优建议:对于关键基础设施组件(如 CoreDNS、kube-proxy),可通过 spec.containers[].securityContext.oomScoreAdj 手动设置更低的 oom_score_adj,确保它们在节点内存紧张时存活。

4.3 内存压力与 Swap 管理

Kubernetes 官方要求节点关闭 Swap,因为 Swap 会破坏内存隔离性,导致 Pod 内存使用统计失真,并可能引发性能抖动。但在某些边缘场景(如裸金属、大数据预处理),合理使用 Swap 可以提升资源利用率。

4.3.1 Swap 对 Kubernetes 的影响

影响维度 具体问题
内存隔离失效 Pod 的 cgroup 限制仅控制物理内存,Swap 可绕过限制,导致节点内存超卖失控
OOM 判断偏差 Kubelet 基于 cgroup memory.usage_in_bytes 判断,但该值不包含 Swap,导致实际内存压力被低估
性能抖动 Swap 触发时,磁盘 I/O 延迟可达毫秒级,对延迟敏感应用造成不可预测的响应时间
驱逐决策错误 节点内存压力驱逐 Pod 时,Swap 可能掩盖真实压力,导致驱逐滞后

4.3.2 内存压力检测与驱逐策略

Kubelet 通过 --eviction-hard 和 --eviction-soft 参数设置内存压力阈值。当节点内存使用超过阈值时,Kubelet 开始驱逐 Pod。

# kubelet 启动参数示例
--eviction-hard=memory.available<100Mi
--eviction-soft=memory.available<200Mi
--eviction-soft-grace-period=memory.available=1m30s
--eviction-minimum-reclaim=memory.available=0Mi
内存压力驱逐决策流程 节点内存监控 阈值判断 驱逐候选排序 Pod 驱逐 驱逐候选排序规则(优先级从高到低): 1. BestEffort Pod(oom_score_adj=1000) 2. Burstable Pod 中内存使用超出 requests 比例最高的 3. Guaranteed Pod(仅当节点内存极度紧张时,按优先级排序) 4. 相同 QoS 下,优先驱逐内存使用量最大的 Pod

4.3.3 Swap 管理最佳实践

  • 生产集群:严格关闭 Swap。在节点初始化时通过 swapoff -a 禁用,并在 /etc/fstab 中注释 Swap 条目。
  • 边缘/裸金属场景:如果必须启用 Swap,建议设置 vm.swappiness=1,仅作为极端情况下的最后保障。
  • Kubelet 配置:从 Kubernetes 1.28 开始,可以通过 --feature-gates=NodeSwap=true 启用有限 Swap 支持,但仅限 Burstable 和 BestEffort Pod。
  • 监控指标:关注 node_memory_MemAvailable_bytes、container_memory_working_set_bytes、container_memory_failures_total 三个指标,及时发现内存压力。
实战检查命令:
kubectl top pod -n <namespace> 查看 Pod 实时内存使用。
kubectl describe node <node-name> 查看节点内存压力状态。
cat /sys/fs/cgroup/memory/kubepods/besteffort/memory.limit_in_bytes 查看 cgroup 硬限制。

4.4 本章小结