4. VM内存管理参数(上):vm.swappiness、vm.dirty_ratio、vm.dirty_background_ratio
内存管理是Linux内核性能调优的核心领域之一。本章聚焦三个最常用且影响最直接的VM参数:vm.swappiness、vm.dirty_ratio 和 vm.dirty_background_ratio。它们分别控制着内存回收策略与脏页刷写行为,直接决定了系统在内存压力下的响应速度与I/O吞吐表现。
调优前提: 在调整任何VM参数前,建议先通过
free -h、vmstat 1、cat /proc/meminfo 等工具确认当前内存使用状态,避免盲目修改导致性能下降。
4.1 vm.swappiness:控制内存回收倾向
4.1.1 参数定义与作用
vm.swappiness 控制内核在回收内存时,倾向于回收匿名页(进程堆、栈、匿名映射)还是文件页(文件缓存、mmap映射)。取值范围为 0 ~ 200,默认值为 60。
- 值越小(接近0): 内核越倾向于回收文件缓存,尽量将匿名页保留在物理内存中。适合需要低延迟响应、避免swap抖动的应用(如数据库、实时服务)。
- 值越大(接近100或200): 内核更积极地回收匿名页,将不活跃的进程内存换出到swap空间,释放物理内存给文件缓存。适合文件缓存密集型任务(如大数据批处理、文件服务器)。
常见误区: 将
vm.swappiness = 0 并不意味着完全禁用swap,而是内核仅在内存极度紧张(内存耗尽)时才会使用swap。在Linux 5.8+内核中,0 的行为已调整为“除非内存耗尽,否则不触发swap”,但仍可能因OOM Killer导致进程被杀死。
4.1.2 配置示例与验证
# 临时生效(立即生效,重启丢失)
sysctl -w vm.swappiness=10
# 永久生效(写入配置文件)
echo "vm.swappiness = 10" >> /etc/sysctl.conf
# 或使用 sysctl 持久化
sysctl -w vm.swappiness=10 >> /etc/sysctl.d/99-custom.conf
# 验证当前值
sysctl vm.swappiness
cat /proc/sys/vm/swappiness
4.1.3 不同场景推荐值
| 应用场景 | 推荐值 | 理由 |
|---|---|---|
| MySQL / PostgreSQL 数据库 | 1 ~ 10 | 减少swap抖动,保障数据库进程内存常驻,降低查询延迟 |
| Redis / Memcached 缓存 | 0 ~ 1 | 缓存数据全部在内存中,swap会严重降低性能 |
| Web服务器(Nginx + PHP) | 10 ~ 30 | 平衡文件缓存与进程内存,避免频繁swap |
| 大数据批处理 / 文件服务器 | 60 ~ 100 | 优先保留文件缓存,提升I/O吞吐 |
| 桌面系统 / 通用服务器 | 60(默认) | 通用平衡策略,适合大多数场景 |
4.1.4 内核回收决策流程(SVG)
下图展示了内核在内存回收时,根据 vm.swappiness 值选择回收目标的核心决策路径:
4.2 vm.dirty_ratio 与 vm.dirty_background_ratio:脏页刷写控制
4.2.1 参数定义与协同机制
这两个参数共同控制着脏页(Dirty Pages)——即内存中被修改但尚未写入磁盘的页面——的刷写行为。它们以系统物理内存百分比为单位,决定了脏页积累的上限与刷写触发时机。
| 参数 | 默认值 | 触发条件 | 行为 |
|---|---|---|---|
vm.dirty_background_ratio |
10 | 脏页占内存比例达到此值 | 内核后台线程(pdflush/flusher)异步开始刷写脏页,不阻塞应用程序 |
vm.dirty_ratio |
20 | 脏页占内存比例达到此值 | 应用程序的写操作同步阻塞,直到脏页比例降至 dirty_background_ratio 以下 |
核心原则:
dirty_background_ratio 必须 小于 dirty_ratio。两者之间的差值构成了“缓冲区间”,在此区间内后台刷写线程有机会在应用程序被阻塞前完成脏页清理。
4.2.2 脏页刷写生命周期(SVG)
下图展示了脏页从产生到刷写的完整生命周期,以及两个参数在其中的控制位置:
4.2.3 配置示例与监控
# 查看当前值
sysctl vm.dirty_background_ratio vm.dirty_ratio
# 临时调整(适用于高写入负载场景)
sysctl -w vm.dirty_background_ratio=5
sysctl -w vm.dirty_ratio=15
# 永久配置
cat >> /etc/sysctl.d/99-dirty.conf << EOF
vm.dirty_background_ratio = 5
vm.dirty_ratio = 15
EOF
# 监控脏页实时状态
grep -E "Dirty|Writeback" /proc/meminfo
# 或使用 watch 持续观察
watch -n 1 'grep -E "Dirty|Writeback" /proc/meminfo'
4.2.4 不同负载场景推荐配置
| 负载类型 | dirty_background_ratio | dirty_ratio | 说明 |
|---|---|---|---|
| 数据库(MySQL/PostgreSQL) | 3 ~ 5 | 10 ~ 15 | 低延迟要求,减少写阻塞,脏页及时刷写 |
| 文件服务器 / NFS | 5 ~ 10 | 20 ~ 30 | 允许脏页适当累积,提升写入吞吐 |
| 日志写入 / 消息队列 | 10 ~ 15 | 30 ~ 40 | 顺序写入为主,可容忍较大脏页缓冲 |
| 虚拟机 / 容器宿主机 | 5 ~ 10 | 20 ~ 25 | 平衡多个虚拟机的I/O抖动 |
| 默认(通用) | 10 | 20 | 适合大多数桌面和服务器场景 |
调优警告: 不要将
dirty_ratio 设置得过高(如超过50%),否则在突发写入时可能导致大量脏页积压,一旦触发同步阻塞,所有写操作将长时间挂起,造成严重的I/O抖动甚至系统假死。对于内存极大的系统(如512GB+),建议使用 dirty_bytes 和 dirty_background_bytes(以字节为单位)替代百分比参数,以获得更精确的控制。
4.3 三个参数的协同调优策略
在实际生产环境中,vm.swappiness、vm.dirty_background_ratio 和 vm.dirty_ratio 需要组合考虑,而非孤立调整。以下是一个典型的协同调优流程:
- 确定业务负载类型: 是I/O密集型、内存密集型还是计算密集型?
- 调整 swappiness: 根据对匿名页的保留需求,设置合适的值(数据库类建议1~10)。
- 调整脏页参数: 根据写入频率和延迟敏感度,设置
dirty_background_ratio和dirty_ratio。 - 观察与验证: 使用
vmstat、iostat、/proc/meminfo监控脏页比例、swap使用量和I/O等待时间。 - 迭代微调: 每次只改一个参数,观察至少24小时,确认无负面效应后再进行下一步调整。
实战案例: 某MySQL数据库服务器(内存64GB)在高峰时段出现频繁的swap抖动和写延迟飙升。通过将
vm.swappiness 从60降至5,并将 vm.dirty_background_ratio 从10降至3、vm.dirty_ratio 从20降至10,swap使用量从8GB降至几乎为0,写延迟降低约40%。核心思路是:减少匿名页换出 + 及时刷写脏页。
4.4 本章小结
- vm.swappiness: 控制内存回收倾向,低值保留匿名页(适合数据库),高值保留文件缓存(适合文件服务器)。
- vm.dirty_background_ratio: 触发后台异步刷写的脏页比例阈值,默认10%。
- vm.dirty_ratio: 触发同步阻塞的脏页比例阈值,默认20%,必须大于
dirty_background_ratio。 - 协同原则: 根据业务负载类型,组合调整三个参数,在内存保留与I/O吞吐之间找到平衡点。