引子
前几天在网上冲浪的时候, 看到了一篇讲 DNS 的宝藏文章: DNS TTL Violations in the Wild.
之所以对我来说是宝藏文章, 因为在读了第一段以后, 我就发现了一个我习以为常的认知其实在实际是错误✖的: 业界都会遵守 DNS 的 TTL 超时逻辑。
然而实际上是: 业界都知道 DNS 的 TTL 超时逻辑,但不一定这么实现。
事件
前几周我们出了个 Bug, 影响了整个开发、测试环境。
我们有很大一块的业务是跟微信做各类 py 交易, 微信要求说我们给个回调域名, 每 10 分钟会推送一个凭证, 我们要用微信最新的凭证去调他们的接口。
最早我们给微信配的回调域名背后是个 AWS ELB, 这是一个亚马逊云上面的旧版负载均衡; 后来我们打算换成新版负载均衡 AWS ALB。
这个操作就很简单嘛, 到 DNS 服务商里看了一下, 微信回调的域名解析 TTL 是 600 秒, 又是开发测试环境; 于是我们直接把解析改到了新版负载均衡上, (出于省钱的想法)顺手还把旧的负载均衡给删了。
哦豁。 微信一天都没有给我们推授权凭证。 于是我们开发测试环境的微信功能挂了一天。
有的时候开发测试环境出问题, 会跟生产环境同样煎熬。 因为你会发现你身边的同事, 每隔 10 分钟就会问你: “弟啊,微信好了没有?”
疑问
改完 DNS 的 86400 秒以后, 微信又继续给我们推送凭证了。
根据现象判定是 DNS 的问题以后, 一边在心里鄙视微信, 一边也产生了疑问: “不科学啊,DNS 这么基础的服务,怎么会出 bug 呢?”
这就回到了本文开头讲的: 业界都知道 DNS 的 TTL 超时逻辑,但不一定这么实现。
每一条 DNS 记录都由两部分数据组成: 什么域名应该指向什么目的地? 我的有效时间是多久? 而这两部分数据会以互联网特有的树状结构层叠而上,盘织交错。 在终端进行 DNS 寻址时, 链路上的任何一个 DNS 服务器都可以实现一套标准或是非标的逻辑。
对于 TTL 这个值, 只有三种实现的逻辑:
- 缓存时间等于 DNS TTL 时间。
- 缓存时间小于 DNS TTL 时间。
- 缓存时间大于 DNS TTL 时间。
世界
要我来写域名服务器的逻辑的话, 不出意外我会严格按照定义来实现。 当然,根据性能、时间、空间的限制, 最终实现出来会有几秒的误差, 不过这不关键。
关键的是,有不少人觉得 DNS 目前的设计是有缺陷的。 而作为整个互联网的底层构架, 不论是要提升还是替换 DNS 目前的逻辑, 都是一个非常巨大的工程。 当然,这也更吸引工程师为此献身了。
于是,当今现实世界里的域名解析, 就不是完全按照“缓存时间等于 DNS TTL 时间”来实现的。
- 当缓存时间小于 DNS TTL 时间时
- 主要争议点在与这个会给上游服务器带来更大的解析压力
- 高频解析也意味着更多的带宽、网费支出
- 但这种情况不会伤害终端用户
- 当缓存时间大于 DNS TTL 时间时
- 主要的问题在于,这会让用户访问到错误的服务器
- 这不仅会带来逻辑错误,还会有潜在的安全隐患
- 在本文最开始出现的问题,其实就是微信的 DNS 链路上出现了缓存过旧的问题
- 好处可能就是在解析费上不用交那么多钱了(x
总结
总的来说,DNS TTL 是一个在互联网基础设施中广泛使用的约定。 但是现实世界中也会有很多非标的实现。 由于 DNS 的特殊性,每一个非标的域名商都会影响一大片他们能触达的用户。 所以在我们操作 DNS 时,要优雅的解决问题就也得把他们给考虑进来。
工程上的问题就是这样, 既有理论的优雅, 又有凡人的愚蠢, 也有分布式的智慧。
By design, the Internet core is stupid, and the edge is smart.
(完)