Table of Contents

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 重定向到目标盘根目录。