DNS 基础设施

本页目录

一家服务商的 DNS 管理 API 已经返回成功,某地区用户仍解析到旧地址。排查时需要沿控制面发布、权威副本、递归缓存、应用缓存逐层核对,而不是只检查管理页面。DNS 的分布式机制提高扩展性,也让“变更已提交”和“用户已切换”之间存在多个可观察阶段。

工作对象负责什么主要观察点
注册/委派管理父区 NS、glue、DS 等父区实际发布的状态
权威服务提供所管理 zone 的数据各权威实例、SOA、签名和应答
递归服务查询、验证、缓存与策略命中率、上游失败、验证和尾延迟
本机/应用解析选择上游、视图及本地缓存应用真实路径、VPN/浏览器设置
DNS 流量调度按策略生成答案缓存粒度、健康检查与应用连接分布

根服务:13 个名字,不是 13 台物理机

根区配置了从 a 到 m 的 13 个具名权威服务,由各运营者部署众多实例。实例数和站点持续变化,不适合把一个无日期的数量写成架构常量。root hints 提供根服务名称和地址,帮助递归器启动;它不是完整根区,也不是 DNSSEC 信任锚。IANA:根名称服务器

根区包含顶级域委派、相应地址及 DNSSEC 等数据,根提示文件只用于找到根服务器,不等于完整根区。需要大小时应对明确版本/格式实际测量,不把提示文件大小当完整区规模。IANA:根区与文件

根服务器不提供普通递归服务,但可以对根区自身负责的数据或相应不存在情况作答,不是只会 referral;收到 RD=1 也不意味着它必须替请求者递归。递归器通过 priming 获得根 NS 等当前信息,启动信息陈旧与根区信任链错误是两类问题。RFC 8109:根启动查询

Anycast:路由选择不等于地理距离排序

多个位置宣告同一服务前缀,网络根据可达性、路由策略及各项度量选择路径。AS_PATH 只是 BGP 候选因素之一,LOCAL_PREF 等可能更早决定结果;所谓“最近”不能直接等于最少 AS 数、最短公里数或最低 RTT。RFC 4786:Anycast 运维

Anycast 选择服务入口,DNS 答案选择应用入口:两次决策 递归解析器 向权威服务地址发查询 Anycast 权威实例 由路由策略选择实例 DNS 答案 返回应用 IP 集合 客户端发起应用连接 采用已解析地址 实际应用 / CDN 节点 还可能有独立 Anycast 或代理 权威查询通常来自递归器;应用连接来自客户端,两个来源与两次路径选择可能完全不同。

从一个观察点访问同一 IP,可能随路由变化切到另一实例。多个实例一致宣告同一 /24 并不能保证永久会话粘性;恰恰因为同一前缀多地宣告,选择才依赖上游路由状态。

短 UDP 查询较容易重试,但 DNS 还使用 TCP、TLS、HTTPS、QUIC 等持有连接状态的承载。路径突然切换时,新实例可能没有旧连接状态,需要合适的路由稳定性、状态处理或重连策略。不能笼统说“DNS 每次独立,所以 Anycast 完美没有代价”。

服务故障也未必导致链路或 BGP 会话故障。若实例无法正确回答却仍宣告路由,流量可能持续落入黑洞;健康检测与撤路由的联动、撤回时机和覆盖前缀需要设计。另一方面,频繁撤回会造成抖动,不应让每次短暂超时直接触发全站撤路由。

权威冗余:多个 NS 名字不等于独立故障域

两个 NS 若共用同一机房、上游、账户或发布流水线,仍可能一起失效。设计需要考虑服务和管理面的共同依赖,并确保每个宣告权威都能正确回答所需数据。

primary/secondary 可以通过 AXFR/IXFR 等同步,托管服务也可用内部数据库发布;无论采用什么机制,都应观察各权威实际结果。SOA serial 有助于检查某些部署的版本,但签名有效性、记录内容与全节点加载结果也要核对。

对外权威通常不应同时向任何人开放递归。BIND 的 views、访问控制与递归选项可以表达不同策略,但其匹配顺序和具体语义要按所用版本核对;“监听了 53”并不说明角色隔离正确。BIND 配置参考

递归容量:缓存命中率决定上游压力

假设服务收到 10000 查询/s,90% 在所讨论的缓存层命中,则约 1000 查询/s 需要进一步处理。若每个未命中平均触发 3 次上游事务,平均上游负载约 3000 次/s;命中率降到 50% 后可升至 15000 次/s。这里的“3”是示例测量假设,实际别名、委派缓存、DNSSEC 和失败重试会改变它。

平均上游事务 3000/s、平均在途时间 20 ms,则按稳定系统的 Little 定律,在途量均值约 60。它不能作为连接池或内存的唯一容量,因为冷启动、权威超时和重试尾部可能远大于均值。

指标帮助区分
命中/未命中与请求类型容量变化是否来自缓存或工作负载
上游事务数、重试和超时外部权威问题还是本地处理问题
RCODE 与验证失败原因NXDOMAIN、SERVFAIL、DNSSEC 错误分别来自哪里
p50/p95/p99 与请求阶段平均正常但尾延迟严重的路径
TCP 回退与响应大小EDNS、分片、DNSSEC 大包相关问题

重启多个递归实例会同时丢失热缓存,可能放大上游压力。负缓存、请求合并、预取和 serve-stale 各有用途与正确性边界,不能只追求把命中率数字做到最大。

命中率少十个百分点,上游会多忙多少?

保持每次未命中的工作量不变,把命中率从90%降到50%,上游从3000变为15000次/s,是五倍而非“只多40%”。随后只拉长时延,上游速率不变,在途量继续增加,这正是 Little 定律中两个因子的分工。

正在呈现知识画面
命中率少十个百分点,上游会多忙多少?

缓存命中率先改变上游到达率,延迟再决定平均占用。相同查询吞吐下,慢上游可以显著增加在途事务。

CDN 与 ECS:权威通常先看到递归器

普通客户端把查询交给递归器,CDN 权威看到的源 IP 通常属于递归器,不是终端本身。地理位置策略用地址库和运营数据作判断,延迟策略也可能使用历史测量或聚合估计,不能假设每条 DNS 查询都实时 ping 所有候选 edge。

ECS 允许解析器携带客户端子网信息,权威可据此细分答案,并使用 scope 等规则约束缓存复用。源前缀长度不是协议强制所有 IPv4 都 /24、IPv6 都 /56;暴露精度、服务支持和配置均会影响结果。RFC 7871:EDNS Client Subnet

假设原本一个名称/类型只需缓存一份答案,引入 100 个相关子网范围后,可能需要多份带范围的缓存条目,复用率下降。ECS 不是只增加“更准的地理定位”而无其他成本,它还改变隐私与缓存行为。

Route 53 的 latency routing 依据其延迟数据选择配置区域的资源,而不是保证请求者到每个具体应用端点的瞬时最小延迟;地理距离近也可能因网络互联更差而更慢。AWS:延迟路由

DNS 负载均衡:选择应答不等于调度每个请求

在一份 A RRset 中列两个 IP,只表达多个地址,并没有用于 weighted round-robin 的权重字段。托管服务的加权策略是在生成应答时按配置选择记录或记录组;客户端如何使用多地址、连接是否复用及失败重试又是下一层行为。AWS:加权路由

例如解析器 R1 缓存到 A 后带来 10000 个业务请求,R2 缓存到 B 后仅带来 100 个。即使这两次 DNS 选择按数量是 1:1,应用负载却约 100:1。因此 DNS 权重不能保证字节量、连接数或交易数精确按比例分配。

健康检查失败后,新答案可避开故障端点,但旧缓存与已有长连接不会立即被“召回”。缩短 TTL 能改变未来缓存时窗,也会增加查询压力,且不能代替客户端重试、应用健康与连接迁移设计。

Split DNS:视图选择与上游路由都要明确

同一名称可在内部返回私有地址、外部返回公开地址,也可让特定后缀只交给内部 DNS。服务端 views 与客户端按后缀选择解析上游是不同实现位置,两者都需要明确哪类请求进入哪条策略。

例如 dashboard.example.com. 内部应答为 192.168.31.8,外部应答为文档示例公网地址。内部用户若浏览器独立 DoH 绕过系统分流,可能得到外部结果;VPN 断开后保留内部缓存也可能出现不可达。这不是 A 记录语法错误,而是查询路径和缓存上下文的问题。

缓存不能不加区分地把某视图结果提供给另一个视图。内外使用同一个受 DNSSEC 签名的名称空间时,还需设计内部授权与验证关系,不能让本地随意覆写与公共 DS 链互相冲突。

搜索域把短名称扩展为候选绝对名称,路由域则帮助选择上游;概念与具体实现语义需分别核对。配置了内部 DNS 也不代表全部应用都会使用它,应从应用实际路径验证。

发布一次变更:分阶段观察

一条 DNS 变更经历发布、权威同步与各层缓存 管理控制面 提交记录与校验 权威数据面 各节点加载/签名 递归与应用缓存 旧副本按规则到期 API 返回成功 ≠ 所有权威已更新 ≠ 所有用户已切换 更新记录、变更 NS 委派和更新 DS 是不同操作,涉及的父子区状态与缓存寿命也不同。

修改普通记录,主要关注权威发布、签名及记录缓存;变更 NS 委派还需关注父区 NS/glue 与新旧权威服务重叠;更新 DS 又涉及 DNSSEC 父子区链及密钥缓存。三者不能用同一个“等待 TTL 就好”概括。

阶段可核查证据
发布接受控制面版本、配置校验与操作状态
权威可见各 NS/实例实际返回的 RRset、SOA、签名
委派一致父区 NS、必要 glue、DS 与子区状态
递归可见多个独立解析路径的答案、TTL 与验证结果
应用可用真正业务连接到哪一地址、是否完成预期请求

诊断可用 dig @<权威地址> <名称> A +norecurse 对照权威,再用所用递归器查询。dig +trace 展示工具自行迭代的路径,不等于应用配置的递归、DoH 或 VPN 路径;改变观察方式也改变了实验条件。本篇未运行真实外部探测。

本地容量与负载模型

query_rate = 10000
upstream_per_miss = 3
warm = query_rate*(1-.9)*upstream_per_miss
cold = query_rate*(1-.5)*upstream_per_miss
assert round(warm)==3000 and cold==15000
assert round(warm*.020)==60
# 两份缓存各选择一次,但各自背后的应用量不同。
requests = {'A':10000,'B':100}
assert requests['A']/requests['B']==100
assert 10000/(10000+100)>.99
# 仅示例限定状态下的负载,不代表实测容量或固定缓存模型。
print('缓存未命中负载、平均在途事务和 DNS/业务比例差异检查通过')

这些是明确假设下的算例,不是服务商性能实测;未修改根提示、公开委派、权威记录或解析器视图。

继续查阅