你把一条 A 记录从旧主机改到新主机。新服务器已经就绪——curl 新 IP 能看到新站点。但一半用户还看到旧站,邮件日志里还有流量打到旧 IP,手机用 4G 看到新站、笔记本连家里 Wi-Fi 看到旧站。其实什么都没坏。你正在见证全球各地缓存的 DNS 按各自的节奏过期,因为你改之前那条记录的 TTL 设得太高了。
这是”DNS 怎么还不传播”投诉里最大的一类,而且完全可以预防。一劳永逸的修复只要 30 秒——但前提是你在变更前 24 小时做,不是变更后。
TL;DR——你现在最快能做的:
- 如果你今天已经改完了,没有现场可以救的办法。旧的 TTL 正在全球缓存里倒数,只能等它走完(旧 TTL 是
86400的话最长 24 小时)。你可以用两大公共 resolver 的清缓存工具把尾巴削短一点:Googledns.google/cache和 Cloudflareone.one.one.one/purge-cache/。 - 下一次:变更前 24 小时先把 TTL 降到
300(或你 provider 允许的最低值),等旧 TTL 走完,再改记录的值。这样传播大约 5 分钟就完成了。
TTL 到底怎么控制传播
TTL(Time To Live)是权威 DNS 服务器在每条应答里附带的一个秒数。从你到用户中间的每一层递归 resolver(用户家 ISP、公司防火墙、Cloudflare 1.1.1.1、Google 8.8.8.8)最多缓存这段时间。
- TTL
300= 5 分钟过期,下次查询回到权威,用户 5 分钟内看到新值。 - TTL
3600= 最长 1 小时。 - TTL
86400= 最长 24 小时。 - TTL
172800(2 天)= 最长 48 小时。很多注册商的默认值。
决定旧值能在缓存里活多久的,是变更之前那条记录的 TTL。同一时刻改值又改 TTL,对已经在外面的缓存毫无用处——它们早就把旧值和旧 TTL 一起拿走了,会按那个时间继续缓存到过期。这一条规则几乎能解释下面所有情况。
先判断你属于哪一种
| 现象 | 大概率原因 | 有没有现场补救? |
|---|---|---|
| 权威已返回新值,公共 resolver 还返回旧值 | 旧 TTL 还在倒数(情况 1) | 没有——只能等 |
dig 出来的 TTL 比 UI 上显示的大 | provider 封顶 / 无视你设的 TTL(情况 2) | 换 provider,或提前计划 |
| 全新子域名一直返回 NXDOMAIN | SOA 负缓存 TTL(情况 3) | 降低 SOA minimum |
dig 返回 104.x / 172.x 的 Cloudflare IP | 前面挂了代理 / CDN,DNS 的 TTL 已经不重要(情况 4) | 清代理的 HTTP 缓存 |
情况 1:今天才改记录,到现在还没全传播
最常见。你今天同时改了值和 TTL。外面老的缓存还在按旧 TTL 倒数。
怎么看:
# 直接查权威,立刻能看到新值
dig yourdomain.com @ns1.your-dns-provider.com +short
# 查公共 resolver,有的新有的旧
dig yourdomain.com @8.8.8.8 +short
dig yourdomain.com @1.1.1.1 +short
dig yourdomain.com @9.9.9.9 +short
# 看缓存里 TTL 的倒数
dig yourdomain.com @8.8.8.8
# 看 ANSWER SECTION 里 TTL 那一列,就是剩余秒数
如果权威已经返回新值,但公共 resolver 还返回旧值,那就是旧 TTL 还没走完。
修复: 没有现场补救,只能等。下次提前 24 小时降 TTL。你可以手动加速两大公共 resolver:
- Google:dns.google/cache——填名字、选记录类型(RR Type)、过一下验证码。不需要 Google 账号;有频率限制,同一个名字/类型不能连续刷两次。
- Cloudflare:one.one.one.one/purge-cache/(或
1.1.1.1/purge-cache/)——可选 A、AAAA、CNAME、MX、NS、TXT 等类型,purge 几秒内就推送到 Cloudflare 所有数据中心。注意:1.1.1.1最长缓存 3 小时,但你设了更短的 TTL 它会遵守。
这两个只动这两个 resolver,碰不到用户家的 ISP,所以是削长尾,不是搞定全世界。
情况 2:DNS provider 偷偷封顶 / 无视你设的 TTL
某些注册商自带的 DNS 不会按你填的 TTL 来对外服务。这里其实有两件不同的事,值得分开看:
- 有个最低限。 有些控制台不接受低于某个固定值。截至 2026 年 6 月,GoDaddy 的 DNS 管理器把 TTL 最低封在
600(10 分钟);Cloudflare 的 DNS-only 记录可以低到60(企业版30);Cloudflare 代理记录则固定钉死在300,根本不能改。如果你的面板不让填300,就用它能填的最低值——600也比86400强太多。 - 静默覆盖。 较老的共享 DNS(部分老 Namecheap / Bluehost 捆绑 DNS)会在 UI 上显示一个值、权威实际却返回一个更大的值。
怎么看:
# 权威实际对外服务的 TTL 是多少?
dig yourdomain.com @<authoritative-ns> | grep -E "^yourdomain"
# 中间那个数字就是 TTL(秒),跟 UI 上的值对比。
UI 显示 300 但 dig 显示 3600+,就是 provider 在覆盖你。
修复: 换一个严格尊重 TTL 的 DNS 托管(Cloudflare、AWS Route 53、Google Cloud DNS、NS1、DNSimple、deSEC)。如果暂时不能换,就接受封顶,每次变更至少提前一个完整 TTL 周期计划。
情况 3:负缓存(NXDOMAIN TTL)让新子域名迟迟不解析
你第一次加 blog.example.com,结果还是不解析。这不是 A 记录的 TTL,是 SOA minimum TTL,它(按 RFC 2308)控制 resolver 把 NXDOMAIN(“不存在”)回应缓存多久。负缓存的实际寿命取 SOA minimum 字段和 SOA 记录自身 TTL 里更小的那个。
怎么看:
dig SOA yourdomain.com +short
# 输出格式: ns1... admin... serial refresh retry expire minimum
# 最后一个数字就是负缓存 TTL
# 是 86400 的话,NXDOMAIN 最长被缓存一天
修复: 在 provider UI 上降低 SOA minimum 字段(界面里可能叫 “Negative TTL” 或 “NXDOMAIN TTL”)。Cloudflare 和 Route 53 默认值就很低(Cloudflare 用 1800);有些老 zone 还带着 86400。如果你正要加子域名,等它建好之后再查一次,别在建好前查——建好前那次查询正是把 NXDOMAIN 种进缓存的元凶。
情况 4:DNS 前面挂了 CDN / 代理层
Cloudflare 的代理模式(橙云)会用自己的 anycast IP、给外面发一个固定 300 秒的 TTL,并且完全无视你的 origin TTL。Vercel 和 Netlify Edge 各有自己的缓存。
怎么看: dig yourdomain.com +short 返回的是 Cloudflare 的 IP(104.x.x.x 或 172.x.x.x),不是你的源站。那些 IP 上对外的 TTL 都很短,但 Cloudflare 的内部回源遵循他们自己的规则。
修复: 一旦 Cloudflare 挂在前面,DNS 层的 TTL 就不重要了——他们大约 30 秒就在边缘把源站切完。如果你真正抱怨的是”用户还看到旧站点”,那是 HTTP 缓存不是 DNS。从 Cloudflare 仪表盘清缓存(Caching → Purge Everything),或用 cache-purge API。
最短修复路径(下一次变更前用)
真正的修复是流程性的,不是补救式的。任何计划中的 DNS 变更前 24 小时跑这一套:
-
24 小时前:在权威 DNS provider 上,把你打算改的每一条记录的 TTL 从当前值(往往
3600或86400)降到300——如果 provider 不接受300就用它的最低值。值先不动,保存。 -
等旧 TTL 走完。旧 TTL 是
3600就至少等 1 小时;是86400就等 24 小时。从这之后,所有缓存都会在300秒内刷新一次。 -
再做真正的变更(改新值,TTL 还是
300)。 -
跨 resolver 验证:
for resolver in 8.8.8.8 1.1.1.1 9.9.9.9 208.67.222.222; do echo "@$resolver: $(dig yourdomain.com @$resolver +short)" done4 个 resolver 都应该在 5 分钟内返回新值。
-
第二天:把 TTL 升回
3600或更高,降低 DNS 查询压力,提高缓存命中率。
怎么确认真的修好了
# 权威 TTL(DNS provider 发出去的)
dig yourdomain.com @<authoritative-ns> | awk '$1=="yourdomain.com." {print $2; exit}'
# 公共 resolver 缓存里的 TTL 倒数(每次查询都在变)
dig yourdomain.com @8.8.8.8 | awk '$1=="yourdomain.com." {print $2; exit}'
# 60 秒后再查一次 —— 应该减少约 60
sleep 60
dig yourdomain.com @8.8.8.8 | awk '$1=="yourdomain.com." {print $2; exit}'
有两个信号说明切换彻底完成:
- 倒数突然跳回完整 TTL、而不是继续减少——说明那个 resolver 刚回权威拿了新答案,旧的过期了、新值缓存进来了。从这一刻起,用这个 resolver 的所有用户都看到新值。
- 公共 resolver 的
+short值和权威的值一致。想看四个 resolver 之外的全球视角,用 whatsmydns.net 这类多地区检测,能看到各大洲一排绿勾。
预防
- 把 TTL 当成维护前要拧低的旋钮。 设一个日历提醒:“T-24h: 把 TTL 降到 300”。然后变更。再 “T+24h: 升回 3600”。
- 经常改的记录(预览环境、staging、A/B 测试 endpoint)长期保持 TTL
300,查询负载基本可以忽略。 - 几乎不会动的记录(根 MX、SPF TXT、DKIM TXT)TTL 设到
86400,缓存命中率更高,DNS provider 偶尔抽风也更稳。 - 不要同时改 TTL 和记录值。 没有意义。决定缓存寿命的,是上一次的 TTL 和上一次的值。
- 挑一个尊重 TTL 的 DNS provider。 Cloudflare、Route 53、Google Cloud DNS、NS1、DNSimple 都严格遵守。便宜注册商捆绑的 DNS 经常不遵守。
这些情况不是你的问题
- 用户 ISP 有自己的缓存层,无视权威 TTL,按固定周期缓存(少见,但部分 Comcast 和亚洲 ISP 有记录)。
- 公司防火墙 / WAF 单独缓存 DNS。
- 浏览器层的 DoH 配置和操作系统 resolver 缓存是分开的。
- 用户在
/etc/hosts里钉死了这个主机,根本不走 DNS 了。
这几种你都没法控。能做的就是告诉用户预期的传播窗口,然后继续走。
FAQ
问:生产环境的长期 TTL 多少合适?
答:3600(1 小时)是”紧急时还能改”的最佳点。86400(1 天)适合永远不动的记录。300(5 分钟)只在计划变更期间、或每周都改的 endpoint 上用。
问:降低 TTL 会影响性能吗?
答:影响很小。每次缓存 miss 多一次 DNS 回程(~20ms),而且只是该 resolver 区域里第一个用户。哪怕 TTL 300,繁忙 resolver 的命中率仍稳稳在 99% 以上,影响微乎其微。3600 影响更小。
问:我的 provider 不让我把 TTL 设到 600 以下,有问题吗?
答:没问题。截至 2026 年 6 月,GoDaddy 把 TTL 最低封在 600 秒;那也比 86400 快 144 倍。先把 TTL 降到 600,等至少一个完整旧 TTL 周期,再改记录。想更短的话,Cloudflare 的 DNS-only 记录能低到 60。
问:Cloudflare 代理说 TTL 是 “Auto”,什么意思?
答:记录被代理(橙云)时,Cloudflare 用自己的 anycast IP 加固定 300 秒 TTL 发给外面,且这个 “Auto” 不能改。你设的 TTL 对外不重要,但 Cloudflare 自己边缘在源站变更后约 30 秒就更新。DNS-only(灰云)记录就按你设的 TTL 来。
问:能强制让 resolver 清缓存吗?
答:基本不行。你只能清自己机器的,也可以让用户清。公共 resolver 不会因为你的请求就 flush——但有两个大例外:Google 的 dns.google/cache 能从 8.8.8.8 清掉某个特定名字,Cloudflare 的 one.one.one.one/purge-cache/ 对 1.1.1.1 同理。对变更后那 1% 死磕看旧值的用户管用。
问:我已经降了 TTL,但变更还是慢。
答:你今天降 TTL、今天又改记录。决定缓存里旧值寿命的是旧的 TTL。如果旧 TTL 是 86400,要等 24 小时让缓存全部刷掉。之后的变更才会很快。