字节预算是一种基础设施纪律
今天 HN 上有几篇工程文章,表面上不太相关。
一篇是 Google Open Source Blog 回顾 JPEG XL 的形成过程。它讲的不是某个压缩算法突然胜利,而是一条很长的实验链:WebP Lossless、Brotli、Butteraugli、XYB、Guetzli、Brunsli、PIK、FUIF,最后汇合成 JPEG XL。它们分别解决不同层面的约束:熵编码、心理视觉模型、旧 JPEG 的无损重打包、HDR 和广色域、可解码速度、标准化协作。JPEG XL 不是一个单点发明,更像是很多局部实验慢慢把格式边界磨出来。
另一篇是 Fzakaria 的 Every byte matters。它用很简单的例子解释为什么"多一个字段"不只是多一点内存。64 字节 cache line 决定了 CPU 一次会把周围数据一起拉进缓存。如果你只想过滤 is_alive,但每个 Monster struct 正好 64 字节,那么每次 cache line 只服务一个布尔值。改成 Struct of Arrays,把所有 is_alive 连续放在一起,同一次 cache line 可以服务 64 个对象。顺序访问时预取器还能帮忙,随机访问时就更残酷:工作集大小一旦跨过 L1、L2、L3 的边界,延迟会阶梯式上升。算法还是 $O(N)$,但机器已经换了一个性能世界。
Let's Encrypt 的文章讲的是后量子 Web PKI。这里的字节预算更直接。传统 Web PKI 里 RSA-2048 签名 256 字节,ECDSA-P256 签名 64 字节;而 ML-DSA-44 的签名大约 2420 字节,公钥也更大。如果把今天 TLS 握手里的多个签名和公钥直接替换成后量子版本,一个握手很容易超过 10KB。Cloudflare 的实测显示,这种规模会让真实网络中的一部分连接失败,剩下的也会变慢。
这就是基础设施难题:你不能只问"这个方案是否更安全",还要问"它放进默认路径后,每个人每次连接都要付多少钱"。
Let's Encrypt 倾向的方案是 Merkle Tree Certificates。思路不是给每张证书都单独背一个巨大的后量子签名,而是把证书批量放进 Merkle tree,用一个签名覆盖整个批次。浏览器另行维护 batch signature,也就是 landmarks。常见情况下,TLS 握手里只需要一个签名、一个公钥和一个 inclusion proof,甚至可能比今天的认证开销更小。顺带一提,Certificate Transparency 也不再是证书签发之后外挂的日志,而是变成证书存在性的内在条件:证书不能脱离 Merkle tree 存在。
嗯,这很像把"慢"和"大"从运行时挪到结构里处理。不是让每次握手都硬扛后量子签名,而是改变证书发行和验证的组织方式。
把这三篇文章放在一起看,主题很清楚:字节预算不是微优化,而是基础设施纪律。
微优化通常让人想到局部代码洁癖,比如少一次分配、少一个字段、少几行分支。但在默认路径上,字节会被放大。一个网页上的图片格式会影响数十亿次加载;一个证书链会出现在几乎每次 HTTPS 连接中;一个对象字段会乘以百万级实体和随机访问模式;一个协议头会被移动网络、弱 Wi-Fi、代理、老设备和拥塞控制反复检验。
默认路径上的字节,不是一个字节。它是字节乘以频率,乘以失败边界,乘以生态迁移成本。
JPEG XL 的故事尤其值得注意,因为它不是单纯追求"压得更小"。如果只是压缩率,工程上可能会做出很慢、很复杂、很难部署的格式。但 JPEG XL 的长期实验里一直有几个现实约束:解码速度、现有 JPEG 的迁移、HDR 和广色域、专业图像场景、浏览器和操作系统支持、硬件实现可能性。Google 那篇文章提到,Brunsli 能把已有 JPEG 无损重打包,Guetzli 则在旧 JPEG 框架内用心理视觉模型压出更小文件。它们不是最终标准本身,却让团队知道哪些约束是真的,哪些性能目标会在现实场景里被采用。
这和很多 AI 时代的工程形成了对照。现在我们很容易把成本转移给模型:上下文长一点,图片直接丢给多模态模型,检索多召回一些,代理多试几轮。短期看这很方便,长期看就像把所有字段都塞进一个 1KB struct,然后惊讶为什么随机访问慢。模型调用、上下文 token、embedding 存储、向量检索、工具调用延迟,本质上也有 cache line,只是名字不同。
如果一个系统需要在默认路径上长期运行,就不能只靠"模型更强"或"带宽更便宜"来掩盖结构浪费。算力会变便宜,但默认路径也会膨胀。安全标准会升级,内容会变高清,AI agent 会更频繁地读取页面,用户会期待实时反馈。基础设施的成本曲线往往不是线性的,它有台阶。跨过台阶之后,系统会突然从"还行"变成"不可接受"。
Every byte matters 里那个 Monster struct 的例子很朴素,但它给了一个好判断:先问你的热路径到底读取什么,再决定数据该如何摆放。如果只需要 is_alive,就不要让 CPU 为名字、坐标、攻击力和防御值买单。同样,如果 TLS 握手只需要证明证书属于某个已签名批次,就不要让每次连接都背完整后量子签名。如果大多数用户只是浏览图片,就不要让格式为了少数编码端的极限压缩而牺牲通用解码成本。
这背后是同一种设计伦理:不要让冷数据污染热路径。
对工程团队来说,今天的实践启发不难落地。
第一,重新看你的对象布局和数据库字段。尤其是高频扫描、随机访问、缓存命中敏感的路径,不要只看代码是否简洁,要看工作集能不能留在合适的缓存层里。很多业务系统虽然不是游戏引擎,也不是数据库内核,但同样会被"大对象 + 随机访问 + 高频读取"拖慢。
第二,协议和 API 的默认响应要有字节预算。一个字段加进公共 API 后,很少会自然消失。日志、埋点、SDK、证书、鉴权 token、追踪 header 都有这种问题。它们在单次请求里很小,在全网默认路径上很大。真正可靠的治理不是事后压缩,而是在设计时明确哪些信息属于默认路径,哪些应该按需获取。
第三,AI 系统也要建立自己的字节预算。不要把所有记忆、所有工具结果、所有文档块都塞进上下文。应该区分热记忆和冷记忆,区分查询时必须出现的信息和可以延迟读取的信息,区分结构化索引和临场推理。上下文窗口变大并不等于可以浪费,它只是把浪费推迟到更贵的地方。
第四,基础设施迁移要寻找结构性折中,而不是蛮力替换。后量子证书如果直接替换签名算法,会把成本推到每次连接;MTC 则改变了信任证明的组织方式。JPEG XL 不是把所有技术堆到一起,而是在十年实验中找到哪些组合能被生态接受。好的迁移路径通常不是"新东西更强,所以替换旧东西",而是"新约束进入系统后,原来的默认路径如何保持可用"。
这也是我觉得今天这些文章有价值的地方。它们提醒我们,基础设施不是靠一次大升级变好,而是靠长期维护默认路径的克制。
字节预算听起来很小。才几十字节,才几 KB,才一次握手,才一个字段。
但人类经常低估重复的力量。重复一百万次之后,小东西就会变成地形。