在GitHub,我们最近从头开始改进了DNS。这包括我们如何与外部DNS提供商交互以及我们如何在内部向我们的主机提供记录。为此,我们必须设计和构建一个新的DNS基础设施,该基础设施可以随着GitHub的发展扩展并跨越多个数据中心。以前,GitHub的DNS基础设施相当简单。它由每台服务器上的本地、仅用于转发的DNS缓存服务器以及所有这些主机使用的一对缓存和权威服务器主机组成。这些主机在内部网络和公共Internet上都可用。我们在缓存守护进程中配置了区域存根以在本地进行查询,而不是在Internet上递归查询。我们还在我们的DNS提供商处设置了NS记录,这些记录将特定的内部域指向该对的公共IP,以供来自我们网络外部的查询。这种配置已使用多年,但并非没有缺点。许多程序对解析DNS查询非常敏感,我们遇到的任何性能或可用性问题最好的情况下会导致服务排队和性能下降,最坏的情况下会导致客户体验中断。配置和代码更改可能会导致查询率发生意外的大变化。因此,扩展到这两个主机之外成为一个问题。由于这些主机的网络配置,如果我们只是不断添加IP和主机,它本身会存在一些问题。在尝试解决和补救这些问题时,遗留系统由于缺乏指标和可见性而难以确定问题的原因。在许多情况下,我们使用tcpdump来识别有问题的流量和查询。另一个问题是在公共DNS服务器上运行,我们有泄露内部网络信息的风险。所以我们决定构建更好的东西,并开始定义我们对新系统的要求。我们着手设计一个新的DNS基础设施,以改善上述操作问题,包括扩展性和可见性,并引入了一些额外的要求。我们希望通过外部DNS提供商继续运行我们的公共DNS域,因此我们构建的系统需要与供应商无关。此外,我们希望系统同时为我们的内部域和外部域提供服务,这意味着内部域仅在我们的内部网络上可用,除非另有特别配置,并且无需离开我们的内部网络即可解析外部域。我们希望新的DNS架构不仅会根据部署工作流程进行更改,而且还会通过我们的存储库和配置系统使用API自动更改DNS记录。新系统不能有任何外部依赖,过度依赖DNS功能会导致级联故障,这包括与其他数据中心的连接以及它们内部可能的DNS服务。我们的遗留系统在同一主机上混合了缓存和权威服务器。我们希望转向具有独立角色的分层设计。***,我们希望系统支持多数据中心环境,无论是EC2还是裸机。实现为了构建这个系统,我们确定了三种类型的主机:缓存主机、边缘主机和权威主机。缓存主机充当递归解析器和DNS“路由器”以缓存来自边缘层的响应。边缘层运行DNS权威守护进程以响应缓存层对DNS区域的请求,该区域被配置为来自权威层的区域传输。权威层充当隐藏的DNS主机,充当DNS数据的规范来源,服务于边缘主机的区域传输,并提供用于创建、修改或删除记录的HTTPAPI。在我们的新配置中,缓存主机存在于每个数据中心,这意味着应用程序主机不需要跨越数据中心边界来检索记录。缓存主机配置为将区域区域映射到其区域内的边缘主机,以便将我们的内部区域路由到我们自己的主机。任何未明确配置的区域都将通过Internet递归解析。边缘主机是存在于我们网络边缘PoP(存在点)中的区域主机。我们的PoP有一个或多个数据中心依赖它们进行外部连接,没有PoP数据中心将无法访问互联网,互联网也无法访问它们。边缘主机向所有权威主机执行区域传输,无论它们存在于哪个区域或位置,并将这些区域存储在本地磁盘上。我们的权威主机也是区域主机,仅包含适用于其区域的区域。我们的仓库和配置系统确定区域存储在哪个区域权限主机,并通过HTTPAPI服务创建和删除记录。OctoDNS将区域映射到地理权威主机,并使用相同的API创建静态记录并保持动态源同步。对于外域(比如github.com),我们有另外一个独立的权威主机来让我们在宕机时查询我们的外域。所有记录都存储在MySQL中。迁移到更现代的DNS基础设施的一个巨大好处是可观察性。我们的旧DNS系统几乎没有指标和有限的日志。决定使用哪个DNS服务器的一个重要因素是它们生成的指标的广度和深度。我们最终使用Unbound作为缓存主机,NSD作为边缘主机,PowerDNS作为权威主机,所有这些都在比GitHub大得多的DNS基础设施上得到证明。当在我们的裸机数据中心运行时,缓存通过私有任播IP访问,允许它到达最近的可用缓存主机。缓存主机以机架感知方式部署,在它们之间提供一定程度的负载平衡,并隔离某些电源和网络故障模式。当缓存主机出现故障时,通常用于DNS查询的服务器现在将自动路由到下一个最近的缓存主机,以保持低延迟并为某些故障模式提供容错能力。Anycast允许我们扩展单个IP地址背后的缓存数量,这与以前的配置不同,允许我们运行DNS需要的缓存主机。无论地理位置如何,边缘主机都使用权威层进行区域传输。我们的区域不是很大,以至于在每个区域中保留所有区域的副本成为一个问题。(LCTT译注:原文在这里“Ourzonesarenotlargeenoughtokeepingacopyofallthemineveryregionisaproblem.”,根据上下文理解翻译。)这意味着对于每个区域,甚至是某个区域离线,或者与上游服务提供商存在连接问题,所有缓存服务器都可以访问具有所有区域本地副本的本地边缘服务器。事实证明,这一变化在面对连接问题时非常有弹性,并有助于在不久前导致客户面临中断的中断期间保持GitHub可用。这些区域传输包括来自其各自权威服务器的内部和外部域的传输。您可能会猜到,像github.com这样的区域是外部区域,而像github.net这样的区域通常是内部区域。它们之间的区别仅在于我们使用的类型和它们存储的数据。了解哪些区域是内部区域和外部区域可以让我们在配置中具有一定的灵活性。$dig+shortgithub.com192.30.253.112192.30.253.113publiczone同步到外部DNS提供商,是GitHub用户日常使用的DNS记录。此外,公共域可在我们的网络内完全解析,无需与我们的外部提供商通信。这意味着任何需要查询api.github.com的服务都可以在不依赖外部网络连接的情况下这样做。我们还使用Unbound的stub-first配置选项,如果我们的内部DNS服务由于某种原因无法进行外部查找,它会为我们提供第二次查找。$dig+shorttime.github.net10.127.6.10github.net区域的大部分是完全私有的,无法从互联网访问,它仅包含RFC1918中指定的IP地址。每个区域和站点都分为私有区域。每个区域和/或站点都有一组适用于该位置的子区域,子区域用于管理网络、服务发现、特定服务记录,还包括我们存储库中的配置主机。私有区域还包括PTR反向查找区域。总结用新系统替换为数百万客户提供服务的旧系统并不容易。使用务实的、基于需求的方法来设计和实施我们的新DNS系统,使DNS基础设施能够快速高效地运行,并有望与GitHub一起成长。想帮助GitHubSRE团队解决有趣的问题吗?我们希望你能加入我们。在这里申请。
