背景

MGLRU 用多代 LRU 管理回收,它的回收循环要把"老化"(aging,推进代)、"要扫描多少 folio"和"实际回收"几件事捏在一起做。这几件事相互耦合,加上脏页(dirty folio)的处理逻辑又和回收主循环差异较大,使得整条回收循环既难读,又让脏页冲刷(dirty flush)难以在合适的时机生效。其中一些问题是在生产环境暴露的。

┌────────────────────────────────────┐
│         MGLRU 回收循环复杂         │
└─────────────────┬──────────────────┘
                  ▼
┌────────────────────────────────────┐
│ 老化、扫描量计算、回收循环互相耦合 │  扫描量每次迭代重算,与老化、轮转纠缠
└─────────────────┬──────────────────┘
                  ▼
┌────────────────────────────────────┐
│       脏页冲刷游离在循环之外       │  回收循环难跟随,脏页冲刷难以生效
└────────────────────────────────────┘

具体地,旧循环每次迭代都重新计算要扫描的 folio 数,而这个计算只在"不需要老化"或"默认优先级"时才按回收优先级移位,把扫描量计算和老化、轮转搅在一起。结果老化在某些本该立即推进的时刻被跳过,回收方白费一轮迭代直到优先级升级,过度回收 slab、破坏多 cgroup 场景下的回收平衡。

问题

  • 老化、扫描量计算、回收循环相互耦合
  • 扫描量每次迭代重算,缠着老化与轮转
  • 脏页冲刷游离在回收循环之外,难以及时生效
  • 部分问题在生产环境暴露,偶发意外 OOM

方案

系列用三条主线收拾这个循环。

旧:耦合,脏页冲刷游离
┌──────────────────────────────┐
│ 扫描量每次迭代重算,缠着老化 │
└──────────────┬───────────────┘
               ▼
┌──────────────────────────────┐
│  脏页冲刷在循环外,难以生效  │
└──────────────────────────────┘

新:起始定扫描预算,脏页冲刷进循环
┌──────────────────────────────────────┐
│       循环起始一次算清扫描预算       │
└──────────────────┬───────────────────┘
                   ▼
┌──────────────────────────────────────┐  老化需要时立即跑,脏页冲刷在循环内及时
│ 老化与回收计算解耦,脏页冲刷移入循环 │  触发
└──────────────────────────────────────┘
  • 引入 scan budget:在回收循环起始就一次性算清这次要扫描多少 folio,不再每轮重算。
  • 把老化从回收计算里解耦出来:扫描量始终尊重回收优先级,老化在该推进时立即推进,原先 DEF_PRIORITY 下即使已经无法 eviction 也跳过老化、空耗迭代,现在只在 eviction 仍可行时才允许这次跳过。
  • 把脏页冲刷逻辑移进回收循环内部,让它在回收进行中就能及时触发,而不是游离在外、错过时机。

这三处相互关联,合起来让回收循环更清晰,脏页冲刷更有效,也为后续 MGLRU 改进铺路。

收益

作者在 48c96t、NUMA 2 节点、128G 内存、NVME 存储的机器上测试。

MongoDB YCSB workloadb(recordcount 20M、operationcount 6M、threads 32,95% read/5% update;10G cgroup、WiredTiger cache 4.5G、NVME、不用 SWAP 以隔离文件 LRU 回写路径):

指标 MGLRU Before MGLRU After 变化
Throughput (ops/sec) 60,653.5 82,384.35 +35.8%
workingset_refault_file 12,904,916 7,128,285 -44.7%
pgpgin 165,366,622 113,170,693 -31.5%

MongoDB 吞吐显著提升,文件 refault 大幅下降,全程无 swap 介入。 在慢 IO(HDD、网络存储)上增益更大,部分 workload 超过 100%。其他常见 benchmark 无回归,LOC 减少,并减少了意外 OOM。