在 READ COMMITTED 隔离级别上做一条线性化日志
来源:materialize.com — 2026-10-13
📋 概述
Materialize 的持久化层需要一个元数据存储为每个持久对象保存少量状态。今年 6 月,一个自托管部署出现亚稳态故障:元数据操作延迟从几毫秒升到三十秒,原因是 SERIALIZABLE 隔离下 SIRead 锁涨到数十万个,每次插入都要走一遍近期读过同一页索引的事务的锁。文章讲述他们如何改造成在 READ COMMITTED 下构建可线性化的日志。核心不变量是:某个分片的序列号始终构成连续区间 [lo, head],于是「expected 存在且 expected+1 不存在」等价于「expected 就是 head」,CaS 只用一条 SELECT 加主键约束即可实现,并发写入靠主键互相围栏。新实现能承载三倍写入吞吐,团队还用 Lean 4 对 READ COMMITTED 建模并证明了线性化。
🔑 核心要点
- 事故形态:SERIALIZABLE 下 SIRead 锁涨到数十万个,每次插入都要检查近期读过同一页的事务,延迟从几毫秒涨到三十秒
- 这是 Bronson 等人所说的亚稳态故障:瞬时变慢让锁变多,锁变多又让每次写入更慢,形成自我维持的效应
- 关键不变量:同一分片的序列号始终构成连续区间 [lo, head]
- 由此推出:「expected 存在且 expected+1 不存在」等价于「expected 是 head」,一次 SELECT 加主键约束即可取代 SERIALIZABLE
- 并发 CaS 仅靠主键互相围栏:多个客户端同时插入同一序号时只有一个成功,其余收到唯一性冲突
- 结果:同样的压测从 4,300 次 CaS/秒的崩溃点提升到约 13,000 次/秒仍未触顶,而且新的失败模式下不存在维持效应
💡 金句
这个设计最终归结为一个不变量:一旦序列号被确认连续,一次主键检查就足以判断写入是否落在 head,SERIALIZABLE 便不再需要。
👍 0
👎 0
← 返回 Lobsters 首页