前缀缓存快照别急着 mmap:先验证文件头和长度 服务重启后想把前缀缓存快速装回来一个常见做法是把树节点和 KV 数据保存成连续镜像再用 mmap 映射。读取路径可以变短文件内容却不会因此自动可信。半写入文件、旧版本布局、损坏的长度字段都会把“快速恢复”变成越界读取。前缀复用本来就依赖已有状态。10 月 12 日 vLLM 的双向 KV 传输方案把跨轮保留状态与后续复用放在同一条链路讨论。官方工程说明 只要状态需要跨时间保存就需要单独设计它的身份、格式与失效条件能找到数据和可以使用数据是两步。文件头是协议不是 C 结构体的照片直接把内存里的结构体写入磁盘会把本机字节序、填充和字段大小也带进去。更稳妥的做法是明确规定每个字段的编码。Python 的 struct 文档区分本机布局与固定大小、固定字节序布局适合用来写一个可检查的最小例子。struct 官方文档这里定义 20 字节文件头4 字节魔数、1 字节版本、3 字节保留位、8 字节载荷长度、4 字节 CRC32。教学载荷是普通字节不是真实 KV 张量。生产格式还需要模型、分词器、张量布局、精度与分片身份。一个会拒绝坏文件的解码器import struct import zlib HEADER struct.Struct(!4sB3xQI) MAX_PAYLOAD 1024 * 1024 def encode(payload): if len(payload) MAX_PAYLOAD: raise ValueError(payload too large) return HEADER.pack(bPFX1, 1, len(payload), zlib.crc32(payload)) payload def decode(blob): if len(blob) HEADER.size: raise ValueError(short header) magic, version, size, crc HEADER.unpack_from(blob) if magic ! bPFX1 or version ! 1: raise ValueError(unknown format) if size MAX_PAYLOAD or size ! len(blob) - HEADER.size: raise ValueError(invalid payload length) payload blob[HEADER.size:] if zlib.crc32(payload) ! crc: raise ValueError(checksum mismatch) return payload blob encode(bprefix-state-demo) assert decode(blob) bprefix-state-demo for bad in (blob[:8], blob[:-1], blob[:-1] bytes([blob[-1] ^ 1])): try: decode(bad) except ValueError: pass else: raise AssertionError(corruption was accepted) print(roundtrip and 3 rejection cases passed)先验证长度再按长度读取不是先相信一个大整数、分配内存、等校验失败后才回收。CRC32 用于发现意外损坏不提供身份认证也挡不住有意修改文件后重新计算 CRC 的人。跨信任边界的快照要另行做认证与访问控制。mmap 没有承诺零 I/Ommap 建立的是地址映射。后续访问可能触发缺页和磁盘读取映射函数返回不等于所有页面已经驻留内存。GPU 还需要可用的设备存储与传输路径。把“省掉对象反序列化”写成“0 微秒恢复完整缓存”会掩盖最耗时的部分。mmap 官方文档快照发布也要考虑写入中断先写临时文件并完成必要的落盘步骤再按文件系统语义发布最终版本读取方只接受完整、兼容的镜像。若校验失败应回退重算并记录原因不能返回一份半恢复的缓存。上述程序只在内存字节上测试协议和失败路径没有映射大文件、读取 SSD 或执行 GPU 恢复。它的价值是让坏数据在边界被拒绝恢复速度要用冷页缓存、真实文件大小和实际设备另外测量。