入门指南
改一条 A 记录不是发布:TTL 是上限、否定回答也会缓存、dig ANY 不算验收
改完记录,旧 IP 还在应答;新子域明明建好了,访问却仍说「不存在」。TTL 只是上限、否定回答也会被缓存、ANY 查询返回的是递归缓存——把四层缓存拆开,再从权威与递归两侧取证。
TTL 是上限,否定回答也缓存,ANY 只回缓存。

先看答案
- 适合谁
- 把域名从旧主机切到新主机、切完发现一半用户还在旧站的人
- 新建子域后立刻访问报「找不到」,过一阵又自己好了的人
- 习惯用 `dig ANY` 或在线「DNS 检测」网站下结论的人
- 你会获得
- TTL 是上限,否定回答也缓存,ANY 只回缓存。
- 发布时间
- 实质更新
- 发布
- AOPC 编辑部
60 秒结论
一分钟看懂这篇文章
TTL 是上限,否定回答也缓存,ANY 只回缓存。
人负责
- 决定何时改、留多久
- 判断该不该先删
AI 负责
- 从权威与递归两侧取证
- 读 SOA 算否定窗口
- 分层
- 降 TTL
- 改值
- 两侧核对
直接答案
「我把 A 记录改了,怎么还没生效?」这句话里其实有四个缓存,它们各自独立过期,任何一层没走完,你看到的都可能是旧世界:
| 层 | 谁在缓存 | 由什么决定 | 你看到的假象 |
|---|---|---|---|
| ① 权威区文件 | 你自己的权威 NS | 记录值与 TTL 字段 | 面板已是新值,指定权威查却还是旧的 |
| ② 肯定缓存 | 递归解析器、运营商 DNS | 旧记录的 TTL 剩余时间 | 「DNS 生效要一天」 |
| ③ 否定缓存 | 同上,针对 NXDOMAIN/NODATA | SOA MINIMUM 与 SOA TTL 的较小值 | 记录早建好了,访问仍说「不存在」 |
| ④ 本机/应用缓存 | 系统 stub、浏览器、运行时 | 各自的实现与上限 | 换台机器就好了,于是以为问题已解决 |
最常见的错误是把 ① 当成全部:面板一改就认为「发出去了」,然后拿一个不指定服务器的 dig 当验收。改记录不是发布,是一次有四层缓存的迁移。
本文以 RFC 2181(DNS 规范澄清,Standards Track,1997-07)与 RFC 2308(否定缓存,Standards Track,1998-03)为规范依据,以 Cloudflare 的公开 DNS 文档为「默认值与默认行为」的实现样本。它不是 DNS 服务商评测,也不假设你用哪家;不同厂商的默认 TTL 不同,但要问的问题一样。
一、TTL 是上限,不是倒计时
这是整篇文章的地基,规范只有一句话,但它推翻了大多数人的直觉:
The TTL specifies a maximum time to live, not a mandatory time to live.
RFC 2181 第 8 节同时把 TTL 的取值范围钉死了:无符号数,最小 0,最大 2147483647(即 2³¹−1);传输时编码在 32 位 TTL 字段的低 31 位,最高位(符号位)为 0;收到最高位为 1 的值,实现应「as if the entire value received was zero」处理。同节还留了一句关键的自由度:
Implementations are always free to place an upper bound on any TTL received, and treat any larger values as if they were that upper bound.
三句话合起来,得到三个反直觉的结论:
- 你写的 TTL 不承诺任何具体缓存时长。 递归解析器完全可以只缓存 60 秒,哪怕你写的是 86400;也可以把超过自身上限的值直接截断到上限。
- 「到点了就会换」不是一个可观测事件。 没有人会通知你某个运营商缓存刚过期;你只能看到「这一次查询返回了什么」。
- TTL 写小是「允许更早换」,不是「保证更早换」。 反过来,TTL 写大也不保证「一定缓存那么久」——只是允许。
RFC 2308 里有一个数字能说明这个上限有多宽:否定缓存「the protocol supports caching for up to 68 years」——那正是 2³¹−1 秒。规范给的是能力边界,不是建议值。
二、先分清你在改哪一种记录
在 Cloudflare 的实现里,记录的两种状态对应两套完全不同的 TTL 规则(其它厂商的默认值不同,但「能不能改」这个区分普遍存在):
| 记录状态 | TTL 规则 | 能不能提前降 |
|---|---|---|
| Proxied(橙云) | 默认 Auto,固定 300 秒,不可编辑 |
不能;这个值就是产品的固定行为 |
| DNS-only(灰云) | 可选 30 秒(Enterprise)/60 秒(非 Enterprise)到 1 天;Auto 也是 300 秒 |
可以,但只能在这个区间内选 |
TTL 页把 proxied 的 300 秒解释得很直接:因为只有「records used for IP address resolution」才能被代理,固定 300 秒可以保证「potential changes to the assigned anycast IP address will take effect quickly, as recursive resolvers will not cache them for longer than 300 seconds (five minutes)」。
注意这句话里的主体:递归缓存的是 anycast 地址,不是你的源站地址。所以对橙云记录来说,「换源站」与「客户端拿到新 IP」是两件不同的事——前者发生在边缘回源,后者才需要等 DNS 缓存。具体 anycast 地址何时变化不由你的 TTL 决定(这是编辑判断,文档只说明它会「被快速传播」,没有承诺地址不变或必变)。
同一页还有一条容易被略过的注脚,它正好否掉了「5 分钟后就一定好了」:
It may take longer than 5 minutes for you to actually experience record changes, as your local DNS cache may take longer to update.
另外别把 Nameserver TTL 混进来:文档明写它是「a separate feature and only affects Cloudflare nameservers and custom nameservers」;你记录表里其它 NS 记录的 TTL,由各自的 TTL 字段控制。
三、改之前唯一有效的动作:提前降 TTL
Cloudflare 的 FAQ 把「多久生效」拆成了两句,第一句很乐观,第二句才是重点:
By default, any changes or additions you make to your Cloudflare zone file will take effect globally within 5 minutes, usually much less.
Depending on the Time-to-Live (TTL) set on the previous DNS record, old data may still remain cached until the TTL expires.
也就是说:「zone file 更新」与「所有人拿到新答案」是两个时刻。 前者是分钟级,后者由旧记录的 TTL 决定。FAQ 给出的建议是:
If changes to records with large TTLs are anticipated, it may make sense to reduce the TTL ahead of time so that the change takes effect as quickly as possible.
这里有一个必须自己补上的推论(文档没有替你算):降 TTL 这个动作本身也要先传播出去。你把 TTL 从 86400 改成 300 的那一刻,递归里存的还是「TTL=86400 的这条记录」,它仍可以按旧上限继续缓存。所以要真正缩短切换窗口,得至少提前一个旧 TTL 把新 TTL 放出去,等这一轮走完,再改记录值。否则你只是在改记录的同一天顺手改小了 TTL,切换窗口一点没缩。
对橙云记录,这条路走不通(300 秒不可编辑)。可行的替代是让旧地址继续可用,直到你确认流量已经切走——这不是 DNS 技巧,是发布顺序问题。
四、否定回答也会被缓存(最容易被忽略的一层)
大多数「切域名翻车」不是肯定缓存没过期,而是否定缓存。RFC 2308 第 3 节规定:
Name servers authoritative for a zone MUST include the SOA record of the zone in the authority section of the response when reporting an NXDOMAIN or indicating that no data of the requested type exists.
The TTL of this record is set from the minimum of the MINIMUM field of the SOA record and the TTL of the SOA itself, and indicates how long a resolver may cache the negative answer.
两条合起来是一个很多人不知道的事实:「这个域名不存在」和「这个域名存在但没有 A 记录」都会被缓存,缓存时长取 SOA MINIMUM 与 SOA TTL 里较小的那个。而且第 6 节写明,缓存命中时返回的 SOA:
with the TTL decremented by the amount of time it was stored in the cache
——所以你在 dig 的 AUTHORITY 段看到的那个 TTL,就是「这个否定结论还能被复用多久」的倒计时。归零之后,第 5 节的要求是:
upon reaching zero (0) indicates the cached negative answer MUST NOT be used again.
SOA MINIMUM 这个字段历史上被三种含义重载过(RFC 2308 第 4 节):整个 zone 的最小 TTL(已废弃)、没有显式 TTL 的记录的默认值(只在主服务器上有意义)、以及现在正式定义的「否定回答的 TTL」。所以在现代实现里,它主要影响的就是「查不到」这件事能记多久。
规范还给了一个实践刻度,值得记住:
Values of one to three hours have been found to work well and would make sensible a default. Values exceeding one day have been found to be problematic.
由此推出三条操作规则(属于编辑判断,但每条都对应上面的原文):
- 不要「先删后建」。 删除旧记录与创建新记录之间哪怕只有几秒,任何在这几秒里查询的递归都会拿到 NXDOMAIN,并把它缓存
min(SOA MINIMUM, SOA TTL)那么久。原地改值(同一个 owner name、同一个类型,只换内容)不会产生否定回答。 - 新子域上线前不要提前探测。 上线前用浏览器或监控探一次「还没建的域名」,等于主动喂出一个 NXDOMAIN 缓存;等记录建好,这个缓存还在。
- 切换窗口内别把 SOA MINIMUM 调大。 它同时是「否定缓存能记多久」,改大等于把一次拼写错误的影响时间拉长。
还有一种更隐蔽的 NODATA:CNAME 指向的目标没有记录。这时查询不是 NXDOMAIN,而是「名字存在、但没有你要的类型」,同样进否定缓存——所以切 CNAME 之前,先把目标端的记录准备好。
五、为什么 dig ANY 不能当验收
FAQ 里关于 ANY 的两句话,基本宣告了它在排错场景的失效:
what they return is just any type in the cache of recursive resolvers. This can cause confusion when they are used for debugging.
Because of Cloudflare’s many advanced DNS features like CNAME flattening, it can be complex and even impossible to give correct answers to ANY queries.
翻成操作语言:ANY 查的不是「你的区文件里有什么」,而是「这个递归手里恰好有什么」。 它可能只回一部分类型、可能回的是几分钟前的缓存、也可能被直接拒绝(FAQ 指向官方的「Deprecating the DNS ANY meta-query type」说明)。用它验收,等于用一个不确定的采样去证明一个确定的状态。
同一页还解释了一个和切域名直接相关的特性:ANAME/ALIAS 这类记录可以用 CNAME 在 zone apex 重建,靠的是 CNAME flattening——「Cloudflare returns an IP address instead of the target hostname that a CNAME record points to」。这带来一个副作用:apex 的 ANY 结果在 flattening 之后更加不可推断,这也正是 FAQ 说「even impossible」的原因之一。
正确的做法是按类型查、按服务器查:要 A 就查 A,要 CNAME 就查 CNAME,并且明确指定问谁。
六、从两侧取证:权威与递归
下面这套顺序是我自己用的(命令与判读属于编辑判断,规范依据在前四节)。核心原则:先证明「我这边改对了」,再证明「别人拿到了」。
# 1. 找到这个 zone 的权威服务器
dig +short NS example.com
# 2. 问权威:区文件里到底是什么(把 ns1.example.net 换成上一步的结果)
dig +noall +answer A www.example.com @ns1.example.net
# 3. 问递归:外面的人现在拿到什么(换两个不同解析器各查一次)
dig +noall +answer A www.example.com @1.1.1.1
dig +noall +answer A www.example.com @8.8.8.8
# 4. 查否定侧:这个「不存在」还能被缓存多久
dig +noall +authority A new.example.com @1.1.1.1
# 5. 查 CNAME 链的终点有没有记录
dig +noall +answer CNAME www.example.com @1.1.1.1
判读时把三个位置的数字分清:
| 你看到的数字 | 它在说什么 |
|---|---|
| ANSWER 段记录的 TTL | 这个缓存还能用这条记录多久(剩余值,不是配置值) |
| AUTHORITY 段 SOA 的 TTL | 这个否定结论还能被缓存多久 |
| 控制台上的 TTL | 上限,不是承诺 |
两个容易读错的细节:
- 递归返回的 TTL 通常小于权威返回的。 这不是配置不一致,而是缓存扣掉了已经过去的时间——RFC 2308 第 6 节对否定回答写明了「decremented by the amount of time it was stored in the cache」,肯定回答同理(这是缓存的定义,属编辑判断)。
- 权威返回的 TTL 才是你配的值。 如果权威侧就已经不对,别再等缓存了,先修区文件。
还有一个方向性问题:问权威时用的是「哪个 NS」。多台权威之间可能有同步延迟,所以第 2 步值得对两台各查一次;只查一台就宣布「权威已更新」,是把单点当成了全局。
七、切换清单(12 项)
| # | 检查项 | 怎么验 | 漏了会怎样 |
|---|---|---|---|
| 1 | 列出所有指向旧地址的记录 | 按 A/AAAA/CNAME 逐条过一遍 | 漏一条就有一部分流量留在旧站 |
| 2 | 分清 proxied 与 DNS-only | 看记录状态 | 以为能降 TTL,其实不能 |
| 3 | 提前把 DNS-only 记录的 TTL 降到目标值 | 改 TTL,等旧 TTL 走完 | 切换窗口一天没缩 |
| 4 | 新端点先能握手 | 用 IP 直连或临时 hosts 测 TLS | 记录切过去,证书不对 |
| 5 | 原地改值,不删后建 | 同 owner name、同类型,改内容 | 喂出 NXDOMAIN 缓存 |
| 6 | 权威侧核对 | dig … @<ns>,两台各一次 |
改了但没同步 |
| 7 | 递归侧核对 | 两个不同解析器各一次 | 只测了自己机房 |
| 8 | 本机/CI 侧核对 | 换一台机器或清 stub 缓存 | 把本机缓存当成线上状态 |
| 9 | CNAME 目标端记录就绪 | 查目标名的 A/AAAA | NODATA 进否定缓存 |
| 10 | apex 记录没被 flattening 误导 | 查 A,不用 ANY | 拿缓存片段当结论 |
| 11 | 旧地址保留到最大 TTL 之后 | 按旧 TTL 与否定窗口取大者 | 回滚时无处可回 |
| 12 | 回滚写成一行命令 | 旧值、旧 TTL、旧地址都在手边 | 出事时现场拼命令 |
第 11 项值得单独说:旧地址该留多久,取决于「最长的那条旧 TTL」和「否定缓存窗口」中的较大者,而不是「我觉得差不多行了」。如果你在切换前把 TTL 降到了 300 秒,那么旧地址留到 300 秒之后、再留一点余量即可;如果没降,就得按旧值等——这也是为什么第 3 项划算。
八、五种常见误读
误读一:「DNS 传播需要 24–48 小时。」 这个说法没有一手来源。可观测的只有两个状态:权威已经返回新值,以及某个递归还在返回旧值。后者由旧 TTL 的剩余时间(以及否定缓存窗口)决定,不是一个固定的「传播时长」。把 24–48 小时当成自然规律,会让你在该排查的时候选择等待。
误读二:「TTL 到点了,就一定换了。」 TTL 是上限。缓存可以更短,实现也可以自行设上限;「到点」没有任何通知机制。你能做的只有查询与留证。
误读三:「TTL=0 就完全不缓存。」 RFC 2181 只说 0 是合法的最小值,并没有规定递归必须怎么处理。把 0 当成「实时生效」的开关,是把取值范围当成了行为承诺(编辑判断)。
误读四:「先删掉旧记录,再建新的,比较干净。」
在 DNS 里这是最脏的顺序:中间那几秒的查询会得到 NXDOMAIN,并按 min(SOA MINIMUM, SOA TTL) 缓存。原地改值才是干净的做法。
误读五:「dig ANY 能看到全部记录,说明配好了。」
ANY 返回的是递归缓存里的内容,在 CNAME flattening 之下还可能「complex and even impossible」给出正确答案。它适合好奇,不适合验收。
(还有一个边界:改 NS 委派与改 A 记录是两件事。 本文只讲后者;换 nameserver 涉及注册商侧的委派与 glue 记录,时间线与排查路径都不同。)
九、本周就能做的五件事
- 抄下主力记录的 TTL 与状态:是 proxied 还是 DNS-only,TTL 是多少。这两个值决定了你有没有「提前降 TTL」这个选项。
- 要切的记录,提前降到 300 秒(DNS-only),并等旧 TTL 走完。如果降不了,就把「旧地址多留几天」写进计划。
- 用两个递归加一台权威各查一次,把输出存下来。出事时这份「切换前长什么样」比任何回忆都可靠。
- 查一次 SOA 的 MINIMUM 与 TTL:
dig +noall +authority SOA example.com。这两个数里较小的那个,就是一次拼写错误会被记住多久。 - 把回滚写成一行:旧记录值、旧 TTL、旧地址。切换当天不要去翻聊天记录找 IP。
如果只能记住一件事:权威区文件是「你说了什么」,递归缓存是「别人记住了什么」,否定缓存是「别人记住了没有」——三者过期时间不同,验收必须分开做。
边界说明:本文的规范性陈述全部来自 RFC 2181(2026-10-29 访问,HTTP 200,36 989 B)与 RFC 2308(同日访问,HTTP 200,41 428 B);实现侧默认值与默认行为全部来自 Cloudflare DNS 的两个公开页面(同日访问,均 HTTP 200:TTL 页 130 480 B、FAQ 171 363 B)。不写「DNS 传播需要 24–48 小时」(无一手来源)、不把 Cloudflare 的 300 秒与 30/60 秒当成所有服务商的默认值、不写「TTL=0 就一定不缓存」、不建议用 dig ANY 做验收、不把改 NS 与改 A 记录混为一谈。文中标注为编辑判断的有:橙云记录下「换源站」与「客户端换 IP」的区分、降 TTL 需等旧 TTL 走完的推论、dig TTL 为剩余值的解读、切换清单的 12 项与「旧地址留多久」的取大者规则。第六节的命令与判读顺序是按前四节规范写的操作流程,不是任何厂商的官方步骤;不同解析器的缓存实现不同,1.1.1.1 与 8.8.8.8 只是两个常见样本,不代表全网。
来源
以下页面均于 2026-10-29 逐条访问并验证为 HTTP 200;字节数为当日抓取的实际大小。
- Time to Live (TTL) · Cloudflare DNS Docs核查于 2026/10/29(200,130 480 B;页面标注 Last updated Apr 16, 2026):TTL 控制每条记录被缓存多久、以及记录更新到达终端用户需要多久;proxied 记录默认
Auto=300 秒且「This value cannot be edited」,因「only records used for IP address resolution can be proxied」,固定值保证 anycast 地址变更能快速生效(递归不会缓存超过 300 秒);注脚写明「It may take longer than 5 minutes for you to actually experience record changes, as your local DNS cache may take longer to update」;DNS-only 记录可选 30 秒(Enterprise)/60 秒(非 Enterprise)到 1 天,Auto=300 秒;Nameserver TTL是独立功能,只影响 Cloudflare nameserver 与 custom nameservers,其它 NS 记录由各自 TTL 字段控制。 - FAQ · Cloudflare DNS Docs核查于 2026/10/29(200,171 363 B;由
/dns/troubleshooting/faq/重定向而来):zone file 的改动「take effect globally within 5 minutes, usually much less」,但「old data may still remain cached until the TTL expires」,proxied 5 分钟、unproxied 可自定义;「If changes to records with large TTLs are anticipated, it may make sense to reduce the TTL ahead of time」;ANY 查询「return is just any type in the cache of recursive resolvers」,且因 CNAME flattening 等特性「it can be complex and even impossible to give correct answers to ANY queries」;另说明 ANAME/ALIAS 可用 apex 的 CNAME 重建,靠 CNAME flattening「returns an IP address instead of the target hostname」。 - RFC 2181: Clarifications to the DNS Specification核查于 2026/10/29(200,36 989 B;Standards Track,1997-07):第 8 节规定 TTL 为无符号数、最小 0、最大 2³¹−1,传输时放在 32 位字段的低 31 位、符号位为 0,收到最高位为 1 的值应按 0 处理;实现「always free to place an upper bound on any TTL received」;关键句「The TTL specifies a maximum time to live, not a mandatory time to live.」
- RFC 2308: Negative Caching of DNS Queries (DNS NCACHE)核查于 2026/10/29(200,41 428 B;Standards Track,1998-03):否定缓存「should no longer be seen as an optional part」;第 3 节要求权威服务器在 NXDOMAIN/无该类型数据时 MUST 在 authority 段带 SOA,其 TTL 取「the minimum of the MINIMUM field of the SOA record and the TTL of the SOA itself」,决定否定回答可缓存多久;第 4 节说明 SOA MINIMUM 的三种历史含义,其中「最小 TTL」已废弃、否定回答 TTL 是现行定义;第 5 节说明该 TTL「decrements in a similar manner to a normal cached answer」,归零后 MUST NOT 再使用;第 6 节说明缓存命中时返回的 SOA「with the TTL decremented by the amount of time it was stored in the cache」;并给出上限「up to 68 years」与实践刻度「one to three hours have been found to work well」「Values exceeding one day have been found to be problematic」。