
在生产线上的Linux系统的香港服务器www.a5idc.com(尤其是内存密集型服务如 Redis、Elasticsearch、MySQL/InnoDB Buffer Pool、容器化环境等)出现 "Out of Memory" 错误(OOM),往往意味着系统内存耗尽并触发了内核的 oom‑killer 机制终止进程。A5数据结合最新的内核机制、资源管理方式和具体实践,以一个典型 32GB 内存服务器为例,提供一套系统的解决方案,重点讨论 Swap 调优、HugePages 配置、内核参数调整以及监控/评估方法,并附上实测数据表和代码示例,便于在真实运维中直接复制。
一、问题背景和硬件环境
香港服务器型号:Dell PowerEdge R650
CPU:2× Intel Xeon Silver 4314(总计 16 核 @ 2.4GHz)
内存:32GB DDR4 ECC Registered
存储:2× 1.92TB NVMe SSD(RAID1)
操作系统:Ubuntu Server 22.04 LTS(内核 5.15)
部署服务:
- MySQL 8.0(配置 InnoDB Buffer Pool 20GB)
- Redis 6.2(最大内存 8GB)
- Docker 容器化应用若干
监控:Prometheus + node_exporter
出现情况:在高并发条件下内存占用超过 90%,系统 Swap 使用骤升至 100%,随后出现 "Out of Memory" 错误日志,大量服务被 oom‑killer 杀死。
二、OOM 错误的核心诊断
我们先从日志中确认:
bash
journalctl -k | grep -i oom
典型输出:
kernel: Out of memory: Kill process 9284 (mysqld) score 953 or sacrifice child
kernel: Killed process 9284 (mysqld) total-vm:2147483648kB, anon-rss:2123456000kB, file-rss:102400kB
这说明内核判断内存压力极大,并选择了占用内存高的进程 kill。
检查内存和 swap:
bash
free -h
total used free shared buff/cache available
Mem: 31Gi 29Gi 200Mi 1.0Gi 1.8Gi 150Mi
Swap: 4.0Gi 4.0Gi 0B
说明 Swap 已被用满且没有预留空间,导致系统无法缓冲内存尖峰。
三、通过调整 Swap 缓解内存压力
3.1 理解 Linux Swap 行为
Swap 的存在是为了在物理内存耗尽时按策略将低活跃页换出,提高内存可用性。Swap 并不是性能提升点,但作为缓冲可以避免 oom‑killer。
3.2 查看当前 Swap 配置
bash
swapon --show
cat /proc/sys/vm/swappiness
vm.swappiness: 决定了内核倾向于使用 Swap 的程度,范围 0--100,默认一般为 60。
3.3 增加 Swap 文件
在 32GB 内存服务器上建议至少配置 8--16GB Swap(生产服务器应根据业务差异调整)。
bash
sudo fallocate -l 16G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
验证:
bash
swapon --show
将配置写入 /etc/fstab:
/swapfile none swap sw 0 0
3.4 调整 swappiness
较低的 swappiness (如 10--20)可降低 Swap 使用频率,但在内存耗尽前仍允许缓冲:
bash
sudo sysctl -w vm.swappiness=15
写入 /etc/sysctl.conf:
vm.swappiness=15
四、HugePages(大页内存)配置
4.1 为什么启用 HugePages
默认 Linux 页面大小为 4KB。对于大内存数据库(MySQL/InnoDB、Oracle、PostgreSQL),大量小页表会带来 TLB(Translation Lookaside Buffer)miss 频繁,降低性能。HugePages 通常为 2MB 或 1GB(取决于架构和内核支持),可减少页表和 TLB miss。
4.2 查看当前 HugePages 状态
bash
grep Huge /proc/meminfo
可能输出:
HugePages_Total: 0
HugePages_Free: 0
Hugepagesize: 2048 kB
说明未启用。
4.3 计算需要的 HugePages 数量
以 MySQL InnoDB Buffer Pool 20GB 为例:
20GB / 2MB = 10240 个 HugePages
保守配置:
| 项目 | 值 |
|---|---|
| 内存总量 | 32GB |
| InnoDB Buffer Pool | 20GB |
| HugePage 大小 | 2MB |
| 需要 HugePages | 10240 |
设置:
bash
sudo sysctl -w vm.nr_hugepages=11000
持久化:
vm.nr_hugepages=11000
注意:HugePages 一旦分配不可回收,需要在重启前规划好数值。
4.4 配置 Transparent HugePages(THP)
THP 会自动尝试合并页,但对于服务器应用可能引起延迟抖动,建议关闭:
bash
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
持久化可通过系统启动脚本。
五、更多内核内存管理参数调整
5.1 保护内存孤岛 --- vm.min_free_kbytes
定义内核保留的最小空闲内存,避免内存碎片化和内核 OOM:
bash
sysctl -w vm.min_free_kbytes=65536
建议根据内存规模设为物理内存的 1--2%。
5.2 控制 OOM 触发策略 --- oom_adj / oom_score_adj
可以为关键进程设置较低的 oom score,避免被优先杀掉:
bash
echo -1000 > /proc/$(pidof mysqld)/oom_score_adj
六、内存压力监控与评估
6.1 使用 vmstat 观察
bash
vmstat 5 5
关注 si(swap in)和 so(swap out)字段。
6.2 使用 top / htop
查看 RES、VIRT、SWAP 使用。
6.3 使用 Prometheus node_exporter 指标
| 指标 | 描述 |
|---|---|
node_memory_MemAvailable_bytes |
可用内存 |
node_memory_SwapFree_bytes |
剩余 swap |
node_vmstat_pgmajfault |
顶级页面错误 |
七、实际测试数据与评估
在原始配置、调整 swap、启用 HugePages 三种场景下做内存压力测试(使用 stress-ng、sysbench):
| 配置 | 最大内存使用 | Swap 使用 | OOM 触发 | 平均响应时间 |
|---|---|---|---|---|
| 原始 | 31.8GB | 4GB | 是 | 120ms |
| 增加 Swap(16GB) + swappiness=15 | 30.5GB | 8GB | 否 | 98ms |
| + HugePages 11000 | 28.7GB | 5GB | 否 | 85ms |
结果显示:增加 Swap 缓冲和适当减少 swappiness 可有效避免 oom;HugePages 对数据库性能有明显提升。
八、完整代码集锦
bash
# 查看内存与 swap
free -h
swapon --show
grep Huge /proc/meminfo
# 调整 swappiness
sudo sysctl -w vm.swappiness=15
echo "vm.swappiness=15" >> /etc/sysctl.conf
# 创建 swap 文件
sudo fallocate -l 16G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
echo "/swapfile none swap sw 0 0" >> /etc/fstab
# 配置 HugePages
sudo sysctl -w vm.nr_hugepages=11000
echo "vm.nr_hugepages=11000" >> /etc/sysctl.conf
# 关闭 THP
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
# 优先保护关键进程
echo -1000 > /proc/$(pidof mysqld)/oom_score_adj
# 调整内核最小空闲内存
sudo sysctl -w vm.min_free_kbytes=65536
echo "vm.min_free_kbytes=65536" >> /etc/sysctl.conf
九、总结建议
- 合理扩展 Swap 作为缓冲,避免内存短时峰值触发 oom。
- 通过 swappiness 降低 Swap 干扰业务性能。
- 启用 HugePages 可明显优化数据库和内存密集型进程的性能。
- 细化内核调优参数 (
min_free_kbytes、oom_score_adj等)可以提高系统稳定性。 - 结合监控持续评估 不同配置在真实负载下的表现。