4. 内存资源配额详解:内存单位(Mi/Gi)、OOM Killer机制、内存请求与限制的配置策略

内存是云原生工作负载中最敏感的资源之一。与 CPU 不同,内存不可压缩——一旦容器超出限制,系统无法像 CPU 那样通过节流来缓解,只能触发 OOM Killer 终止进程。本章深入解析 Kubernetes 内存资源配额的底层机制与最佳配置策略。

4.1 内存单位:Mi 与 Gi 的二进制差异

Kubernetes 使用两种内存单位体系,理解其换算关系是避免配置偏差的第一步。

单位 全称 换算关系 典型场景
Mi Mebibyte(二进制兆字节) 1 Mi = 2²⁰ = 1,048,576 Bytes 容器内存 requests/limits
Gi Gibibyte(二进制吉字节) 1 Gi = 2³⁰ = 1,073,741,824 Bytes 节点容量、大内存应用
M Megabyte(十进制兆字节) 1 M = 10⁶ = 1,000,000 Bytes 不推荐在 K8s 中使用
G Gigabyte(十进制吉字节) 1 G = 10⁹ = 1,000,000,000 Bytes 不推荐在 K8s 中使用
⚠️ 常见陷阱: 使用十进制单位(M/G)可能导致实际分配内存比预期少约 7%。例如,配置 memory: 1G 实际只有 953 Mi,而 memory: 1Gi 才是真正的 1024 Mi。生产环境务必统一使用 Mi/Gi。

4.2 OOM Killer 机制:从 cgroup 到内核的终结链

当容器内存使用超过 limits 或节点整体内存不足时,Linux 内核的 OOM Killer 会介入。Kubernetes 环境下,OOM Killer 的触发路径如下:

OOM Killer 触发路径 容器内存超限 cgroup memory.limit_in_bytes 触发 OOM 内核 OOM Killer 计算 oom_score 选择 victim 进程 Pod 被终止 (Exit Code 137) 💡 oom_score 受以下因素影响:进程内存占用(越大分越高)、 oom_score_adj(K8s 自动设置,Guaranteed QoS 类为 -998,BestEffort 为 1000)
🔍 关键指标: 当 Pod 被 OOM Killer 终止时,kubectl describe pod 的 Last State 字段会显示 Reason: OOMKilled,退出码为 137(SIGKILL)。这是诊断内存超限的第一线索。

4.3 内存请求与限制的配置策略

4.3.1 核心配置模型

每个容器可以设置 requests.memory 和 limits.memory,两者共同决定调度决策与运行时行为。

apiVersion: v1
kind: Pod
metadata:
  name: memory-demo
spec:
  containers:
  - name: app
    image: nginx:latest
    resources:
      requests:
        memory: "256Mi"      # 调度保证值
      limits:
        memory: "512Mi"      # 硬上限,不可突破

4.3.2 三种 QoS 类与内存行为

QoS 类 配置条件 内存行为 OOM 优先级
Guaranteed requests == limits(所有容器) 严格限制,超出即 OOM 最低(oom_score_adj = -998)
Burstable requests < limits(至少一个容器) 可突发使用至 limits 中等(oom_score_adj 范围 -997 ~ 1000)
BestEffort 未设置 requests 和 limits 无限制,节点压力时最先被杀死 最高(oom_score_adj = 1000)
💡 最佳实践: 生产环境核心服务应使用 Guaranteed QoS 类,确保内存资源确定性。批处理或低优先级任务可使用 Burstable 提高资源利用率。避免使用 BestEffort,除非是临时调试 Pod。

4.3.3 配置策略矩阵

根据应用类型选择不同的内存配置策略:

  • Java 应用: 设置 limits = requests + 25% 堆外内存(Metaspace、线程栈、Direct Buffer)。JVM 参数 -Xmx 应设置为 limits 的 70%~80%。
  • Go 应用: 内存占用相对稳定,建议 requests = limits,避免 GC 抖动导致 OOM。
  • Node.js 应用: 设置 --max-old-space-size 为 limits 的 80%,预留 20% 给 V8 内部结构。
  • 缓存类应用(Redis/Memcached): 设置 requests = limits,并配置 maxmemory 为 limits 的 90%。

4.4 内存资源配额的成本分摊模型

在成本优化视角下,内存配额直接影响集群的 资源利用率 和 成本分摊。以下是一个典型的多租户成本分摊模型:

内存成本分摊模型 集群总内存成本(节点费用) 已分配内存(requests) 未分配内存(Buffer/空闲) 按 requests 比例分摊 按实际使用量分摊 💡 推荐策略:内部成本核算按 requests 分摊,外部计费按实际使用 + 预留溢价

4.5 常见问题与排查手段

问题现象 可能原因 排查命令 解决方案
Pod 频繁重启,Exit Code 137 内存 limits 设置过低 kubectl logs --previous 增大 limits 或优化应用内存
节点内存压力,部分 Pod 被驱逐 节点总 requests 超过容量 kubectl describe node 调整 requests 或扩缩节点
Java 应用堆外内存 OOM 未预留堆外内存空间 jcmd <pid> VM.native_memory 设置 limits = -Xmx * 1.25
内存利用率低但成本高 requests 设置过大 kubectl top pod 基于历史数据下调 requests
📊 性能调优黄金法则: 内存 requests 应基于 P99 峰值使用量 设置,limits 应基于 P99.9 峰值 + 安全余量 设置。使用 VPA(Vertical Pod Autoscaler)的推荐模式自动生成初始值,再根据生产数据微调。