DNS 传播为什么不同地区看到不一样

改完 DNS 本机 dig 出新值、同事打不开、海外刷新忽新忽旧——这不是 bug 是设计。本文讲清楚 TTL 倒计时机制,并给一套提前降 TTL 把生效窗压到可控的修复路径。

你在 Cloudflare / GoDaddy / Route 53 改完一条 A 记录或 CNAME,本机 dig 看到新值,公司同事还在打不开,海外朋友刷新一次新一次旧——这不是 bug,是 DNS 的设计。全球数万递归解析器各自按 TTL 倒计时,必须等老缓存过期才会回源拉新值,没有”立即生效”这种东西。本文先解释为什么不同地区结果不一致,再给一条把”等多久”压到可控范围的修复路径。

常见原因

按命中率从高到低。

1. 旧 TTL 还在递归解析器里倒计时

如果改之前那条记录的 TTL 是 3600 秒(1 小时),那么在你改完的那一刻,全世界已经缓存它的解析器会按各自剩余的秒数继续返回旧值——最坏情况是改完前 1 秒被缓存,整整 1 小时才轮到失效。

$ dig +short yourdomain.com @8.8.8.8
76.76.21.21      # 新值(Vercel)

$ dig +short yourdomain.com @1.1.1.1
185.199.108.153  # 旧值(GitHub Pages)— Cloudflare 缓存还没过期

如何判断:用 dig @<不同 resolver IP> yourdomain.com 轮询 8.8.8.8 / 1.1.1.1 / 9.9.9.9 / 114.114.114.114,结果不一致就是 resolver 缓存差异。

2. ISP 解析器不尊重你的 TTL

部分电信运营商(特别是中国大陆、印度、东南亚)的递归解析器会强制把所有记录的 TTL 抬到 1–24 小时以节省回源开销,无论 authoritative 那边设的是多少。

如何判断:用 dig +noall +answer yourdomain.com 看返回里 TTL 数值——如果远高于你 authoritative 设的值,就是被运营商重写了。

3. 同时存在多个 authoritative DNS 源

域名注册商默认 NS 没改、但你已经把 zone 搬到了 Cloudflare;或者历史上加过 GoDaddy + Cloudflare 双重托管。不同 resolver 命中不同 authoritative,自然给出不同答案。

如何判断

dig +short NS yourdomain.com
# 期望看到一组 NS(比如全部 *.ns.cloudflare.com)
# 出现混合厂商就是多源

4. 本机 / 浏览器 / 操作系统层缓存

macOS 的 mDNSResponder、Linux 的 systemd-resolved、Chrome 内置的 host cache,都会再缓存一层。你 authoritative 已经更新、resolver 也已经刷新,本机这层还在用旧值。

如何判断dig 命令绕开本机 stub resolver 直接问公网 8.8.8.8 已经是新值,但浏览器仍然连旧 IP——本机缓存的可能性最大。

5. CDN / load balancer 在 DNS 之上做了 GeoDNS

Cloudflare、AWS Route 53 latency-based routing、Vercel Anycast 会按用户地理位置返回不同 IP——这本身就是设计,但容易被误判成”传播不一致”。

如何判断:用 https://dnschecker.org 看各地区返回的 IP 是不是都是同一家厂商的不同 PoP;如果是,正常。

最短修复路径

DNS 传播没法”加速”,但可以做到:先确认 authoritative 正确、再用工具看清传播进度、最后让本机立即生效。

Step 1:先验证 authoritative 已经更新

直接问域名的 NS,跳过所有 resolver 缓存:

# 找出当前的权威 NS
dig +short NS yourdomain.com
# 例如返回 ns1.vercel-dns.com.

# 直接问权威,必须返回新值
dig +short yourdomain.com @ns1.vercel-dns.com

如果这一步还是旧值,说明记录根本没改成功——回控制台核对一遍,特别注意末尾的 .(CNAME 必须以 . 结尾的 FQDN)。

Step 2:用 dnschecker 看全球传播进度

打开 https://dnschecker.org,输入域名,看到一张地图:

比例含义
< 30% 节点已更新还在早期,可能只过去几分钟
50–80%正常推进,再等一个 TTL 即可
> 80% 但某地区始终旧那个地区的 ISP resolver 在硬扛 TTL

如果大多数地区已经返回新值、只有零星节点旧,就属于正常推进中。

Step 3:清本机各层缓存让自己先看到

# macOS
sudo dscacheutil -flushcache && sudo killall -HUP mDNSResponder

# Linux (systemd-resolved)
sudo resolvectl flush-caches
# 或老版本
sudo systemd-resolve --flush-caches

# Windows (PowerShell as admin)
ipconfig /flushdns

Chrome 单独有一层:地址栏访问 chrome://net-internals/#dns → “Clear host cache”,再到 #sockets → “Flush socket pools”。

Step 4:暂时绕开自己 ISP 的 resolver

把系统 DNS 改成 1.1.1.1 或 8.8.8.8(这两家 TTL 处理最规矩),重启浏览器再试:

# macOS 临时改
networksetup -setdnsservers Wi-Fi 1.1.1.1 8.8.8.8
# 恢复
networksetup -setdnsservers Wi-Fi empty

Step 5:等满一个旧 TTL

记下你改记录时 authoritative 上一版的 TTL(在注册商面板能查历史)。从改动时刻开始等满那个时间——常见值 300s / 1800s / 3600s。如果你不知道,按 1 小时等。等满之后绝大多数 resolver 都会回源。

下一次迁移前一天先把 TTL 降到 300s,迁完观察 24 小时再升回 3600s,可以把”等多久”从 1 小时压到 5 分钟。

预防建议

  • 计划迁移前 24–48 小时先把对应记录 TTL 降到 300s,迁完观察 1 天再升回去。
  • DNS 只保留一个权威来源:在 GitHub 或 Terraform 里管 zone 文件,杜绝双家托管。
  • CNAME 记录始终用 FQDN(末尾带 .),避免被解析成 foo.example.com.example.com
  • 上线前用 dig +trace yourdomain.com 走完整 root → TLD → authoritative 链路,确认没有 lame delegation。
  • 维护一个”DNS 健康检查” cron:每 5 分钟 dig @8.8.8.8 @1.1.1.1 @9.9.9.9 对比结果,不一致就告警。

相关阅读

标签: #部署 / 托管 #排查 #排查 #DNS