Kernel dirty
“**kernel dirty 配置**” 通常指的是 Linux 内核中与 **页缓存(page cache)写回(writeback)机制** 相关的一系列参数,常见于 **/proc/sys/vm/** 目录下,比如:
``` /proc/sys/vm/dirty_ratio /proc/sys/vm/dirty_background_ratio /proc/sys/vm/dirty_bytes /proc/sys/vm/dirty_background_bytes /proc/sys/vm/dirty_writeback_centisecs /proc/sys/vm/dirty_expire_centisecs ```
这些参数控制了内核何时、以及如何将脏页(dirty pages,即被修改但尚未写回磁盘的数据)写回到磁盘。 下面详细介绍它们的含义和使用场景 👇
---
- 🧠 基础概念
当进程写文件时,Linux 不会立刻把数据写到磁盘,而是先写到内存页缓存(page cache)里。 这些被修改但未同步到磁盘的页称为 **dirty pages**。
内核会在一定条件下触发“回写”(writeback)操作,把 dirty pages 写到磁盘中。
如果 dirty pages 太多,会影响内存可用性、系统性能甚至 I/O 延迟; 而太少,则可能浪费磁盘 I/O 带宽。 所以内核通过以下参数平衡这两者。
---
- 🔧 核心参数说明
- 1. `/proc/sys/vm/dirty_ratio`
- **作用**:系统中 dirty 页占全部可用内存的最大比例(百分比)。
- **当 dirty 页超过这个比例时,触发进程自身同步写回**。
- **默认值**:通常是 20。
📘 举例:
``` vm.dirty_ratio = 20 ```
如果系统总内存 16GB,那么当 dirty 页超过 3.2GB 时,任何后续写操作都会被阻塞,直到部分脏页被写回磁盘。
---
- 2. `/proc/sys/vm/dirty_background_ratio`
- **作用**:dirty 页达到这个比例时,内核后台(flush 线程)会异步写回。
- **默认值**:通常是 10。
📘 举例:
``` vm.dirty_background_ratio = 10 ```
表示 dirty 页占总内存 10% 时,后台写回线程开始工作,但不会阻塞应用。
---
- 3. `/proc/sys/vm/dirty_bytes`
- 与 `dirty_ratio` 类似,但以 **绝对字节数** 控制阈值。
- **单位**:字节。
- 优先级高于 `dirty_ratio`。
- 建议在大内存服务器上使用,因为比例值可能太大或太小。
📘 举例:
``` vm.dirty_bytes = 268435456 # 256MB ```
表示 dirty 页超过 256MB 时触发同步写回。
---
- 4. `/proc/sys/vm/dirty_background_bytes`
- 与 `dirty_background_ratio` 类似,以字节数为单位。
- 表示 dirty 页超过该值时,后台开始异步写回。
📘 举例:
``` vm.dirty_background_bytes = 134217728 # 128MB ```
---
- 5. `/proc/sys/vm/dirty_writeback_centisecs`
- **作用**:后台写回线程周期性检查 dirty 页的时间间隔。
- **单位**:1/100 秒(centisecond)。
- **默认值**:500(即 5 秒)。
📘 举例:
``` vm.dirty_writeback_centisecs = 500 ```
表示每 5 秒检查一次 dirty 页并写回。
---
- 6. `/proc/sys/vm/dirty_expire_centisecs`
- **作用**:dirty 页在内存中存活的最大时间。
- 超过该时间后,即使未达阈值,也会被写回。
- **默认值**:3000(即 30 秒)。
📘 举例:
``` vm.dirty_expire_centisecs = 3000 ```
表示 dirty 页在 30 秒后会被写回。
---
- ⚙️ 关系示意图
```text 应用写文件
↓
数据写入 page cache
↓
dirty < background_ratio → 不写回 dirty ≥ background_ratio → 后台写回线程启动 dirty ≥ ratio → 应用被阻塞并强制写回
```
---
- 💡 调优建议
| 场景 | 调优建议 | | ----------------- | ----------------------------------------------------------------- | | 高写入频率、低延迟系统(如数据库) | 降低 `dirty_ratio` 与 `dirty_background_ratio`,如 10 和 5,减少突发写回造成的延迟。 | | 批量文件写入或大文件拷贝 | 提高 `dirty_ratio`(如 40),让系统积累更多写缓存,减少频繁 I/O。 | | SSD 系统 | 可以略微提高比例,因为写入延迟低。 | | HDD 系统 | 建议保守设置,避免一次性写入量太大造成 I/O 卡顿。 |
---
- 🔍 查看当前值
``` cat /proc/sys/vm/dirty_ratio cat /proc/sys/vm/dirty_background_ratio cat /proc/sys/vm/dirty_writeback_centisecs ```
---
- 🧩 临时与永久修改
- 临时修改(立即生效,重启后失效):
``` sysctl -w vm.dirty_ratio=15 ```
- 永久修改:
在 `/etc/sysctl.conf` 或 `/etc/sysctl.d/*.conf` 中加入:
``` vm.dirty_ratio=15 vm.dirty_background_ratio=5 ```
然后执行:
``` sysctl -p ```
---
- 🧠 实战案例
- 案例:数据库写延迟高
- 现象:**
- PostgreSQL 写入延迟周期性上升。
- iostat 显示磁盘突发写入。
- 原因:**
- dirty 页积累过多,触发同步写回(`dirty_ratio` 超限)。
- 解决:**
``` sysctl -w vm.dirty_ratio=10 sysctl -w vm.dirty_background_ratio=5 ```
结果:写入更平滑,系统延迟下降。
---
是否希望我帮你结合 “高 I/O wait 问题(例如 EC2+EFS 场景)” 一起讲讲这些 dirty 参数如何优化?那样我可以给你一个专门的实战优化方案。
非常好 👍 那我们接着来讲 **结合 EC2 + EFS 高 I/O wait 的 dirty 参数优化实战方案**。 这类问题你之前提到过(EC2 访问 EFS I/O wait 高、系统卡顿、load average 高等),其实和 **内核 dirty 页缓存机制** 的行为密切相关。
---
- 🧩 一、问题背景
EFS(Amazon Elastic File System) 是基于网络的 NFS 存储。 它的写入路径是这样的:
``` 应用 → 内存页缓存(dirty page) → 内核写回 → 网络(NFS 客户端) → EFS 服务端 ```
所以,**EFS 写延迟** 受三方面影响:
1. dirty 页写回时,**NFS I/O 延迟高**; 2. 写回过程阻塞进程,**I/O wait 上升**; 3. dirty 阈值太大导致突发写回,**系统抖动明显**。
---
- 🧠 二、内核默认行为(不适合 EFS)
在标准 Linux(尤其是 EC2 默认配置)中:
```bash vm.dirty_ratio = 20 vm.dirty_background_ratio = 10 ```
假设实例有 8GB 内存:
- dirty 页最多可以积累 1.6GB;
- 当超过 1.6GB 时,所有写进程会被阻塞;
- 然后内核突然把 1.6GB 数据通过 NFS 写入 EFS → 网络阻塞 → I/O wait 飙升。
📉 典型症状:
- `top` 显示 iowait 占用高;
- `load average` 周期性升高;
- `iostat` 中 `await`(等待时间)上升;
- EFS CloudWatch 中看到 **burst write spikes**。
---
- ⚙️ 三、优化思路
目标: 让 dirty 页积累更少、更早写回,从而使写入更平滑、I/O 更稳定。
推荐参数调整如下:
| 参数 | 默认值 | 建议值(EFS) | 说明 | | ------------------------------ | ---- | -------- | --------------- | | `vm.dirty_background_ratio` | 10 | **3** | 后台线程更早启动写回 | | `vm.dirty_ratio` | 20 | **6** | 降低写缓存积累,减少突发写入 | | `vm.dirty_expire_centisecs` | 3000 | **1500** | 15秒后强制写回旧数据 | | `vm.dirty_writeback_centisecs` | 500 | **100** | 每1秒检查一次 dirty 页 | | `vm.vfs_cache_pressure` | 100 | **50** | 减少元数据缓存回收频率(可选) |
设置命令:
```bash sysctl -w vm.dirty_background_ratio=3 sysctl -w vm.dirty_ratio=6 sysctl -w vm.dirty_expire_centisecs=1500 sysctl -w vm.dirty_writeback_centisecs=100 ```
或者永久写入 `/etc/sysctl.conf`:
```bash vm.dirty_background_ratio=3 vm.dirty_ratio=6 vm.dirty_expire_centisecs=1500 vm.dirty_writeback_centisecs=100 ```
---
- 📊 四、验证效果
1. 运行:
```bash vmstat 1 ```
看 `wa`(I/O wait)列是否下降。
2. 查看:
```bash iostat -xz 1 ```
观察:
* `await`(等待时间)应更稳定; * `util`(设备利用率)峰值应降低。
3. 如果有 CloudWatch:
* EFS “DataWriteIOBytes” 图表应更平滑; * EC2 “DiskWriteOps” 波动应减小。
---
- 🧠 五、补充优化(EFS 特有)
- 1️⃣ 使用 NFS mount 参数优化
在 `/etc/fstab` 或挂载命令中添加:
``` nfsvers=4.1,_netdev,noresvport,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2 ```
说明:
- `rsize`/`wsize`:增大块传输尺寸;
- `hard`:启用重试;
- `timeo=600`:超时调整;
- `noresvport`:避免固定端口带来的冲突。
---
- 2️⃣ 检查写缓冲模式
确认挂载选项中没有 `sync`,要使用异步写:
``` mount | grep efs ```
如看到:
``` nfs4 rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,... ```
说明是异步写(✅)。
---
- 3️⃣ 对比测试
可以在调整前后使用:
```bash dd if=/dev/zero of=/mnt/efs/testfile bs=1M count=1024 conv=fdatasync ```
比较写入时间与 iowait。
---
- ✅ 六、结论
- **默认 dirty 参数不适合 EFS 等高延迟网络文件系统**;
- **调低比例和间隔** 可显著改善 I/O wait;
- **EFS + NFS mount 优化** 能进一步提升性能;
- 调优后系统写操作更平滑、负载更稳定。
---
如果你愿意,我可以帮你写一个自动检测+优化 dirty 参数的脚本, 它能根据内存大小和挂载类型(EFS/NFS/local)自动计算合适参数。 是否帮你生成一个这样的 Bash 工具?
- here
“什么样的 dirty 参数配置更适合 EFS 这类高延迟网络文件系统”**。 这正是很多在 AWS 上跑容器、Web 服务或 CI/CD 工具(Jenkins、GitLab Runner 等)的人经常忽略的性能关键点。
---
- 💡 一、为什么默认参数不适合 EFS?
Linux 默认 dirty 策略是为 **本地磁盘(SSD/HDD)** 设计的,假设写入延迟低、带宽高。 但 EFS 是 **NFS over network(网络文件系统)**,意味着:
- 写延迟高(>5ms 常见);
- 吞吐受限于网络;
- 写回触发时,内核可能要等待远程 ACK。
所以默认策略下:
- dirty 页积累较多(默认 10%~20% 内存);
- 一旦超过 dirty_ratio,内核会一次性写大量数据;
- 导致所有写入线程被阻塞(I/O wait 飙升);
- 系统负载周期性抖动。
---
- ✅ 二、EFS 适配原则(经验法则)
EFS 是 **高延迟 + 异步写** 场景,目标是:
> “让系统频繁地、少量地、平滑地写回,而不是一次性大量写回。”
因此参数调优目标是:
- **降低 dirty 页累积量**;
- **加快后台写回频率**;
- **减少一次性突发写入量**;
- **保证内核不阻塞应用写入。**
---
- 🧩 三、推荐参数配置(EFS 最佳实践)
| 参数 | 默认 | 推荐值(EFS) | 说明 | | ------------------------------ | ---- | -------------- | --------------------- | | `vm.dirty_background_ratio` | 10 | **2–3** | 让后台写回更早启动 | | `vm.dirty_ratio` | 20 | **4–6** | 避免突发同步写回 | | `vm.dirty_expire_centisecs` | 3000 | **1000–1500** | 脏页在 10–15 秒内强制写回 | | `vm.dirty_writeback_centisecs` | 500 | **100** | 每 1 秒周期性触发写回 | | `vm.dirty_background_bytes` | - | 可选,如 **64MB** | 固定后台写回阈值(大内存机器推荐) | | `vm.dirty_bytes` | - | 可选,如 **128MB** | 固定同步写回阈值 | | `vm.vfs_cache_pressure` | 100 | **50** | 保留更多文件系统缓存(NFS 元数据有用) |
---
- 🔧 四、示例配置
```bash cat <<EOF | sudo tee /etc/sysctl.d/99-efs-tuning.conf vm.dirty_background_ratio=3 vm.dirty_ratio=6 vm.dirty_expire_centisecs=1500 vm.dirty_writeback_centisecs=100 vm.vfs_cache_pressure=50 EOF
- 应用新配置
sudo sysctl -p /etc/sysctl.d/99-efs-tuning.conf ```
---
- 📊 五、为什么这些值合适
| 参数 | 原理解释 | | ------------------------------- | ---------------------------------- | | `dirty_background_ratio=3` | 当 dirty 页达到 3% 内存时就开始后台写回,避免积压。 | | `dirty_ratio=6` | 写缓存不会超过 6%,即使写入速度快、网络延迟高,也不至于堆积太多。 | | `dirty_writeback_centisecs=100` | 每 1 秒检查一次,让系统能持续写,而非积累后集中写。 | | `dirty_expire_centisecs=1500` | 防止老脏页滞留太久,EFS 这种延迟较高的系统中可以避免写延迟突发。 | | `vfs_cache_pressure=50` | 减少内核频繁回收目录和 inode 缓存,适合频繁访问的小文件场景。 |
---
- 🧠 六、内核行为对比(默认 vs 调优)
| 指标 | 默认值 | 调优后(EFS) | | ------------ | -------- | -------- | | dirty 页积累 | 高(可达几GB) | 低(几十MB) | | 写回触发频率 | 低(5秒一次) | 高(1秒一次) | | 每次写入量 | 大 | 小 | | 应用写入延迟 | 周期性卡顿 | 平滑稳定 | | 系统 iowait | 高峰周期性上升 | 平稳较低 | | Load Average | 周期性波动 | 相对平稳 |
---
- 🧪 七、验证方法
- 1️⃣ 实时监控
```bash watch -n1 "cat /proc/meminfo | grep -E 'Dirty|Writeback'" ```
调优后,你应该看到 `Dirty` 保持在几MB以内(非常稳定)。
- 2️⃣ I/O 观察
```bash iostat -xz 1 ```
看 `await`、`svctm`、`util`,调优后波动应小。
- 3️⃣ CloudWatch 验证
查看:
- EC2 → CPUUtilization(iowait 应下降)
- EFS → DataWriteIOBytes(更均匀)
---
- 💬 八、进阶建议
- 1. 大内存机器(>32GB)
使用字节型参数更合适:
```bash vm.dirty_background_bytes=67108864 # 64MB vm.dirty_bytes=134217728 # 128MB ```
- 2. 对于数据库或日志型写入
可进一步降低 dirty_ratio,比如:
```bash vm.dirty_background_ratio=2 vm.dirty_ratio=4 ```
- 3. 只读 EFS 场景
可不调 dirty 参数,仅关注缓存压力:
```bash vm.vfs_cache_pressure=50 ```
---
- 🧰 九、实战建议总结
| 目标 | 策略 | | -------------- | --------------------------------------- | | 平滑写入、减少 iowait | 减小 dirty_ratio 和 dirty_background_ratio | | 避免突发写回 | 提高写回频率(dirty_writeback_centisecs 降低) | | 降低旧页滞留 | 降低 dirty_expire_centisecs | | 大内存系统更精准 | 使用 *_bytes 参数替代 *_ratio | | 减少目录/元数据抖动 | 降低 vfs_cache_pressure |
---
是否希望我帮你写一个小脚本,它会自动检测系统类型(EBS 本地盘 / EFS / NFS) 然后自动应用最优 dirty 参数配置? 例如一键运行 `optimize-dirty.sh` 即完成优化(支持 rollback)。