Kernel dirty

来自linuxsa wiki
Evan留言 | 贡献2025年10月9日 (四) 15:46的版本 (创建页面,内容为“ “**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 ``` 这些参数控制了内核何时、以及如何将脏页…”)
(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)
跳转到导航 跳转到搜索

“**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,即被修改但尚未写回磁盘的数据)写回到磁盘。 下面详细介绍它们的含义和使用场景 👇

---

    1. 🧠 基础概念

当进程写文件时,Linux 不会立刻把数据写到磁盘,而是先写到内存页缓存(page cache)里。 这些被修改但未同步到磁盘的页称为 **dirty pages**。

内核会在一定条件下触发“回写”(writeback)操作,把 dirty pages 写到磁盘中。

如果 dirty pages 太多,会影响内存可用性、系统性能甚至 I/O 延迟; 而太少,则可能浪费磁盘 I/O 带宽。 所以内核通过以下参数平衡这两者。

---

    1. 🔧 核心参数说明
      1. 1. `/proc/sys/vm/dirty_ratio`
  • **作用**:系统中 dirty 页占全部可用内存的最大比例(百分比)。
  • **当 dirty 页超过这个比例时,触发进程自身同步写回**。
  • **默认值**:通常是 20。

📘 举例:

``` vm.dirty_ratio = 20 ```

如果系统总内存 16GB,那么当 dirty 页超过 3.2GB 时,任何后续写操作都会被阻塞,直到部分脏页被写回磁盘。

---

      1. 2. `/proc/sys/vm/dirty_background_ratio`
  • **作用**:dirty 页达到这个比例时,内核后台(flush 线程)会异步写回。
  • **默认值**:通常是 10。

📘 举例:

``` vm.dirty_background_ratio = 10 ```

表示 dirty 页占总内存 10% 时,后台写回线程开始工作,但不会阻塞应用。

---

      1. 3. `/proc/sys/vm/dirty_bytes`
  • 与 `dirty_ratio` 类似,但以 **绝对字节数** 控制阈值。
  • **单位**:字节。
  • 优先级高于 `dirty_ratio`。
  • 建议在大内存服务器上使用,因为比例值可能太大或太小。

📘 举例:

``` vm.dirty_bytes = 268435456 # 256MB ```

表示 dirty 页超过 256MB 时触发同步写回。

---

      1. 4. `/proc/sys/vm/dirty_background_bytes`
  • 与 `dirty_background_ratio` 类似,以字节数为单位。
  • 表示 dirty 页超过该值时,后台开始异步写回。

📘 举例:

``` vm.dirty_background_bytes = 134217728 # 128MB ```

---

      1. 5. `/proc/sys/vm/dirty_writeback_centisecs`
  • **作用**:后台写回线程周期性检查 dirty 页的时间间隔。
  • **单位**:1/100 秒(centisecond)。
  • **默认值**:500(即 5 秒)。

📘 举例:

``` vm.dirty_writeback_centisecs = 500 ```

表示每 5 秒检查一次 dirty 页并写回。

---

      1. 6. `/proc/sys/vm/dirty_expire_centisecs`
  • **作用**:dirty 页在内存中存活的最大时间。
  • 超过该时间后,即使未达阈值,也会被写回。
  • **默认值**:3000(即 30 秒)。

📘 举例:

``` vm.dirty_expire_centisecs = 3000 ```

表示 dirty 页在 30 秒后会被写回。

---

    1. ⚙️ 关系示意图

```text 应用写文件

数据写入 page cache


dirty < background_ratio → 不写回
dirty ≥ background_ratio → 后台写回线程启动
dirty ≥ ratio → 应用被阻塞并强制写回

```

---

    1. 💡 调优建议

| 场景 | 调优建议 | | ----------------- | ----------------------------------------------------------------- | | 高写入频率、低延迟系统(如数据库) | 降低 `dirty_ratio` 与 `dirty_background_ratio`,如 10 和 5,减少突发写回造成的延迟。 | | 批量文件写入或大文件拷贝 | 提高 `dirty_ratio`(如 40),让系统积累更多写缓存,减少频繁 I/O。 | | SSD 系统 | 可以略微提高比例,因为写入延迟低。 | | HDD 系统 | 建议保守设置,避免一次性写入量太大造成 I/O 卡顿。 |

---

    1. 🔍 查看当前值

``` cat /proc/sys/vm/dirty_ratio cat /proc/sys/vm/dirty_background_ratio cat /proc/sys/vm/dirty_writeback_centisecs ```

---

    1. 🧩 临时与永久修改
      1. 临时修改(立即生效,重启后失效):

``` sysctl -w vm.dirty_ratio=15 ```

      1. 永久修改:

在 `/etc/sysctl.conf` 或 `/etc/sysctl.d/*.conf` 中加入:

``` vm.dirty_ratio=15 vm.dirty_background_ratio=5 ```

然后执行:

``` sysctl -p ```

---

    1. 🧠 实战案例
      1. 案例:数据库写延迟高
    • 现象:**
  • 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 页缓存机制** 的行为密切相关。

---

    1. 🧩 一、问题背景

EFS(Amazon Elastic File System) 是基于网络的 NFS 存储。 它的写入路径是这样的:

``` 应用 → 内存页缓存(dirty page) → 内核写回 → 网络(NFS 客户端) → EFS 服务端 ```

所以,**EFS 写延迟** 受三方面影响:

1. dirty 页写回时,**NFS I/O 延迟高**; 2. 写回过程阻塞进程,**I/O wait 上升**; 3. dirty 阈值太大导致突发写回,**系统抖动明显**。

---

    1. 🧠 二、内核默认行为(不适合 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**。

---

    1. ⚙️ 三、优化思路

目标: 让 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. 📊 四、验证效果

1. 运行:

  ```bash
  vmstat 1
  ```
  看 `wa`(I/O wait)列是否下降。

2. 查看:

  ```bash
  iostat -xz 1
  ```
  观察:
  * `await`(等待时间)应更稳定;
  * `util`(设备利用率)峰值应降低。

3. 如果有 CloudWatch:

  * EFS “DataWriteIOBytes” 图表应更平滑;
  * EC2 “DiskWriteOps” 波动应减小。

---

    1. 🧠 五、补充优化(EFS 特有)
      1. 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`:避免固定端口带来的冲突。

---

      1. 2️⃣ 检查写缓冲模式

确认挂载选项中没有 `sync`,要使用异步写:

``` mount | grep efs ```

如看到:

``` nfs4 rw,relatime,vers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,... ```

说明是异步写(✅)。

---

      1. 3️⃣ 对比测试

可以在调整前后使用:

```bash dd if=/dev/zero of=/mnt/efs/testfile bs=1M count=1024 conv=fdatasync ```

比较写入时间与 iowait。

---

    1. ✅ 六、结论
  • **默认 dirty 参数不适合 EFS 等高延迟网络文件系统**;
  • **调低比例和间隔** 可显著改善 I/O wait;
  • **EFS + NFS mount 优化** 能进一步提升性能;
  • 调优后系统写操作更平滑、负载更稳定。

---

如果你愿意,我可以帮你写一个自动检测+优化 dirty 参数的脚本, 它能根据内存大小和挂载类型(EFS/NFS/local)自动计算合适参数。 是否帮你生成一个这样的 Bash 工具?

      • here

“什么样的 dirty 参数配置更适合 EFS 这类高延迟网络文件系统”**。 这正是很多在 AWS 上跑容器、Web 服务或 CI/CD 工具(Jenkins、GitLab Runner 等)的人经常忽略的性能关键点。

---

    1. 💡 一、为什么默认参数不适合 EFS?

Linux 默认 dirty 策略是为 **本地磁盘(SSD/HDD)** 设计的,假设写入延迟低、带宽高。 但 EFS 是 **NFS over network(网络文件系统)**,意味着:

  • 写延迟高(>5ms 常见);
  • 吞吐受限于网络;
  • 写回触发时,内核可能要等待远程 ACK。

所以默认策略下:

  • dirty 页积累较多(默认 10%~20% 内存);
  • 一旦超过 dirty_ratio,内核会一次性写大量数据;
  • 导致所有写入线程被阻塞(I/O wait 飙升);
  • 系统负载周期性抖动。

---

    1. ✅ 二、EFS 适配原则(经验法则)

EFS 是 **高延迟 + 异步写** 场景,目标是:

> “让系统频繁地、少量地、平滑地写回,而不是一次性大量写回。”

因此参数调优目标是:

  • **降低 dirty 页累积量**;
  • **加快后台写回频率**;
  • **减少一次性突发写入量**;
  • **保证内核不阻塞应用写入。**

---

    1. 🧩 三、推荐参数配置(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 元数据有用) |

---

    1. 🔧 四、示例配置

```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

  1. 应用新配置

sudo sysctl -p /etc/sysctl.d/99-efs-tuning.conf ```

---

    1. 📊 五、为什么这些值合适

| 参数 | 原理解释 | | ------------------------------- | ---------------------------------- | | `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 缓存,适合频繁访问的小文件场景。 |

---

    1. 🧠 六、内核行为对比(默认 vs 调优)

| 指标 | 默认值 | 调优后(EFS) | | ------------ | -------- | -------- | | dirty 页积累 | 高(可达几GB) | 低(几十MB) | | 写回触发频率 | 低(5秒一次) | 高(1秒一次) | | 每次写入量 | 大 | 小 | | 应用写入延迟 | 周期性卡顿 | 平滑稳定 | | 系统 iowait | 高峰周期性上升 | 平稳较低 | | Load Average | 周期性波动 | 相对平稳 |

---

    1. 🧪 七、验证方法
      1. 1️⃣ 实时监控

```bash watch -n1 "cat /proc/meminfo | grep -E 'Dirty|Writeback'" ```

调优后,你应该看到 `Dirty` 保持在几MB以内(非常稳定)。

      1. 2️⃣ I/O 观察

```bash iostat -xz 1 ```

看 `await`、`svctm`、`util`,调优后波动应小。

      1. 3️⃣ CloudWatch 验证

查看:

  • EC2 → CPUUtilization(iowait 应下降)
  • EFS → DataWriteIOBytes(更均匀)

---

    1. 💬 八、进阶建议
      1. 1. 大内存机器(>32GB)

使用字节型参数更合适:

```bash vm.dirty_background_bytes=67108864 # 64MB vm.dirty_bytes=134217728 # 128MB ```

      1. 2. 对于数据库或日志型写入

可进一步降低 dirty_ratio,比如:

```bash vm.dirty_background_ratio=2 vm.dirty_ratio=4 ```

      1. 3. 只读 EFS 场景

可不调 dirty 参数,仅关注缓存压力:

```bash vm.vfs_cache_pressure=50 ```

---

    1. 🧰 九、实战建议总结

| 目标 | 策略 | | -------------- | --------------------------------------- | | 平滑写入、减少 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)。

references

Linux内存查看及一次释放Linux内存问题处理(Aliyun ecs)