SYSTEMS NOTES阅读地图
7个主要章节
4张图片与图示
4组对照与手算表

从一个具体请求或状态变化出发,追踪数据流与方法成立的条件。

章节速览7 节 · 展开选择

网络基础把 DNS 放在一次网页请求的开头,HTTP 缓存讨论网页表示能否复用。它们都叫缓存,却没有保存同一种东西:DNS 常保存名称对应的资源记录,HTTP 缓存保存请求所选择的表示及其元数据。

这次只追问两件事:一条 DNS 结果还能用多久,它究竟回答了哪些查询? 把时间和作用范围分开,就不容易把“没有 AAAA 记录”“名称不存在”和“解析服务器暂时没给出结果”混成一种失败。

先固定一条结果,而不是模拟完整解析器

本文假定响应已经完成来源、问题匹配等必要校验,只讨论 IN 类、普通 ASCII 完整主机名的一份有效结果。正结果是一组名称、类型、类相同且 TTL 一致的资源记录(RRset);例子只用 A、AAAA、MX、TXT。名称末尾的点表示完整名称,字母大小写不构成本文比较中的区别。

下面不处理别名链、委派查找、DNSSEC 证明、子树推断、抢先刷新、过期数据服务或缓存容量淘汰。内部程序只是单条结果的时间与匹配核算,没有读取或修改本机 DNS 设置,没有向真实解析器发送测试查询,也没有实现 DNS 报文解析。

RFC 1034 §3.6解释资源记录的名称、类型、类与 TTL;RFC 2181 §5.2澄清同一 RRset 的 TTL 应一致。这里直接以已符合条件的一组记录作为起点,不把拼接不同来源的记录当作合法 RRset。

TTL 是复用上限,不是整个名称的更新时间

假设解析器在逻辑时刻 r=100 秒收到一份可缓存的 A 记录集,收到的 TTL 为 T=60 秒。若未提前淘汰、未取得更新结果,也不使用过期复用机制,则:

到期时刻 d=r+T=160;在时刻 t 的剩余寿命为 max(0,d−t)。

本文允许缓存复用的区间为 r≤t<d;t=d 时已经到期。

时间都使用同一条按整秒递增的逻辑时间轴。公式描述“收到以后还剩多久”,并不表示每层缓存都能重新获得原始权威 TTL。RFC 1035 §3.2.1规定 TTL 为零的结果只能用于当前事务,不能靠缓存继续复用;本文的缓存查询也不会把它当作新事务的命中。

条目与收到时间收到的寿命查询时刻剩余秒数本文缓存复用判断
A 记录;r=1006010060可复用
同一 A 记录6015010可复用,向下游转发时不能仍报 60
同一 A 记录601600恰好到期,不再作为新事务的缓存命中
否定结果;r=200min(300,120)=12025070仅在该否定结果的查询范围内复用
同一否定结果1203200恰好到期

TTL 不是“这个域名所有数据同时更新”的周期。A 与 AAAA 是不同类型的记录集,可能有不同 TTL、不同到达时间;本地程序、递归解析器和其他中间层也可能在不同时间收到自己的副本。

上游在时刻100收到TTL60的A记录,150时剩余10秒;下游150收到的是TTL10,所以也在160到期。若150错误重置为60则延到210,额外多用50秒。
原创整秒时间线,使用上表自拟数值。横轴刻度与有效窗口按同一尺度绘制;不是网络抓包或真实解析器延迟测量。查看原图

若上游在 t=150 向下游回答这份结果,忽略本例未建模的传输耗时,下游收到的剩余 TTL 应是 10。下游到期时刻仍为 150+10=160。反过来,每次命中都重新设置 60 秒,会把到期点错误推到 210;频繁查询甚至可能让旧数据一直续命。

这个不变性来自一个简单等式:在转发时刻 u,剩余量为 d−u;下游的新到期点为 u+(d−u)=d。它解释的是同一份缓存信息转发时的倒计时;收到一份新的、经过校验的响应,是另外一个更新事件。

两种否定:名称不存在,还是这一类数据没有

先看两个自拟的查询结果,名称均不经过 CNAME:

查询及响应 能表达的结论 同名换类型时能否直接沿用这个否定
missing.example. IN A,RCODE 为 NXDOMAIN 该类中的这个名称不存在 本文同一 QNAME、QCLASS 的查询可以复用,不依赖 QTYPE
api.example. IN AAAA,NOERROR 且确认为 NODATA 没有所问的 AAAA 记录集 不能据此否定同名 A 或 MX;需要包含 QTYPE
同一查询得到 SERVFAIL 或超时 解析过程没有得到可用结论 不能改写成“名称不存在”

NODATA 不是一个独立的 DNS RCODE。它需要从完整响应内容判断;空 Answer 加 NOERROR 也不自动就是可缓存的 NODATA,例如还可能遇到委派等情况。本文从已经确认的否定结果起步,不提供仅凭两个字段分类报文的捷径。

RFC 2308 §5给出这两种否定缓存的匹配范围:NXDOMAIN 对应 QNAME 与 QCLASS,NODATA 还要包括 QTYPE。这样,查询 api.example. 的 AAAA 失败,并不会把同名的 A 正结果一同判成不存在。

这里刻意只比较同一个名称。后来的 RFC 8020 §2规定 NXDOMAIN cut:缓存的名称不存在结论还可影响该节点的后代查询,并列出继续使用已有未过期数据等例外。本文内部模型不实现这套子树推断;它对另一个名称返回未命中,不代表真实解析器必须对后代重新查询,也不把这个模型当作完整的现行否定缓存规则。

NXDOMAIN键为名称和类,同名IN类的A与AAAA查询都能匹配;NODATA键还含类型,api.example的AAAA缺失不能否定A。SERVFAIL与超时被放在单独的解析失败分支。
原创查询范围示意,所有名称均为教学例子。仅比较相同 QNAME,未画别名链、后代名称推断或 DNSSEC 证明。查看原图
自检:AAAA 返回 NODATA,为什么不能直接回答“这个名称没有 IPv4 地址”?

AAAA 与 A 是不同的 QTYPE。NODATA 的匹配键包括类型,只能复用“这个类、这个名称的 AAAA 记录集缺失”这一结论;A 记录仍须由自己的结果回答。

否定 TTL 从 SOA 取得,也要不断倒数

否定响应没有所问的正记录可附上寿命,因此通常借助 Authority 中的 SOA。按 RFC 2308 §3,权威服务器设置否定响应中 SOA 的 TTL 时,取 SOA 自身 TTL 与 SOA.MINIMUM 的较小值。

本例 SOA 自身 TTL 为 300,MINIMUM 为 120,否定缓存寿命为 min(300,120)=120 秒。

在 r=200 收到时,到期点为 320;t=250 剩 70,t=320 不能继续命中。若接收的是另一个缓存转发来的否定响应,还要尊重它已经减少的 SOA TTL,不能重新拿到权威处的完整窗口。RFC 2308 §6要求缓存回答携带相应 SOA,并减少已经经过的时间。

没有 SOA 的否定响应,不能从空气中编造一个无限寿命。RFC 2308 建议不缓存这类否定;本文的内部模型直接不建立可复用条目。TTL 为零也不建立这种条目。真实解析器还可以施加更短的本地上限,因此 TTL 是许可复用的上限,不是必须保留到最后一秒的承诺。

不要把 SOA.MINIMUM 机械地理解为“全区所有记录当前 TTL 的下限”。其历史语义经过更新;也不要从 RFC 1035 的早期说明推断 SOA 永远不能缓存。RFC 2181 §7.2 与 §8澄清了 SOA TTL 与 TTL 上限的相关约定。

解析失败缓存,不能冒充名称不存在

SERVFAIL、拒绝、超时等情况,没有提供“这个数据存在还是不存在”的有效结论。它们仍可能需要缓存,以免故障触发大量重复查询;但缓存的含义是暂时抑制无益重试,而不是证明 NXDOMAIN。

RFC 9520 §3.2已经要求解析器缓存解析失败,时间至少 1 秒、至多 5 分钟,并说明不同失败条件可以采用不同的匹配方式。不能把 RFC 2308 早期的“某些故障缓存可选”原样当作当前结论。

本文内部核算刻意不实现这套故障策略,也不把 SOA 的否定寿命套给它。对反复失败的实际系统,应另查解析器实现、超时重试与容量约束;不能根据这个教学模型安排生产故障恢复。

DNS、HTTP 与 LRU,各自回答不同的问题

机制 保存或管理什么 首先要检查什么
本篇 DNS 结果缓存 资源记录集或有范围的否定结论 查询名称、类型、类与剩余 TTL
HTTP 缓存 被请求选中的表示、验证器与指令 变体匹配、新鲜度及条件验证
LRU 淘汰 有限容量中条目的保留次序 访问历史与复用距离

LRU 可以让一个尚未到期的条目因容量不足而离开;反过来,条目即使仍在内存里,TTL 到期后也不能按本文规则直接复用。DNS 重新查询成功,也不会自动使已有 HTTP 表示变新鲜;这些时间线要分别记录。

手算之后,核对什么边界

内部验证使用独立的整秒倒计时与事件区间参考,核对到期前、恰好到期、TTL 零、多层转发不续命,以及同名跨类型、不同名称和大小写规范化。模型只接收已规范化为 0 至 2³¹−1 的整数 TTL;RFC 2181 §8 对线缆上高位被置为 1 的 TTL 所作处理不在这个输入接口里重新实现。名称验证限定普通 ASCII 主机名,不能当作 DNS 对任意标签的完整语法要求;不解析 RDATA,不执行报文合法性或服务器符合性认证。

tests/verify-dns-cache-article.cjs 已验证 1000 个随机条目的 95541 个倒计时位置、同数目的时间平移、8000 组名称与类型范围、2000 次转发链、24 个大整数边界和 29 类非法输入;手算表五行与图中五项坐标也接受核对。两张 SVG 共 30 个文字节点边界通过,原图已逐张查看。以上都是教学算术和模型边界检查,没有运行真实解析器性能实验。

现象或输入 本文的处理与限制
时间早于条目收到时刻 拒绝这条矛盾的时间线
TTL 到零、没有 SOA 的否定 不作为新事务的缓存命中
同名 AAAA 缺失、A 有结果 两种类型的结论分别匹配
名称大小写或尾点不同 本模型要求完整尾点,ASCII 字母统一小写比较
SOA TTL 与 MINIMUM 不同 取较小值;转发时仍扣除已经经过的时间
TTL 很大或收到时刻相加超出安全整数 拒绝教学模型不能准确表示的输入
只有 SERVFAIL 或超时 不伪造成 NXDOMAIN;故障策略另按 RFC 9520 处理
自检:每次命中都把寿命重新设成 60 秒,会发生什么?

同一份信息的到期点会被反复向后推,频繁访问可能让旧信息一直留存。例子里150时只剩10秒,下游也应在160到期;重新给60秒则错误延长到210。取得新的已校验响应才是另一个更新事件。

资料核对于 2026-10-27:RFC 1034、RFC 1035、RFC 2181、RFC 2308、RFC 8020、RFC 9520。正文时间线与图中名称均为原创教学例子,不是线上测量。