定向 DNS 构建之外:大规模区域变更的验证顺序与内存预算
Cloudflare 用定向构建规划器把区域设置变更从整区重建压缩到最小安全范围,文章摘要称全量构建减少 40%、峰值内存降低 85%、构建延迟减半。其核心不是少做工作,而是先证明定向写入与全量构建逐字节一致再执行;对装不下的大区域,用记录数阈值绕开全量构建,并接受覆盖不完整。
- 定向构建的前提是证明等价:无法证明的变更一律退回全量构建。
- 执行前要重读发布快照;写入顺序是先记录键、后引用它们的共享元数据键。
- 全量构建内存随区域线性增长;超过固定记录数阈值后系统放弃全量构建,改为重建顶点、元数据和事件涉及的名称。
- 同一域名可能有多个内部区域,共享元数据键像目录,必须整体重建而非打补丁。
先回答标题:定向构建决定“做多少”,验证顺序与内存预算决定“能不能做”#
Cloudflare 在 2026 年 11 月 2 日的文章中描述了 DNS 区域构建的一次改造:过去一次区域设置变更会重建整个区域,哪怕这个区域有数千万条记录;现在由规划器挑选“能证明安全的最小构建”。文章摘要称,这一改动让全量构建减少 40%、峰值内存降低 85%,并把从 DNS 变更到数据写入 Quicksilver 的时间减半(来源)。这些数字的统计基期与测量方法,本次材料未说明,引用时需要保留这一限制。
对开发者更有迁移价值的部分在数字之外:定向构建的重点不是“少做工作”,而是“先证明少做的工作与全量构建等价,再执行”;当区域大到全量构建装不下时,系统还必须有一条明确的降级路径。下文按材料顺序拆开这两条线,并标出材料截断处无法确认的部分。
为什么全量构建随区域规模失效#
材料把一次构建定义为:读取数据库当前状态,转换成边缘使用的格式,再写入 Quicksilver(Cloudflare 的分布式键值存储)。全量构建的步骤是读区域与设置、读每条记录、编码成键、与 Quicksilver 已有键比较、删除陈旧键并写入变更。最终写入的确实只有变化的键,但读、编码、比较仍覆盖每条记录,而且整个过程要把整个区域放进内存。
区域规模是关键变量:材料称部分区域已超过 2000 万条记录,并预计向数亿条增长;最大的区域已经无法完整放进内存。作为对照,2022 年的按记录构建平均比全量构建快 150 倍,在一百万条记录的测试区快 4250 倍。这两个数字来自材料,测试环境与测量方法未在提供的片段中展开。
材料还顺带纠正了一个常见误判:事件数量并非主要矛盾。Zone Builder 现在每秒接收约 700 个 DNS 记录变更,另有约 100 个其他事件(例如区域设置变更),相比 2022 年的约 250 个确实增长明显,但真正的问题在于部分事件所需的工作量会随区域大小增长。
验证顺序:从事件到写入的六步#
材料把“证明何时安全”称为大部分工作量所在。记录事件能说明改了什么;区域设置事件可能来自多个 Cloudflare 产品,不一定说明原因,还可能改动同名多个区域共享的数据。选多了浪费容量,选少了会在边缘留下陈旧或错误的 DNS 数据。为此,Cloudflare 的验证顺序大致如下:
- 事件携带变更信息。 生产者写入变更的字段与设置,并在可用时带上旧值和新值;随后沿生成 DNS 输出的代码追踪每个设置的影响面。
- 不确定性一律退回全量构建。 只更新时间戳的数据库操作、缺失细节、未知事件、可能影响区域内任意记录的变更,都按全量构建处理。材料的原话是:规划器从不把不确定性变成更少的工作。
- 映射到五种构建类型之一。 见下表。
- 执行前重读快照。 事件描述的是过去;构建可能排队等待,数据库已经变化,所以规划发生两次,执行前读取新的发布快照。材料在此处截断,后续对账细节未提供。
- 写入顺序是先记录键、后元数据键。 元数据键引用记录键,顺序反了会让权威服务器短暂指向尚未写好的数据。
- 元数据键整体重建。 若本次要写共享元数据键,就从新视图重建整个键,而不是在旧副本上打补丁;旧记录键则通过扫描 Quicksilver 中该名称下现有键来清除。
| 构建类型 | 重建内容 | 材料给出的典型触发 |
|---|---|---|
| Resources only | 特定 DNS 名称(资源)的记录键,不改区域元数据 | 普通 A、AAAA、TXT、CNAME 变更 |
| Resources and metadata | 特定名称和共享元数据 | NS、通配符变更 |
| Apex and metadata | 区域顶点和元数据 | Universal SSL 等设置 |
| Purge | 移除不应再发布的区域 | 区域下线 |
| Full zone | 全部记录 | 无法证明更小构建安全时 |
这张表背后是一条硬规则:定向构建写入的每个键,必须与全量构建会写出的内容逐字节一致;证明不了,就做全量构建。设置的影响面并不总是显然的,材料举的例子是 Universal SSL——启用或关闭它会更新元数据,并可能改变区域顶点的 CAA 记录(证书颁发机构授权记录,用来告诉证书颁发机构能否为该域名签发证书)。
内存预算:装不下的时候,正确性怎么让步#
材料明确写出一个有意为之的例外:全量构建同时持有数据库里的每条记录和 Quicksilver 中该区域的所有现有键,最大区域放不下;因此超过一个固定记录数阈值后,Zone Builder 永不升级为全量构建,改为重建区域顶点、元数据,以及队列中事件涉及的每个名称。阈值具体数值材料未给出,待核实。
这是用覆盖完整性换吞吐的决定。材料给出的理由是:对这些区域做全量构建根本无法完成,而重试期间它会占住 Kafka 分区,阻塞该分区上的其他所有变更。代价是某些名称可能没有被重建;缓解手段包括 zone holds(阻止同一名称被加入另一个账户)和必要时手动重建单个名称。哪些场景仍必须全量构建、降级之后如何收敛到最终一致,属于截断部分未覆盖的内容。
同名多区域与共享元数据键#
Quicksilver 为每个区域单独存记录键,同时为同一域名下所有 Cloudflare 区域存一个共享元数据键,作用类似目录:告诉权威 DNS 服务器回答查询时可以使用哪些内部区域 ID。客户在上下线等生命周期变化中,同一公开域名可能短暂存在多个区域对象,系统用优先级策略选出一个有界的小集合发布。
材料给出的例子是 example.com 下有 Zone 101、202、303、404,元数据键当前列出 101、202、303,404 存在但未被选中。此时 www.example.com 的 TXT 变更只影响 Zone 202 的记录键,元数据键不变;而 NS 或通配符变更因为元数据键记录了相关信息,必须同时更新两者。执行时,Zone Builder 会重新读取当前发布列表,因此它写入的是基于新视图重建的元数据键,而不是事件发生时的旧副本。
可以带走的检查项(以下为建议,非材料结论)#
- 把“无法证明等价就做全量”写成默认分支,而不是异常分支。
- 事件契约要能表达“改了什么”和“旧值是什么”;否则定向构建会静默退化为全量构建。
- 写入顺序按依赖排:先数据键,后引用数据的目录或元数据键,并整体重建后者。
- 为“装不下”设计显式降级路径,同时写清覆盖缺口和人工兜底方式。
- 合并同一区域的待处理工作可以省容量,但材料把“合并工作不能丢 Kafka 消息”列为五个待解问题之一,具体机制在截断部分,实施前需单独核实。
边界与待核实#
本次材料由文章摘要与部分正文组成,抓取标记为截断,结论可能在未提供部分。因此以下事项保持待核实:记录数阈值的具体数值;两次规划之间数据库变化后的对账与冲突处理;Kafka 消息合并的去重与丢失防护;40%、85% 和延迟减半的完整统计口径。可以确认的是验证顺序与内存预算这两条主线:先证明等价再选构建,先写被引用的数据再写引用它的元数据,以及在内存放不下时用显式例外换取流水线吞吐。
常见问题(FAQ)
定向构建一定比全量构建省内存吗?
超过记录数阈值的区域如何保证正确?
40%、85% 和延迟减半的统计口径是什么?
参考来源
以上为本文写作时的参考资料,引用观点以原文为准。