性能优势

简介:DNS 延迟的原因和缓解

随着网页变得越来越复杂,引用来自多个网域的资源,DNS 查找可能会成为浏览体验的重要瓶颈。每当客户端需要通过网络查询 DNS 解析器时,引入的延迟时间可能很长,具体取决于解析器要查询的域名服务器的近程和数量(超过 2 个,但这种情况很常见)。例如,以下屏幕截图显示了 Page Speed 网页性能测量工具报告的时间。每个条形都表示从网页引用的资源;黑色部分表示 DNS 查询。在此页面中,在网页加载的前 11 秒内进行 13 次查询。虽然有几次查询是并行执行的,但屏幕截图显示需要 5 次串行查找时间,约为网页加载时间 11 秒的几秒钟。

DNS 延迟时间有两个组件:

  • 客户端(用户)与 DNS 解析服务器之间的延迟时间。 在大多数情况下,这主要是由于联网系统中通常的往返时间 (RTT) 限制造成的:客户端与服务器之间的地理距离;网络拥塞;丢包和长重新传输延迟(平均一秒);超载服务器、拒绝服务攻击等。
  • 解析服务器与其他域名服务器之间的延迟时间。 造成这种延迟的主要原因是以下因素:
    • 缓存未命中。 如果无法从解析器的缓存中提供响应,但需要以递归方式查询其他域名服务器,那么增加的网络延迟时间将相当长,尤其是在权威服务器位于地理位置偏远的情况下。
    • 预配不足。 如果 DNS 解析器过载,它们必须将 DNS 解析请求和响应加入队列,并且可能会开始丢弃并重新传输数据包。
    • 恶意流量。 即使 DNS 服务超额预配,DoS 流量也可能会在服务器上产生不必要的负载。同样,Kaminsky 式攻击可能还包含泛滥解析器,这些查询肯定会绕过缓存并需要传出请求以解决问题。

我们认为缓存未命中是导致 DNS 延迟的最常见原因,下文会详细讨论。

缓存未命中

即使解析器有丰富的本地资源,与远程域名服务器通信时发生的基本延迟也很难避免。换言之,假设解析器的预配足够好,使得缓存命中在服务器端花费的时间为零,因此在延迟时间方面,缓存未命中的成本非常高。为应对未处理的情况,解析器必须与至少一个(但通常两个或两个以上的)外部域名服务器通信。 运行 Googlebot 网页抓取工具后,我们发现响应的域名服务器的平均解决时间为 130 毫秒。但是,由于 UDP 数据包丢失且服务器无法访问,因此 4-6% 的请求完全超时。 如果我们考虑了丢包、域名服务器无效、DNS 配置错误等失败情况,那么实际的端到端平均解决时间为 300 到 400 毫秒。但是,差异很大并且存在长尾。

虽然缓存未命中率可能会因 DNS 服务器而异,但缓存未命中从根本上很难避免,原因如下:

  • 互联网规模和增长。 简单来说,随着互联网的发展(无论是通过添加新用户还是新网站),大多数内容都只是边际兴趣。虽然少数网站(因此是 DNS 名称)非常受欢迎,但大多数网站只对少数用户感兴趣,很少被访问;因此大多数请求会导致缓存未命中。
  • 存留时间 (TTL) 值较低。 DNS TTL 值偏低的趋势意味着解析需要更频繁地查找。
  • 缓存隔离。 DNS 服务器通常部署在负载平衡器后面,而负载平衡器会将查询随机分配给不同的机器。这会导致各个服务器维护单独的缓存,而不是能够重复使用共享池中的缓存分辨率。

缓解措施

在 Google 公共 DNS 中,我们实施了几种缩短 DNS 查找时间的方法。其中一些方法比较标准;还有一些方法尚处于实验阶段:

  • 充分配置服务器来处理来自客户端流量(包括恶意流量)的负载。
  • 防范 DoS 和扩散攻击。 虽然这主要是一个安全问题,但对关闭的解析器的影响小于开放解析器,但通过消除 DNS 服务器造成的额外流量负担,防止 DoS 攻击对性能也有好处。如需了解我们为了尽量降低遭到攻击的可能性而采用的方法,请参阅关于安全优势的页面。
  • 实现共享缓存的负载均衡,以提高整个服务集群的汇总缓存命中率。
  • 覆盖全球所有国家/地区

充分预配服务集群

缓存缓存 DNS 解析器必须执行比权威域名服务器更高的操作,因为许多响应无法从内存传送;相反,它们需要与其他域名服务器通信,因此需要大量的网络输入/输出。此外,开放式解析器很容易受到缓存投毒尝试的影响,这会增加缓存未命中率(此类攻击会专门针对无法从缓存中解析的虚假名称发送请求)以及 DoS 攻击(会增加流量负载)。如果解析器预配不足,导致跟不上负载,这可能会对性能产生非常负面影响。数据包被丢弃并需要重新传输,域名服务器请求需要排队等。所有这些因素都会加重延迟。

因此,请务必将 DNS 解析器配置为大批量输入/输出。 这包括处理可能的 DDoS 攻击,其唯一有效的解决方案是为多台机器过度预配。但是,同时添加机器时不要降低缓存命中率;这需要实施有效的负载均衡政策,我们将在下文讨论。

用于共享缓存的负载均衡

如果未能正确实现负载均衡,通过添加机器来扩缩解析器的基础架构实际上可能会适得其反,并降低缓存命中率。在典型的部署中,多个机器位于负载平衡器后,使用轮询等简单算法将流量平均分配给每台机器。其结果是每台机器都会维护自己的独立缓存,以便缓存内容在各机器之间实现隔离。如果每个传入查询分布到一个随机机器,则根据流量的性质,有效缓存未命中率可能会按比例增加。例如,对于反复查询较长 TTL 的名称,缓存未命中率可能会根据集群中的机器数量增加。(对于 TTL 非常短的名称,查询频率极低或导致不可缓存响应(0 TTL 和错误),添加机器时缓存未命中率不会受到实际影响。)

为了提高可缓存名称的命中率,必须对服务器进行负载均衡,以免缓存碎片化。在 Google 公共 DNS 中,我们有两个缓存级别。在一台非常靠近用户的机器池中,每台机器的小缓存中包含最常用的名称。如果此缓存无法满足某个查询,则会将其发送到按名称对缓存进行分区的另一台机器池。对于此第二级缓存,系统会将所有同名查询发送到同一台机器,并缓存其中的名称。

分发服务集群以实现广泛的地理位置覆盖

对于封闭式解析器,这实际上不是问题。对于开放式解析器,服务器离用户越近,客户端看到延迟就越少。此外,有足够的地理覆盖范围还可以间接缩短端到端延迟时间,因为域名服务器通常会返回针对 DNS 解析器位置优化的结果。也就是说,如果内容提供程序托管镜像的网站遍布世界各地,则该提供商的域名服务器将返回最接近 DNS 解析器的 IP 地址。

Google 公共 DNS 托管在全球各地的数据中心,并使用任播路由将用户引导至地理位置最近的数据中心。

此外,Google 公共 DNS 支持 EDNS 客户端子网 (ECS),这是解析器可将 DNS 协议转发到域名服务器的 DNS 协议,该扩展可以返回针对实际客户端 IP 地址(而不是解析器的 IP 地址)优化的对位置敏感的响应。如需了解详情,请参阅此常见问题解答。 Google 公共 DNS 会自动检测支持 EDNS 客户端子网的域名服务器