摘要

  • DNS 最初依靠从服务器按 REFRESH 周期查询主服务器的 SOA 序列号。它减少了主服务器负载,也把多台权威服务器暂时说出不同答案变成了设计内的常态。
  • NOTIFY 不是把新区数据直接推入从服务器,而是催促它向已配置的主服务器核验序列号;IXFR 随后可以从客户端已有版本出发,只发送按顺序排列的删除与新增。
  • 更快的路径仍受序列号环形算法、AXFR 完整回退、持久化、完整处理、原子切换和可选 TSIG 事务认证约束。信号可以让审查提前,却不能自行成为权威。

权威服务器彼此不同意的那些分钟

同一个 DNS 域部署多台权威服务器,是为了避免一台机器、一条线路或一个地点成为唯一故障点。但复制也带来一个不那么显眼的问题:主副本发生变更以后,其他同样对外宣称“权威”的服务器,要过多久才能知道自己正在描述昨天?

RFC 1034 给出的模型,是在一台主服务器上协调变更,由从服务器周期性查询 SOA 记录。从服务器比较 SERIAL;若主服务器版本较新,就获取新的域副本。REFRESH 决定常规检查的间隔,RETRY 决定失败后的重试节奏,EXPIRE 则规定长期无法刷新后必须停止以权威身份回答的最后期限。RFC 1035 把这些字段规定为 32 位数值,并为整域传送定义了 AXFR。

这套机制并不粗糙。没有变化时,系统只需交换一条很小的 SOA 查询,而不必重复搬运整个域。主动权也留在从服务器一侧:它知道向谁检查,知道多久重试,也知道何时必须撤下已经无法证明新鲜度的副本。

代价是,延迟被写成了策略。主服务器若在一次检查刚结束后更新,从服务器便可能在下一个 REFRESH 到来前继续提供旧版本。把间隔设短,会在平静时期增加无效查询;把间隔设长,又会拉长权威集合内部的不一致。

这里的陈旧与递归解析器缓存并不是一回事。即使所有权威服务器已经同步,解析器仍可能在 TTL 结束前使用旧记录;反过来,如果权威集合尚未收敛,两台没有缓存的解析器也可能因为问到不同权威服务器而得到不同答案。NOTIFY 与 IXFR 解决的是后者。

轮询把等待时间变成了运营选择

从服务器自主轮询有一个重要优点:即便某条通知通道不存在或失效,定时器最终仍会迫使它检查。系统不需要主服务器长期记住每个副本的在线连接,也不会因为一次消息丢失而永远失明。

到了 1990 年代中期,规模让两个成本变得突出。为了迅速发现小改动,运营者必须频繁查询;而一条地址记录的变化,又可能要求通过 AXFR 重传整个大域。发现变化的成本取决于轮询频率,取得变化的成本却取决于域的总大小,两者都和那次编辑本身不相称。

RFC 1996 直接写出了矛盾:较长的刷新周期能降低主服务器负担,却会在更新后造成较长的权威不一致。DNS NOTIFY 在轮询旁边加了一种“中断”。主服务器载入新版本后,可以告诉一组从服务器:有内容值得重新查看。

关键在“告诉”,而不是“替换”。从服务器收到 NOTIFY 后,应向自己配置的主服务器发起 SOA 查询,比较序列号,再决定是否传送。NOTIFY 中即使附带了答案数据,也只是未经保护的提示。发送者获得的是让检查提前发生的能力,并没有获得直接改写另一台服务器的能力。

敲门声不是送进屋里的包裹

默认通知集合来自域的 NS 记录,但排除 SOA 的 MNAME 所指主机;管理员可以覆盖该集合,也可以加入只存在于本地配置中的隐形从服务器。传送关系必须组成无环依赖图。某台服务器可以先作为从服务器取得副本,再作为下游服务器的主服务器继续分发。

这让负载可以分层,而不要求每个权威节点都直连唯一主节点。与此同时,真正的复制拓扑不一定完全写在公开域数据中,运营者必须自行掌握哪些节点从谁取数、谁又会通知谁。

NOTIFY 采用尽力而为语义。使用 UDP 时,发送方可以重发直至收到应答或达到上限,并通过退避避免轰击。从服务器可能从多个上游听到同一次变化;它需要在更新进行时抑制重复通知,以免几下敲门变成几次并发传送。

NOTIFY 应答只证明“听到了”,不证明新区已经上线。伪造源地址可以诱发无意义的 SOA 查询;不支持该操作码的旧服务器可以回复 NOTIMP。若通知丢失,原来的 REFRESH 轮询依然会接管恢复。因此把它简单称为“DNS 推送”并不准确:被推送的是紧迫性,权威数据仍要经过另一条受控路径。

会绕回零却不能随意倒退的序列号

更快检查依赖一个前提:两端必须判断哪一版更新。32 位数最终会从最大值回到零;若把 SOA 序列号当普通整数比较,新未来会被误判为旧过去。

RFC 1982 为此定义了有限序列空间。加法采用模运算,并限制可加范围;只要差距小于半圈,就能跨过零点判断前后。正好相隔半个 32 位空间的两个值没有定义顺序。在一个 EXPIRE 周期内,序列号累计推进不得超过 2^31−1,否则陈旧从服务器可能反而看上去更“新”。

序列号因此不是时间戳。它不说明编辑发生于何时、由谁批准,也不证明记录内容正确。它只是在允许的转换序列里提供相对位置。这个狭窄证据足以驱动复制,却不支持把它当成身份、所有权或永久真理。

发送修改,而不是重新搬一次档案馆

NOTIFY 缩短了发现变化的等待。RFC 1995 定义的 IXFR,则降低了追赶变化的成本。客户端在请求中携带自己已有副本的 SOA 序列号;若服务器仍保存从该版本到当前版本的历史,就只返回所需的差异序列。

每个差异由删除与新增构成,并由旧 SOA、新 SOA 划定版本边界。修改一条 RR,要先删除旧形式,再新增新形式。多个差异按从旧到新的顺序排列。它表达的不是悬空的“补丁”,而是“你现在持有 X,依次执行这些变化后得到 Y”。客户端只有处理完全部序列,才可以用新版本替换旧版本。

IXFR 历史从未被设计成永恒账本。服务器可以清除旧差异;当增量响应甚至大于 AXFR 时,直接发送整域更合理。超过 EXPIRE 的历史可以被丢弃,多次变化也可以压缩成一次净差异。压缩后,另一台服务器可能不认识客户端所持的中间序列号,于是仍要退回 AXFR。

这个回退不是失败,而是安全出口。差异传送需要双方共享一个明确起点,并需要服务器保存从起点到终点的路径。当共同记忆消失时,完整副本重新建立共同状态。优化可以放弃,收敛能力不能放弃。

新版本必须先能熬过重启

如果主服务器先向外分发、后持久化,崩溃后就可能不再拥有从服务器已经接受的版本。RFC 1995 因此要求,新区版本在用于回答 IXFR 或 AXFR 前先写入稳定存储。速度不能建立在源头自己会失忆的状态之上。

RFC 5936 从接收端进一步明确了 AXFR 完整性:客户端应先把新区放入独立存储,完成传送和合理性检查,再一次性切换对外服务。若过程失败,就继续服务先前有效版本。IXFR 也遵循同样边界:半段差异绝不能成为半个上线中的权威域。

于是,一次快速同步实际上由四种动作组成:通知触发检查;序列号证明需要更新;IXFR 或 AXFR 给出候选状态;完整验证与原子切换决定公开答案。任何一环都不能冒充全链条。

认证传输,不神化内容

域传送可能暴露大量结构,也会直接影响接收服务器的权威回答。RFC 5936 建议按策略限制传送访问,并用事务签名保护授权与完整性。现行 RFC 8945 定义了 TSIG:共享秘密的两端使用消息认证码保护 DNS 事务。

对于由多条消息构成的 TCP 域传送,TSIG 可以把认证链贯穿整个数据流,使接收端发现篡改。它能证明对方持有约定密钥,却不提供加密,也没有替运营者解决密钥分发。关系数量很大时,点对点共享秘密的管理会迅速复杂化。

更重要的是,TSIG 认证的是传输,不是源数据的真伪。一个被攻陷或判断错误的主服务器,完全可以发送密码学上无误的错误域。MAC 校验通过,并不等于记录建立了法律所有权、机构授权或事实真实性。保护边界越清楚,安全机制越不容易被借来制造越权结论。

一项安静的权力分拆

NOTIFY 和 IXFR 看起来只是性能改进,却回答了分布式权威中的核心问题:一个运营者怎样让另一个运营者尽快改变,又不直接接管对方的执行?标准把这件事拆成几句有限陈述:“发生变化了”“我的版本是 Y”“从你的 X 到 Y 需要这些步骤”“如果历史断了,这里是完整副本”“这次传输来自持有约定密钥的一方”。

没有一句可以单独上线。从服务器仍要判断起点、选择来源、完成数据、校验并切换。正因为权力被拆开,过时的权威副本才能更快退出,而无需让网络上最早到达的包自动成为事实。

加速也会让错误更快收敛。坏编辑可能在第一通投诉电话到来前覆盖所有边缘;过短的日志可能在长故障恢复时引发 AXFR 洪峰;错误序列号可能冻结同步;隐藏拓扑和失效密钥会放大不可见依赖。更快并不意味着更少治理,而是把治理前移到提交、验证和发布之前。

历史上的重要变化,不是主服务器获得了更大主权,而是域学会了敲门。从服务器可以更早醒来,但仍要为自己最终回答的内容负责。

来源与证据边界

RFC 1034 与 RFC 1035 规定轮询、SOA 计时和 AXFR;RFC 1982 定义序列号算法;RFC 1995 定义 IXFR 及完整回退;RFC 1996 定义 NOTIFY 和配置拓扑;RFC 5936 明确完整与原子上线;RFC 8945 定义 TSIG 及其限制。

这些规范能够证明协议设计,不能证明 1996 年 8 月存在一次全球同时部署,也不提供所有运营者的参数、日志深度或全球收敛实测值。本文的结论限于架构:触发、版本证据、传送和本地执行被刻意分离。