TierWAL 性能基线
TierWAL 三份性能契约 + 稳定性矩阵实测(Release 配置)。数字实测于本机 (12 逻辑核 / .NET 8.0.30 / x64,2026-08-28 当轮)。盘口:C: 为 NVMe SSD、F: 为 WDC 1TB 机械盘(WD10EZEX)——local 介质的延迟由盘的 fsync 成本主导,两盘对照即最坏/最优情形。 探针归属
benchmarks/TC.Tier.Products.Benchmarks(--wal-*-probe路由,同二进制绕开 BDN harness)。
配置
- TierWAL(EntryLog 底层:Managed meta 策略 / 16KB opaque 容器 / 锚点间隔 1024)
- entry 64B;组提交 = 批 1000 显式 CommitAsync 驱动;单条提交 = 三维度全 0(每写即 fsync)
- IO 模式 = FileOpenHints 简写参数(none/wt/dio/dio+wt;meta probe 默认 all 四模式全跑)
- 复现(介质 = spec 参数;磁盘介质将 TMP/TEMP 重定向到目标盘):
dotnet run -c Release --project benchmarks/TC.Tier.Products.Benchmarks -- --wal-meta-probe local 1000 all # 契约①(IO 模式矩阵) dotnet run -c Release --project benchmarks/TC.Tier.Products.Benchmarks -- --wal-meta-probe virtual 1000 all true # 契约①(virtual 载体写穿档) dotnet run -c Release --project benchmarks/TC.Tier.Products.Benchmarks -- --wal-replay-probe local 500000 64 250000 dio # 契约② dotnet run -c Release --project benchmarks/TC.Tier.Products.Benchmarks -- --wal-catchup-probe local 200000 20000 64 wt # 契约③ dotnet run -c Release --project benchmarks/TC.Tier.Products.Benchmarks -- --wal-snapshot-store-probe local 256 4 64 none # 快照存储选型 dotnet run -c Release --project benchmarks/TC.Tier.Products.Benchmarks -- --wal-append-probe local 1000 5000 wt # 稳定性矩阵(介质 × IO 模式) dotnet run -c Release --project benchmarks/TC.Tier.Products.Benchmarks -- --wal-append-probe virtual 1000 5000 none true # 稳定性矩阵(virtual 载体写穿档)
数字
契约①:选举时间窗口 ↔ 元数据持久化(WriteMetaAsync = stage + 一次 fsync 应答)
1000 次 × 128B 元数据(预热 3 次后采样)。判定线 = 150ms 选举窗口下界。
| 介质 | IO 模式 | p50 | p99 | p99.9 | 判定 |
|---|---|---|---|---|---|
| memory: | buffered | 0.005ms | 0.009ms | 0.019ms | 达标 |
| local @ C: SSD | buffered | 4.13ms | 10.95ms | 56.2ms | 达标 |
| local @ C: SSD | WriteThrough | 0.086ms | 0.573ms | 0.593ms | 达标 |
| local @ C: SSD | DIO | 2.18ms | 5.23ms | 8.52ms | 达标 |
| local @ C: SSD | DIO+WriteThrough | 0.051ms | 0.505ms | 1.69ms | 达标(最快) |
| local @ F: 机械盘 | buffered | 17.1ms | 59.6ms | 102ms | 达标(临界格——机械盘 fsync 方差大,跨轮可翻线) |
| local @ F: 机械盘 | WriteThrough | 0.170ms | 0.389ms | 16.2ms | 达标 |
| local @ F: 机械盘 | DIO | 20.3ms | 96.6ms | 178ms | 不达标 |
| local @ F: 机械盘 | DIO+WriteThrough | 0.127ms | 0.225ms | 0.429ms | 达标(全介质最优) |
| virtual(.tier,F: 盘,句柄级) | buffered | 16.7ms | 42.2ms | 125ms | 达标(临界,同上) |
| virtual(.tier,F: 盘,句柄级) | WriteThrough | 80.1ms | 251ms | 278ms | 不达标(逐写 journal 提交,见选型) |
| virtual(.tier,F: 盘,句柄级) | DIO | 19.5ms | 51.0ms | 157ms | 不达标 |
| virtual(.tier,F: 盘,句柄级) | DIO+WriteThrough | 17.5ms | 157ms | 256ms | 不达标 |
| virtual(载体写穿档) | buffered | 0.324ms | 0.504ms | 1.71ms | 达标 |
| virtual(载体写穿档) | WriteThrough | 0.180ms | 0.490ms | 0.869ms | 达标 |
| virtual(载体写穿档) | DIO | 0.171ms | 0.308ms | 0.990ms | 达标 |
| virtual(载体写穿档) | DIO+WriteThrough | 0.153ms | 0.223ms | 1.08ms | 达标(四模式全达标,与 local WT 同量级) |
机制:WriteThrough(写透)消除 commit 的 fsync 成本——每写已同步落盘 (FILE_FLAG_WRITE_THROUGH/O_SYNC),Flush 不再付全量刷缓存开销;buffered 每次 commit 付全量 fsync(盘物理成本 2–20ms/次);DIO(NoBuffering)单独是反模式——绕过页缓存但未写透, fsync 依旧 + 三重对齐成本;DIO+WriteThrough 叠加最优(直 IO 无缓存双拷贝 + 写透免 fsync)。
契约②:重放吞吐 ↔ RTO(50 万条 × 64B,起点 = count/2)
| 介质 | 重放吞吐 | 首次产出延迟(定位) |
|---|---|---|
| memory: | 3.42M 条/s(208.5 MB/s) | 5.3ms |
| local @ C: SSD | 2.82M 条/s(172.4 MB/s) | 9.9ms |
| local @ F: 机械盘 | 3.12M 条/s(190.2 MB/s) | 8.6ms |
| virtual(.tier,F: 盘) | 2.97M 条/s(181.5 MB/s) | 10.8ms |
重放是读路径,对 IO 模式不敏感(±5%)。RTO 外推:100 万条 ≈ 0.3–0.35s。 定位 = O(1):任意起点 = 段表二分 + 段内扫帧,固定 ~5–11ms(与起点无关、与总量无关)。
契约③:冷节点追赶 ↔ 收敛时间(快照 20 万条 + 增量 2 万条,WriteThrough)
形态:一体快照(N₀ = PersistedIndex,镜像 12.97MB)→ 导出(经注入 IAsyncTransferPersistence) → 冷节点导入 → 增量段补给(模拟网络到货)→ 增量重放 (N₀, N₀+delta]。
| 介质 | 快照生成 | 快照导出 | 冷节点导入 | 增量重放 | 收敛(存储侧) |
|---|---|---|---|---|---|
| local @ F: 机械盘 | 0.31s | 0.04s(339.5 MB/s) | 0.29s | 0.01s(1.51M 条/s) | 0.34s |
| virtual(.tier,F: 盘) | 0.37s | 0.04s(354.1 MB/s) | 0.38s | 0.01s(1.34M 条/s) | 0.43s |
三介质收敛同量级,存储侧无介质敏感瓶颈。快照传输时间不在口径内(内存传输面—— 真实网络传输由协议层承担)。
快照存储选型(256MB 镜像 × N 次快照,local)
形态:方案 A(段增量——每次只写增量段)vs 方案 B(全量重写——每次重写整个镜像);条目流 64B/条。
| 场景 | A 写 | B 写 | A 读(拼接) | B 读(单段) |
|---|---|---|---|---|
| 256MB × 4 快照 | 256MB / 0.34s | 640MB / 0.88s(2.5× 字节差) | 2365MB/s | 2175MB/s |
| 256MB × 8 快照 | 256MB / 0.34s | 1152MB / 1.68s(4.5× 字节差) | 3026MB/s | 2668MB/s |
结论(数字定案):方案 A 胜——写侧 = 镜像总量(恒增量)vs 累计全量(Σk×delta), 快照越频繁省得越多;读侧持平(拼接开销可忽略);A 的段累积合并成本 = B 单次全量写 (低频触发——raft 只需最新快照)。落地面 = IncrementalSnapshot (段 = 帧 + 段表 meta O(1) 恢复 + 阈值合并)。
稳定性矩阵:介质 × IO 模式 × 两提交形态(p99/p999 抖动有界)
组提交 = 批 100 × 1000 批(10 万条,纯缓冲——显式 CommitAsync 驱动,采样每批延迟); 单条 = 每写 fsync,采样每条延迟(5000 条)。每格预热 3 次后采样。
| 介质 | IO 模式 | 组提交 p50 | 组提交吞吐 | 组提交刺 | 单条 p50 | 单条吞吐 | 单条抖动 p99/p50 |
|---|---|---|---|---|---|---|---|
| memory: | buffered | 0.045ms | 34.5 万条/s | 241ms | 0.107ms | 9083 条/s | 1.6× |
| local @ F: | buffered | 0.046ms | 60.8 万条/s | 95ms | 41.7ms | 22 条/s | 1.8× |
| local @ F: | WriteThrough | 0.047ms | 58.6 万条/s | 88ms | 0.520ms | 1782 条/s | 2.3× |
| local @ F: | DIO | 0.046ms | 101.7 万条/s | 36ms | 33.7ms | 25 条/s | 3.2× |
| local @ F: | DIO+WriteThrough | 0.045ms | 41.8 万条/s | 139ms | 0.638ms | 1305 条/s | 2.5× |
| virtual(.tier,F: 盘,句柄级) | buffered | 0.052ms | 19.5 万条/s | 369ms | 33.3ms | 29 条/s | 2.3× |
| virtual(载体写穿档) | buffered | 0.045ms | 24.3 万条/s | 331ms | 1.13ms | 815 条/s | 2.1× |
组提交形态(raft 主路径)p50 全介质全模式有界(0.045–0.052ms);每格恰一次页 flush 提交刺(36–369ms,一次性事件非持续抖动——NTFS 扩容经稀疏化标记后无即时簇分配巨刺)。 单条提交形态 = IO 模式主导变量:WriteThrough 比 buffered 快 ~80×(0.52ms vs 41.7ms), 同契约①机制(写透免 fsync)。
选型
- 达标变量 = 介质 × IO 模式 × 提交形态的三维组合:FileOpenHints 正交 flags 设计 (None/NoBuffering/WriteThrough 可叠加 + 介质统一抽象 + hints 传递链路 TierWalOptions→引擎→ 文件打开)——同一套代码零介质分支,机械盘从 buffered 不达标(p99.9 178ms)翻转为 DIO+WT 达标(0.43ms,余量 350×)。
- raft 节点磁盘配置:WriteThrough(或 DIO+WriteThrough,全介质最优);buffered 在 机械盘上不可用于选举窗口场景;DIO 单独是反模式。
- virtual 完整能力 = 挂载级载体写穿档(CarrierWriteThrough——挂载参数第 5 个旋钮): 四模式全达标(p50 0.15–0.32ms),与 local WriteThrough 同量级。句柄级 hints 在 virtual 上 = 逐写 journal 提交(RM-07——每写付 fsync,p50 17–80ms),只作对照不作选型。
- virtual 的 Flush = 真 fsync(载体在途写屏障——绕写页缓存的字节计入脏判定, Flush 与同盘裸 fsync 同形 ~17–21ms)。
- 三份契约全部量化达标(存储侧):契约① 上表;契约② 重放 ~3M 条/s (RTO 100 万条 ≈ 0.35s);契约③ 收敛 0.34–0.43s(20 万条快照 + 2 万增量口径)。
- 快照存储 = 段增量(IncrementalSnapshot):写侧恒增量 vs 累计全量,快照越频繁省得越多 (×8 快照 4.5× 字节差);读侧拼接与单段持平。
维护
- 改动 TierWAL 写路径(append/opaque/提交链)或 Log 底层 cursor/Seek 后必须重跑对应探针 并更新数字(性能论断须实测)。
- 探针跑法见「配置」节;介质切盘 = TMP/TEMP 重定向到目标盘根目录。