This post is also available in 简体中文.
对大规模运营而言,IP 寻址抑制了网络和 web 导向服务的创新。对于每一个架构更改,当然在开始设计新系统时,我们被迫问的第一组问题就是:
我们要用或可以用哪一段 IP 地址?
我们是否有足够的 IPv4 地址?如果没有,我们从哪里或如何获得地址?
我们如何使用 IPv6 地址,这是否会影响 IPv6 的其他用途?
对了,迁移需要什么周密的计划、检查、时间和人员呢?
不得已停下来并担忧 IP 地址问题是非常浪费时间、金钱和资源的。鉴于 40 多年前 IP 地址面世时就具有远见且富有韧性,这可能令人觉得意外。根据设计,IP 地址应该是任何网络必须考虑的最后一件事。然而,如果互联网暴露了任何东西,那就是,任何细小或看起来不重要的弱点——通常在设计时看不见或不可能看到——总是以足够大的规模出现。有一件事我们是知道的:“更多地址”永远不应该是答案。在 IPv4 中,这种想法只会加剧其稀缺性,进一步推高其市场价格。IPv6 是绝对必要的,但只是解决方案的一部分。
例如,在 IPv6 中,最佳实践称,最小的分配仅供个人使用,是 /56,也就是 272,即 4,722,000,000,000,000,000,000 个地址。我肯定无法理解那么大的数字。您可以吗?
在本博文中,我们会解释为什么 IP 地址会是 web 服务的一个问题,根本原因是什么,并说明一个我们称为“寻址敏捷性(Addressing Agility)”的创新解决方案,以及我们已经学到的经验教训。其中最好的部分可能是寻址敏捷性支持的各种新系统和架构。完整的细节可参阅我们最近在 ACM SIGCOMM 2021 发表的论文。作为预览,如下概述我们所学到的一些东西:
这是真的!任何一个地址上出现的名称数量是无限的;_在任何地方_任何名称的的地址可随每一次查询而变化;改变地址可能出于任何原因,可能是因为服务配置,策略或性能评估,或其他我们还没有遇到的原因……,
下面解释了为什么这一切都是真的,我们如何做到,以及为何这些教训对_任何规模_的 HTTP 和 TLS 服务都很重要。我们依据的关键洞察:在互联网协议(IP)设计中,就像全球邮政系统一样,地址从来没有,永远不应该,也绝不需要代表名称。只不过,我们有时对待它们的方式就像它们代表名称。相反,这项工作显示,所有名称都应该共享它们的所有地址,任何地址集,或甚至仅一个地址。
窄腰是一个漏洞,也是一个阻塞点。
数十年的约定人为将 IP 地址和名称、资源绑定起来。这是可以理解的,因为驱动互联网的架构和软件是从一台计算机拥有名称和(通常)拥有一个网卡的设定演变而来的。因此,互联网演变成一个 IP 地址与名称和软件进程相关联的状态就不足为奇了。
对最终客户端和网络运营商而言,由于很少需要名称和侦听进程,这些 IP 绑定的影响甚微。然而,名称和进程约定对_所有_内容托管、分发和内容服务提供商(CSP)造成了较大限制。一旦指定了名称、接口和套接字,地址就基本上成为静态,即使有可能更改,也需要经过计划并小心进行。
IP的“窄腰”使互联网成为可能,但就像 TCP 用于传输协议和 HTTP 用于应用协议一样,IP 已成为创新方面令人窒息的瓶颈。下图可以看到,分别的通信绑定(与名称)和连接绑定(与接口和套接字)在两者之间创建传递关系。
这种传递锁定难以打破,因为改变其中任一个都会影响到另一个。此外,服务提供商常常使用 IP 地址来代表策略和服务层,而这些策略和服务级别本身是独立于名称存在的。最终,IP 绑定是需要考虑的另一件事——而且这种做法并没有很好的理由。
让我们换一种说法。当考虑新的设计,新的架构,或者只是更好的资源分配时,第一组问题永远不应该是“我们使用哪些IP地址?”或者“我们有IP地址用于这个吗?” 诸如此类的问题及其回答会延缓发展和创新。
我们意识到,IP 绑定不仅是人为的,而且根据最初富有远见的 RFC 和标准,也是不正确的。事实上,IP 地址代表可达性以外的任何其他东西这一想法与其最初设计背道而驰。在最初的 RFC 和相关草稿中,架构是明确的,“名称指示我们寻找的东西。地址指示其所在位置。路由指示如何到达。” 任何将 IP 与更高层协议的 SNI 或 HTTP 主机关联的做法都是明显违反分层原则的。
当然,我们的任何工作都不是孤立存在的。但它确实完成了一个长期进行的演变,将 IP 地址与其传统用途脱钩,这个演变过程包括站在巨人的肩膀上。
回顾演变过程……
回望过去20年,不难看到,对寻址敏捷性的追求已经进行了一段时间,Cloudflare 也也在这个方面进行了大量投入。
IP 与网卡长达数十年的一对一绑定在几年前首次被打破: Google 的 Maglev 结合等价多路径(ECMP)和一致哈希值,从单一“虚拟” IP 地址在多个服务器之间传播流量。
自那以来,很多类似的系统在 GitHub、Facebook 和其他地方出现,包括我们自己的 Unimog。最近,Cloudflare设计了一种新的可编程套接字架构,称为bpf_sk_lookup,用于将 IP 地址与套接字和进程脱钩。
但哪些名称怎么处理呢?1997 年, HTTP 1.1 将主机字段定义为强制字段,确立了“虚拟主机托管”的价值。这是第一次正式承认多个名称可在单一 IP 地址上共存,并且必须由 TLS 在服务器名称指示(Server Name Indication)字段中复制。由于可能的名称数量超过 IP 地址的数量,这些要求都是绝对必要的。
……预示敏捷的未来
展望未来,莎士比亚曾经聪明的问道,“名字有什么意义呢?”如果当时互联网能够说话,它可能会说,“我们用任何其他地址标记的名字都是可以到达的。”
如果莎翁的问题改为,“地址有什么意义呢?”,那么互联网会以同样的方式回答,“我们用任何其他名称标记的地址都是可以到达的。”
以上答案中可以看出一个强烈的暗示:名称和地址之间的映射是任意对任意的。若然如此,任何地址都可以用来访问一个名称,只要名称可在某个地址上到达。
事实上,自从 1995 年推出基于 DNS 的负载平衡以来,一种多地址对应一个名称的版本就已经存在。那么,为何不能所有地址对应所有名称,或任何地址在任何时间对应所有名称呢?或者,正如我们即将发现的那样,一个地址对应所有名称!但首先让我们谈一下实现寻址敏捷性的方式。
实现寻址敏捷性:忽略名称、映射策略
实现敏捷性的关键是权威 DNS——但不是以某种形式的记录或查找表存储的静态名称到 IP 映射。从任何客户端的角度来看,绑定只出现在“查询中”。对于映射的所有实际应用,查询的响应是某个请求生存期中最后一个名称可与地址绑定的时刻。
这让人想到,名称映射实际上不是在某个记录或分区文件中进行,而是在响应返回时进行。这是一个微妙但重要的区别。今天的 DNS 使用名称来查找一组地址,然后有时使用某种策略来决定返回哪个特定的地址。下图显示了这个概念。当查询到达时,查询显示与该名称相关联的地址,然后返回其中一个或多个地址。DNS 常常会使用额外的策略或逻辑过滤器来缩小地址选择范围,例如服务级别或地理区域覆盖。重要的细节是先用名称识别地址,然后才应用策略。
(a) 传统的权威 DNS
(b) 寻址敏捷性
寻址敏捷性是通过逆转这个关系来实现的。我们的架构不是预先将 IP 地址分配给名称,而是从一个可能包含名称(我们的方案不包含)的策略开始。例如,策略可能由位置和帐户类型等属性表示,并忽略名称(我们的部署就是这样做的)。这些属性识别一个与该策略相关联的地址池。这个池本身可能与该策略隔离,或者具有与其他池和策略共享的元素。此外,池中的所有地址都是等价的。这意味着,其中任何地址都可能返回,甚至随即选择,而不检查 DNS 查询名称。
现在要暂停一下,因为查询前响应都有两个值得注意的影响:
i. IP 地址可以在运行时或查询时计算并分配。
ii.IP 到名称映射的生存期是后续连接生存期和下游缓存 TTL 中的较大者。
结果是强有力的,这意味着绑定本身是短暂的,可以在不考虑以前的绑定、解析器、客户端或目的的情况下更改。而且,扩展也不是问题,我们知道这一点是因为我们已经在边缘进行了部署。
IPv6——新的衣服,同样的皇帝
在讨论我们的部署前,让我们先谈一下“房间里的大象”(指大家都知道但刻意回避的问题):IPv6。首先要明确的是,这里在 IPv4 语境下讨论的_一切_,对 IPv6 同样适用。正如全球邮政系统,地址就是地址,无论是在加拿大、柬埔寨、喀麦隆、智利还是中国,其中包括了地址相对静态、不灵活的本质。
尽管是等价的,显而易见的问题依然是:仅仅改变到 IPv6 就能满足追求寻址敏捷性的所有理由了吗?答案可能与直觉相悖,但答案是斩钉截铁的“不”!IPv6 可以缓解地址耗尽,至少在当今活着的人的有生之年是这样,但 IPv6 前缀和地址的丰富性使得处理地址与名称、资源的绑定变得困难。
IPv6 地址的丰富性也存在效率低下的风险,因为运营商可利用比特的长度和大前缀容量将意义嵌入 IP 地址中。这是 IPv6 的一个强大特性,但也意味着任何前缀中的许多地址都将不被使用。
需要明确的是,Cloudflare 显然是 IPv6的最大支持者之一,而且有充分的理由,尤其是丰富的地址确保了使用寿命。尽管如此,IPv6 几乎没有改变地址与名称和资源绑定的方式,而地址的灵活性确保了其生存期内的灵活性和响应能力。
附带说明:敏捷性适用于每一个人
我们对架构及其可移植性的最后一点评论:对于任何操作权威 DNS 的服务来说,寻址敏捷性都是可用的,甚至是可取的。其他以内容为导向的服务提供商显然是竞争者,但规模较小的运营商也是如此。大学、企业和政府只是能够运营自己权威服务的组织的几个例子。只要运营商能够接受返回 IP 地址上的连接,所有运营商都是寻址敏捷性的潜在受益者。
基于策略的随机地址——规模化实施
2006 年以来,我们一直在边缘通过生产流量来实际应用寻址敏捷性,包括:
超过 2000 万个主机名和服务
加拿大的所有数据中心(提供合理的人口和多个时区)
/20 (4096 个地址, IPv4) 和 /44 (IPv6)
2021 年 1 -6月,/24(256 个地址, IPv4)
对每一个查询,在前缀中生成一个随机的主机部分。
毕竟,对敏捷性的真正考验最极端的时候就是,为每个访问我们服务器的查询生成一个随机地址。然后我们决定将这个想法真正付诸实践。2021 年 6 月,在我们的蒙特利尔数据中心,以及不久之后的多伦多数据中心,所有 2000 多万个区域都被映射到单一地址。
在一年时间内,策略捕获的每个域查询都会收到一个随机选择的地址——最初来自少至 4096 个地址的集,然后是 256 个,最后是一个。在内部,我们将只有一个地址的集称为 Ao1,稍后将再详细说一下这一点。
衡量成功的标准:“这里没有任何东西可看”
一些读者可能正在私下问自己:
这会破坏互联网上的什么东西?
这对 Cloudflare 系统有何影响?
如果可以,我会看到什么事情发生?
对于上面每个问题,简短的答案是“什么都没有”。但是(很重要的一点)地址随机化确实暴露了那些依赖于互联网的系统在设计上的弱点。这些弱点的每一个都总是出现,原因是设计者将可达性以外的含义加诸于 IP 地址上。(或许,所有这些缺点都能通过使用一个地址——Ao1——来解决。)
要更好地理解“什么都没有”的本质,我们先从下往上回答上面的问题。
如果可以,我会看到什么事情发生?
答案在下图所示的例子中。在我们的部署以外的“世界其他部分”,对于一个区域的查询,所有数据中心都返回相同的地址(例如 Cloudflare 的全球任播系统)。相反,在部署数据中心,每个查询都会收到一个随机地址。可在下面对不同数据中心的连续 dig 命令中看到这些信息。
如果您在考虑后续请求流量的问题,没错,这意味着服务器被配置为,为地址池中_所有_地址上的 2000 多万个域的_任何_一个接受连接请求。
好吧,但是 Cloudflare 的周边系统肯定需要做修改吧?
不用。这是对权威 DNS 数据管道的一个直接表观更改。BGP、DDoS、负载均衡器、分布式缓存……等的每一个路由前缀通告,都不需要更改。
但是有一个很有意思的副作用:随机化对 IP 地址的作用就好比良好的哈希函数对一个哈希表的作用——它均匀地将任意大小的输入映射到固定数量的输出。这种影响可从随机化前后的每 IP 负载测量值上看出来,如下三张图所示,数据来自一个数据中 7 天期间的 1% 请求样本。
应用寻址敏捷性前
按 /20 随机化
按 /24 随机化
随机化前(图 a ),对仅仅一小部分 Cloudflare 的 IP 空间,每 IP 的请求最大和最小数(左侧 y1-轴)差异达到 3 个数量级;同样,每 IP 的字节数(右侧 y2-轴)差异接近 6 个数量级。随机化后(图 b),对于在单一 /20 上(此前占据多个 /20)的所有域,差异分别减少了 2 和 3 个数量级。再进一步(图 c),2000 多万个域的每查询随机化到 256 个地址后,负载差异减少到一个较小的常量。
对任何可能考虑通过 IP 地址配置资源的内容服务供应商而言,这一点也许很有意义。提前预测客户产生的负载并非易事。上面的图证明,未来最佳的方式将是_将所有地址赋予所有名称_。
这肯定会在互联网上破坏某些东西吧
在这里,答案也是否定的。或许更准确地说,“不,随机化不会破坏任何东西……但它会暴露系统及其设计的弱点。”
任何_可能_受到地址随机化影响的系统似乎都有一个先决条件:IP 地址被赋予某种超出单纯可达性的意义。寻址敏捷性保持甚至恢复了 IP 地址和核心互联网架构的语义,但它会破坏对它们的意义作出假设的软件系统。
我们先看几个例子,为什么它们不重要,然后对寻址敏捷性做一个小的改变来绕过弱点(通过使用单一 IP 地址):
HTTP 连接合并使客户端能够重用现有连接来请求来自不同来源的资源。在 URI 权威匹配连接时允许合并的客户端(如 Firefox)不受影响。然而,需要 URI 主机解析到与给定连接相同的 IP 地址的客户端将会失败。
基于非 TLS 或 HTTP 的服务可能会受到影响。例如,ssh 在其 known_hosts 中维护主机名到 IP 的映射。这种关联虽然可以理解,但已经过时了,并且已经被破坏,因为许多 DNS 记录目前返回多个 IP 地址。
非 SNI TLS 证书要求一个专用 IP 地址。由于每个地址仅能支持一个非 SNI 证书,提供商被迫收取额外费用。与 IP 无关,更大的问题是非 SNI TLS的使用。我们已经开始努力理解非 SNI,希望能够结束这个不幸的遗产。
依赖于目标 IP 的 DDoS 保护最初可能会受到妨碍。我们认为寻址敏捷性有两个好处。首先,IP 随机化将攻击负载分布到所有正在使用的地址,有效地充当了第三层负载均衡器。其次,DoS 缓解常常通过改变 IP 地址来工作,这是寻址敏捷性所固有的能力。
万物为归一,一为万物
我们最先用数万地址来服务 2000 万个域,成功减少到 4096 个地址(/20),然后是 256 个地址(/24)。这个趋势自然会引发一个问题:
如果随机化能在 n 个地址上起作用,为何不能在 1 个地址上随机化?
的确,有何不可呢?回想一下,我们在前面说过,IP 地址随机化就好比哈希表中的完美哈希功能。基于哈希的结构,如果设计良好,无论结构的大小如何,即使只有 1,都能保持其属性。对于寻址敏捷性所赖以构建的基础而言,这种减少将是一个真正的考验。
我们进行了测试。从一个 /20 地址集到 /24,然后从 2021 年 6 月起,到一个 /32 的地址集,等效于 /128(Ao1)。不但行得通,还_非常_成功。Ao1 解决了随机化可能暴露的问题。例如,非-TLS 或非-HTTP 服务有一个可靠的 IP 地址(或至少非随机,并直至对该名称的策略发生变化为止)。同时,HTTP 连接合并也大量涌现,没错,在使用 Ao1 的情况下,合并水平增加了。
但为何在 IPv6 中有这么多地址?
反对绑定到单个 IPv6 地址的一个理由是没有必要,因为地址不太可能耗尽。这是一个在 CIDR(无类域间路由)前的立场,我们认为,这种说法往好里说是善意的,往坏里说是不负责任的。如上所述,IPv6 地址的数量使得对它们的推理变得困难。与其问为什么使用一个 IPv6 地址,我们应该问,“为何不呢?”
是否会对上游产生影响呢?是的,还会带来机会!
Ao1揭示了一系列完全不同于 IP 随机化的含义,可以说,通过放大看似微小的行动可能产生的影响,为我们打开了一扇通向互联网路由和可达性未来的窗口。
为什么呢?宇宙中可能的可变长度名称的数量总是会超过固定长度地址的数量。也就是说,按照鸽巢原理(又名抽屉原理),单一 IP 地址必须由多个名称和来自不相关方的不同内容共享。
Ao1 放大的可能上游效应值得讨论,如下所述。然而,到目前为止,我们在评估中没有看到这方面的影响,在与上游网络的通信中也没有出现。
上游路由错误是即时和全局的。如果所有流量到达单一地址(或前缀),那么上游路由错误会对所有内容产生同等的影响。(因此,Cloudflare 返回非连续地址范围的两个地址。)但是,请注意,对威胁拦截也是如此。
上游 DoS 保护可能会被触发。可以想象,请求和流量集中在单个地址上有可能被上游视为 DoS 攻击,并触发可能存在的上游保护。
在以上情况中,由于寻址敏捷性能够迅速大规模改变地址,这些行动都得到缓解。预防也是可能的,但需要公开的沟通和讨论。
最后一个可能的影响是:
IPv4 NAT 中的端口耗尽可能会加速,并由 IPv6 解决!从客户端到一个地址的允许并发连接数量是由传输协议的端口字段大小决定的,例如 TCP 中大约是 65K。
例如,Linux 上的 TCP 中,直到最近这还是一个问题。(查看这个 提交 以及 ip(7) man page 中的 SO_BIND_ADDRESS_NO_PORT。)在 QUIC 中,连接标识符可以防止端口耗尽,但必须使用它们。然而,到目前为止,我们还没有看到任何证据表明这是一个问题。
即使如此——这是最棒的部分——据我们所知,这是单一地址使用的唯一风险,并可通过迁移到 IPv6 来马上得到解决。(因此,ISP 和网络管理员,事不宜迟,马上实施 IPv6 吧!)
我们才刚刚开始!
就这样,我们又回到开始所说的问题。如果任何单个 IP 地址可对应无限数量的名称,具备可对每个查询改变地址的能力,无论出于什么原因,那么_您_会创造什么东西呢?
我们其实还只是刚刚起步!寻址敏捷性具备灵活性和未来适应性,让我们能够想象、设计和构建新的系统和架构。我们正在计划针对任播系统的 BGP 路由泄漏监测和缓解,测量平台,等等。
欢迎查看这篇论文和这个短视频介绍,其中包括有关以上内容的更多技术细节,并向所有使这一切成为可能的人致谢。即使有了这些新的可能性,挑战依然存在。有许多悬而未决的问题,包括但不限于以下:
哪些策略可合理地表达或实施?
是否有一种抽象的语法来表达它们?
我们能否使用正式的方法和验证来预防错误或冲突的策略?
寻址敏捷面向每个人,这甚至是这些想法更广泛地获得成功的必要条件。有任何想法或建议,请发送到 [email protected]。
如果您是在读博士研究生或参与同等研究项目,正在寻找 2022 年在美国或加拿大和欧盟或英国的实习机会。
如果您有兴趣为这样的项目做出贡献,或帮助 Cloudflare 开发其流量和地址管理系统,我们的寻址工程团队正在招聘!