2859 字
约 9 分钟
18
S02-A13 · DNS 变更的生效与回退:为什么"改了却没变"

一次迁移把域名 A 记录从旧机房指向新机房,改完之后一部分用户访问新站,一部分还是旧站,持续了整整两天。第三天有人把 TTL 从 3600 调到 60,说"这样以后就好办了"——但已经发出去的那批 3600 秒记录,还在各地递归服务器上缓存着。

DNS 变更是少数"改了之后不听你指挥"的操作:你控制的是权威记录,用户用的是缓存副本。中间隔着运营商的递归服务器、终端系统的缓存、以及应用自己实现的缓存,每一层都按自己的规则保留一段时间。


1. 一条记录的传播路径

层级 缓存依据 谁能控制
浏览器/系统 各系统自己的策略,可能忽略 TTL 终端用户
本地递归服务器(运营商) TTL,且常设最小值下限 运营商
公共 DNS TTL 与自身策略 服务商
权威服务器 无缓存,直接返回 你

最后一列是全部事实:只有权威服务器在你说了算的范围内。前三层的保留时间由"TTL"与"对端是否遵守 TTL"共同决定。

判断一次解析结果来自哪一层,有个很直接的命令:dig 的输出里有一个"已缓存时长"字段,它告诉你这条记录在这台服务器上存在了多久。

// 看缓存来源与已缓存时长(第二个数是 TTL 剩余,第三个是原始 TTL)
dig www.example.com A +noall +answer
// www.example.com. 2841 IN A 203.0.113.10
// 剩余 2841 秒,若原始 TTL 是 3600,说明这条记录已被缓存了 759 秒

这解释了一个常见困惑:TTL 设成 60 秒,为什么还有用户访问旧站两小时。因为部分递归服务器会对短 TTL 设下限(比如不低于 300 秒),而某些终端会忽略 TTL 直接缓存到进程重启。

2. 变更前必须做的一件事:降 TTL

正确顺序不是"改完再降 TTL",而是先降 TTL、等一个旧 TTL 周期、再改记录。

步骤 时间点 目的
1. 把 TTL 降到 60 T-24 小时 让旧缓存尽快过期
2. 等待旧 TTL 走完 T-24 到 T 确保各地缓存里的都是短 TTL 记录
3. 修改记录指向 T 此时传播窗口是分钟级
4. 观察流量切换 T 之后数小时 确认新站承接
5. 恢复原 TTL T+24 小时之后 减少权威服务器压力

第二步是关键,也最常被跳过:在还没降 TTL 的时候就改了记录,等于用旧的、可能是几小时的 TTL 在传播这次变更。降 TTL 的动作本身也要经过这个传播周期才生效,所以它必须提前做。

// 变更前核对:各公共 DNS 看到的 TTL 是否已经降下来
for r in 8.8.8.8 1.1.1.1 223.5.5.5 114.114.114.114; do
  echo -n "$r  "
  dig +noall +answer @$r www.example.com A | awk '{print $2"s", $5}'
done
// 第二列是当前缓存剩余 TTL;若仍是 3600,说明降 TTL 尚未传播完,不要动记录

3. 为什么会出现"一半新一半旧"

原因 机制 表现
缓存未过期 各地 TTL 起算时间不同 分批切换,持续数小时
多记录并存 A 记录有多条,客户端轮询 新旧混合,看起来随机
双份配置 CDN 与源站各有一套解析 部分路径指向旧站
应用层缓存 服务端缓存了解析结果 即使 DNS 变了,连接仍连旧的
长连接未断 已建立的 TCP 连接不重新解析 老客户端持续连旧 IP

还有一个更隐蔽的原因:客户端自己的解析缓存。很多语言的 HTTP 客户端会缓存解析结果直到进程重启,容器里的长驻进程尤其明显。这类缓存不受 TTL 约束,也不体现在任何 DNS 查询日志里。

第五项最容易被忽略:DNS 只影响新建连接。已经建立的长连接会一直用到断开为止,所以"改完 DNS 之后旧机器还有流量"是正常的,需要主动断开或等连接自然回收。

// 确认旧机器上的流量是"新连接"还是"长连接残留"
ss -tn state established '( dport = :80 or dport = :443 )' | wc -l
ss -tn state established '( dport = :80 or dport = :443 )' | awk '{print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head
// 旧机房仍有大量 established → 长连接残留,考虑 graceful 关闭与连接迁移

4. 回退比变更更难

回退时最容易犯的错是"把记录改回去就完了"。但此时情况与变更前不同:新的 TTL 已经传播,旧的缓存可能还留着新指向。

阶段 变更时 回退时
缓存状态 全部指向旧值 新旧混杂
传播速度 受旧 TTL 限制 受当前 TTL 限制(通常更快)
副作用 新站需承接流量 旧站需重新承接,且可能有数据已写入新站
关联变更 通常无 往往已做了一串关联改动

回退预案里还有一条常被忘记的:回退期间的旧 TTL 也要重新考虑。如果变更时把 TTL 从 3600 降到了 60,回退后应该保持 60 一段时间再恢复,否则恢复动作本身又会制造一轮不可控的传播。

第三行是回退的真正难点:DNS 回退只把流量带回去,已经写在新环境里的数据不会自己回去。所以回退预案必须包含数据处理,而不只是解析记录。

5. 可靠变更的四个配套

配套 作用 最小实现
变更前快照 记录改前的完整区文件与 TTL 导出 zone 文件存档
灰度入口 先让一部分流量验证 权重解析或按地域解析
双写期 两个环境都能服务 旧站保留到观察期结束
观测口径 知道流量切换了多少 按来源 IP 段统计新旧站流量

这四项可以压成一份变更单,放在变更执行前逐项确认:

// DNS 变更单的六项,缺一项就不该执行
1. 当前 TTL 与降 TTL 的时间点(必须已传播完)
2. 改前 zone 快照路径(可回滚到精确状态)
3. 灰度方式(按权重 / 按地域 / 全量)
4. 新旧站同时可服务的确认(旧站保留到何时)
5. 观测口径(新旧流量各占多少,从哪看)
6. 回退触发条件与执行人(谁在什么指标下决定回退)

第六项的"执行人"要落到名字,且必须是变更窗口内在岗的人。

第五项"双写期"在网站迁移里常被简化成"旧站不关",但真正需要确认的是旧站能不能在切换后继续正确处理写入。如果旧站已经停止维护、或者它的数据不会被同步回主库,那么保留它只是在制造分叉。

第四项常被省略:切换过程中如果没有"新旧各占多少"的数字,就只能靠用户反馈判断。这个数字用两边的访问日志按时间聚合即可,不需要额外埋点。

6. 排错:五种"改了没生效"

现象 成因 处理方向
部分地区仍旧站 递归缓存未过期 核对各地 TTL 剩余时间
全部地区仍旧站 改的是错误区域/子域 用权威服务器直接查询验证
解析正确但访问失败 新站证书或端口未就绪 先验证直连 IP 与 SNI
邮件或验证码异常 只改了 A 记录,MX/TXT 未同步 检查全部记录类型
恢复 TTL 后又乱了一次 恢复动作本身触发新一轮传播 恢复也要按变更流程做

第二项要用权威服务器直接查,绕过所有缓存:

// 绕过缓存,直接问权威服务器
dig +norecurse @ns1.example.com www.example.com A
// 若权威返回新值而递归返回旧值 → 纯缓存问题,等待即可
// 若权威仍是旧值 → 改动没生效,检查区域文件与推送

// 追踪完整解析链,看是哪一层给了旧答案
dig +trace www.example.com A | tail -20
// 变更前一次性导出全部记录类型,避免遗漏
dig +noall +answer example.com ANY
dig +noall +answer _dmarc.example.com TXT
dig +noall +answer example.com MX
dig +noall +answer example.com CAA
// 把输出存档;迁移后逐条比对,缺的补上

第四项值得单列:DNS 变更往往只想着 A 记录,而 MX、TXT(SPF/DKIM/域名验证)、CAA 这些记录在迁移中经常被遗漏,症状是"网站正常但邮件发不出去"或"某个第三方验证失效"。

7. 边界:什么情况可以简化流程

场景 为什么 做法
内部域名,无外部解析 只有自己控制递归 直接改,无需降 TTL
无状态服务且可随时切回 回退成本低 保留旧站即可
已有全局流量管理(按权重) 切换在应用层完成 DNS 不动,改权重
测试域名、短生命周期 无真实用户 直接改

判断口径一句话:这次变更的回退是否需要搬数据。不需要,DNS 就是一个流量开关,流程可以简化;需要,它就是一个迁移项目,必须有观察期与数据处理方案。


8. 自测

  1. 四个层级里,哪一层是"你说了算"的?其余三层的保留时间由什么决定?
  2. 为什么必须先降 TTL 并等一个旧 TTL 周期,再改记录?跳过这一步会怎样?
  3. DNS 变更为什么只影响新建连接?旧机器仍有流量时,如何区分是缓存残留还是长连接残留?
  4. 回退与变更相比,多出哪两类难点?为什么"改回去就完了"不成立?
  5. 只改 A 记录会漏掉哪些记录类型?各自会导致什么症状?
  6. 判断一次 DNS 变更是否可以简化流程的关键问题是什么?
S02-A13 · DNS 变更的生效与回退:为什么"改了却没变"
https://www.clxhxhhr.top/posts/6397/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。