原文首发于 TechNova: 基于 Intel Optane 的低延迟撮合引擎状态持久化架构深度剖析
承接页(解决方案):https://technologynova.org/solution/
传统 DRAM + SSD 的架构中,落盘意味着走一条很长的 I/O 路径:系统调用、文件系统、块设备层、DMA、设备队列……
哪怕 NVMe 很快,一次 fsync 的尾延迟也可能从数百微秒到数毫秒。
如果你把“确认回包”放在 fsync 之后,就等于在关键路径里引入不可控抖动。
于是很多系统退而求其次:撮合在内存里跑、日志异步刷盘。 这确实快,但会留下一个清晰的“丢数据窗口”——断电发生在刷盘前,最后几毫秒/几十毫秒的已确认交易会消失。
PMEM 的定位是填平 DRAM 与 SSD 的性能鸿沟:延迟通常比 DRAM 慢一个数量级(如 300–500ns 量级), 但比 NVMe SSD 快两个数量级,并且最关键的是可字节寻址:CPU 可以像访问内存一样直接访问它。
在 App Direct 模式下,结合支持 DAX 的文件系统(如 ext4-dax / xfs-dax),应用可以用 mmap 将 PMEM 映射到进程地址空间。
这样读写就不再走传统存储栈,而是直接由 CPU load/store 触发到内存控制器。
就算你写的是 PMEM 地址,CPU 的写回缓存策略仍会先把数据留在 L1/L2/L3 cache(易失)。
因此必须显式把相关 cache line 写回并建立顺序保证:典型序列是 store → clwb → sfence。
在实践里,一般不会手写这些指令,而是借助 PMDK(例如 libpmemobj)把一致性、刷写与恢复流程封装起来。
PMEM 编程最大的坑之一是:重启后虚拟地址会变。 如果你把普通指针持久化,重启后它会变成野指针。 所以正确做法是使用 PMDK 的“对象池 + 偏移指针(relative pointer)”模型, 以根对象(root object)作为所有持久化结构的入口。
原文给了一个清晰的方向:用 libpmemobj 管理订单簿/委托/成交等核心结构,并用事务 API 保证跨多结构修改的原子性。
事务提交时库会确保变更被正确刷写;崩溃恢复时依赖 undo log 回滚未完成事务,让状态重新变“可解释”。
mmap,而不是回放几分钟甚至几十分钟日志。如果你正在做撮合/风控/清算等交易核心系统,建议把“关键路径持久化”拆成两个问题来评审: 1) 如何在业务上定义“确认”的语义(对应 RPO/RTO 指标); 2) 如何在工程上把持久化从 I/O 路径变成内存路径(PMEM/DAX/事务/刷写顺序)。 更系统的落地路径可参考: https://technologynova.org/solution/