DNS TTL 与故障切换:一次误判的复盘
几个月前我们做过一次“提高故障切换速度”的改造:把业务域名的 TTL 从 3600 秒降到 60 秒。按理说,主节点挂掉之后,最多一分钟客户端就该解析到备用节点。实际演练时,部分用户的恢复时间超过了十五分钟。这篇记录我们后来查到的原因。
假设
最初的假设非常朴素:TTL 决定缓存时间,TTL 小,缓存过期快,切换就快。这个模型忽略了三件事:
- 递归解析器不一定会严格遵守 TTL,尤其是开启了“缓存优化”的公共 DNS;
- 客户端和 CDN/网关之间的长连接不会因为 DNS 变化而重建;
- 操作系统的 stub resolver 自己还有一层缓存。
查到的证据
1. 递归解析器的缓存
我们在切换前后用多个公共 DNS 分别查询,发现有的解析器在 TTL 到期后仍然返回旧记录,延迟几秒到几十秒不等;还有的解析器在 TTL 之外叠加了自己的最小缓存时间。也就是说,60 秒的 TTL 实际生效时间可能是 90 秒甚至更久。
2. 连接复用掩盖了 DNS 变化
这是影响最大的一点。移动端 SDK 和网关之间维持着 HTTP/2 长连接,DNS 解析结果只影响新连接的建立。故障发生时,旧连接在 TCP 层已经死了,但客户端要等到读写超时才会重建连接——这个超时设置是 30 秒,重试还有退避。DNS 再快也没用。
3. stub resolver 的 negative cache
故障期间我们把记录短暂摘除过,结果部分客户端缓存了 NXDOMAIN,恢复后仍然解析失败。后来改成直接把记录指向备用地址,而不是删除记录,问题才消失。
改了什么
- TTL 保持在 120 秒,不再追求极端的 60 秒——收益有限,反而增加了权威 DNS 的查询压力;
- 客户端把连接空闲超时从 30 秒降到 10 秒,并在连续失败时主动重建连接;
- 切换流程从“删记录再加记录”改成“改记录指向”,避免 NXDOMAIN 被缓存;
- 增加了从多个地理位置对权威 DNS 的主动探测,切换后验证而不是假设。
结论
DNS 只是故障切换链路里的一环,而且往往不是最慢的那一环。真正决定恢复时间的是客户端的连接管理和重试策略。把 TTL 当成开关,是一种很常见的错觉。
复盘的价值不在于找到“是谁的错”,而在于修正那个过于简单的模型。我们原来的模型里,只有 DNS 一个变量。