Kernel dirty

来自linuxsa wiki
跳转到导航 跳转到搜索

“**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)。

references

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