🐧 第六章 存储层次
📄 一句话概括

脏页攒到 10% 开始后台回写,攒到 20% 就阻塞写操作。模拟 4 GB 连续写:32 轮里有 11 轮被卡住——这就是【写入突然卡一下】的来源,不是磁盘坏了。

📝 本节和前面几节的关系

6.9 到 6.12 讲清了【缓冲与回写】的机制,这一节看它的旋钮在哪、该怎么拧。

一、六个参数

dirty_ratio(默认 20%):脏页超过总内存这个比例,写操作直接被阻塞,等回写完才能继续。 dirty_background_ratio(默认 10%):超过这个比例,后台线程开始回写,但不会阻塞你。 dirty_expire_centisecs(默认 3000,即 30 秒):脏页最多攒这么久。 dirty_writeback_centisecs(默认 500,即 5 秒):回写线程多久醒一次。 swappiness(默认 60):有多愿意把匿名页换出去(5.15 讲过)。 vfs_cache_pressure(默认 100):回收目录项与 inode 缓存的积极程度。

二、两个门槛的分工

10% 是【软门槛】:到这儿开始动手,但不打扰你。 20% 是【硬门槛】:到这儿你写的每一次都得等——因为再不写就要脏页溢出到磁盘上了。 所以【写入突然卡顿】几乎都是撞上了 20% 这个数。不是磁盘坏了,是脏页攒太多。 模拟一下:4 GB 连续写、32 轮里被卡 11 次——这个比例在真实系统里也差不多。

三、三类负载怎么调

数据库:想要【提交延迟稳定】。调低 dirty 比例、调短 dirty_expire——让脏页早点回写,别攒到硬门槛再一次性卡住。 大文件拷贝:想要【总吞吐】。调高 dirty 比例——多攒一点再一次写,减少随机写。但要接受【最后收尾时卡一下】。 突然断电不能丢:靠 fsync,不靠这些参数。参数只影响【什么时候写】,不影响【写没写下去】。

四、调参的三条纪律

一、一次只改一个。 改两个就不知道是哪个起作用。 二、量的是【你要的指标】。改吞吐就量吞吐,改延迟就量 P99 延迟——别只看平均值。 三、记住默认值再改。/proc/sys/vm/ 下每个文件都是当前值,先记下来。 还有一条:调参永远救不了错误的 IO 模式——如果程序在做小块随机写,先把模式改对,再谈调参。

五、动手 Demo:调优参数——脏页攒到多少才开始回写

这一节先把六个参数摆出来,再用一个模拟演一遍:连续写 4 GB 的时候,脏页怎么涨、什么时候会把你卡住。

total = 4096.0
bg = 0.10 * total      # 软门槛
hard = 0.20 * total    # 硬门槛
dirty, blocked = 0.0, 0

while written < 4096:
    dirty += 128
    if dirty > bg:
        dirty -= 128 * 0.6      # 后台回写跟不上
    if dirty > hard:
        blocked += 1
        dirty = hard * 0.9

实跑输出:

--------------------------------------------------------------------
调优参数——脏页攒到多少才开始回写
--------------------------------------------------------------------
① 先把参数摆出来

  参数                          默认量级          管什么
  -----------------------------------------------------------------------------------
  dirty_ratio                   20%               脏页超过总内存这个比例,写就被阻塞
  dirty_background_ratio        10%               超过这个比例,后台开始回写
  dirty_expire_centisecs        3000(30 秒)     脏页最多攒多久
  dirty_writeback_centisecs     500(5 秒)       回写线程多久醒一次
  swappiness                    60                有多愿意把匿名页换出去
  vfs_cache_pressure            100               回收目录项与 inode 缓存的积极程度

② 演一遍:连续写 4 GB,脏页怎么涨、什么时候被卡住

  指标             值
  -------------------------
  总内存假设       4096 MB
  后台回写起点     410 MB
  阻塞写的门槛     819 MB
  写入轮次         32 轮
  被阻塞的轮次     11 次

  **注意最后一行**:**写入并不是一直顺畅的**——**脏页顶到硬门槛,写操作就得等回写。**
  **这就是【写入突然卡一下】的来源**,**不是磁盘坏了。**

③ 三类负载该往哪调

  负载               想优化什么       怎么调
  ----------------------------------------------------------------------
  数据库             提交延迟稳定     调低 dirty 比例,早点回写
  大文件拷贝         总吞吐           调高 dirty 比例,多攒一点再一次写
  突然断电不能丢     —                靠 fsync,不靠这些参数

  **注意第三条**:**调参永远替代不了 fsync。**
  **参数只影响【什么时候写】,不影响【写没写下去】。**

软门槛 410 MB、硬门槛 819 MB,32 轮写入里被卡了 11 次。 注意【被卡】的意思是:写操作要停下来等回写——用户感觉就是【突然卡一下】。 这个比例取决于【写入速度】与【回写速度】谁快:写得比回写快,就一定会撞硬门槛。 所以【抖动】的本质是【生产速度超过消费速度】——这跟内存不足时的 Swap 抖动是同一个道理(5.15)。 对策只有两条:要么写慢一点(攒批),要么把回写调积极(调低门槛)。

📋 Linux 上看当前值:sysctl -a | grep -E 'dirty|swappiness|vfs_cache'——一次看全所有相关旋钮。

30 秒实验

  1. sysctl -a | grep dirty,把这台机器的六个值抄下来。
  2. cat /proc/meminfo | grep -E 'Dirty|Writeback',看现在的脏页有多少。
  3. 写一个大文件的同时反复读这两个数,看它什么时候涨到硬门槛。

常见误区

  1. 【dirty_ratio 管的是缓存大小】。它管的是脏页占内存的比例上限,是触发回写的门槛。
  2. 【调低 dirty 比例一定更快】。它让写更早发生、延迟更稳,但吞吐可能变低(写得碎)。
  3. 【调了参数就不用 fsync】。参数只管什么时候写,不管【写没写下去】。
自测三问(点开对答案) 1. dirty_background_ratio 与 dirty_ratio 差在哪? —— **前者到点开始后台回写、不阻塞你;后者到点直接阻塞写操作等回写。****一个软门槛,一个硬门槛。** 2. 写入突然卡一下是什么原因? —— **脏页撞上了硬门槛**,**写操作要停下来等回写到门槛以下。****不是磁盘坏了。** 3. 数据库为什么要把 dirty 比例调低? —— **为了让回写更早发生、更平稳**,**避免攒到硬门槛时一次性卡住,让提交延迟更稳定。**

相关笔记