跳到主内容
@wquguru
精选88Cloudflare 博客(RSS)技巧与观点

Cloudflare 优化 DNS 构建:延迟减半内存降 85%

How we halved DNS build delay and cut memory use by 85%

原文
发到 X
推荐理由

DNS 基础设施的工程实践干货,详细拆解了大规模分布式系统下的增量构建与状态一致性难题,对做高并发数据处理的同学极具参考价值。

When I last wrote about our DNS propagation pipeline in 2022, the Zone Builder received about 250 DNS record changes per second. Today it receives about 700, nearly three times as many, plus about 100 other events, such as zone setting changes. However, the number of events was never the real problem. The problem was the kind of work some of those events needed, and how that work grows with the size of a zone. Some zones now hold more than 20 million records, and we expect them to keep growing toward hundreds of millions.

当我在 2022 年上次撰写关于我们的 DNS 传播管道(DNS propagation pipeline)的文章时,Zone Builder 每秒接收大约 250 次 DNS 记录变更。如今它每秒接收大约 700 次,几乎是之前的三倍,此外还有大约 100 次其他事件,例如区域设置变更。然而,事件数量从来不是真正的问题。问题在于其中一些事件所需的工作类型,以及这些工作如何随着区域大小的增长而增加。某些区域现在包含超过 2000 万条记录,我们预计它们将继续增长至数亿条。

Each event starts a clock that measures how long it takes us to turn that change into data our authoritative DNS servers can use. We call that work a build. A build reads the current database state, converts it into the format used at the edge, and writes any changes to Quicksilver.

每个事件都会启动一个计时器,用于测量我们将该变更转化为权威 DNS 服务器可用的数据所需的时间。我们将这项工作称为构建(build)。构建过程读取当前的数据库状态,将其转换为边缘节点使用的格式,并将任何变更写入 Quicksilver。

In 2022, per-record builds were 150 times faster than full builds on average. On a test zone with one million records, per-record builds were 4,250 times faster. We ended that post with the obvious next step: do the same thing for zone settings.

在 2022 年,每条记录的构建平均比完整构建快 150 倍。在一个包含一百万条记录的测试区域中,每条记录的构建快了 4,250 倍。我们在该文章的结尾提出了显而易见的下一步:对区域设置也做同样的事情。

Why doesn't the Zone Builder just rebuild the setting that changed?

为什么 Zone Builder 不直接重新构建发生更改的设置呢?

It should, and that is where we ended up. However, proving when it was safe took most of the work. A record event identifies what changed. A zone event can come from many Cloudflare products, may not say why the zone changed, and can alter data shared by several zones with the same name. Choosing too much work wastes capacity. Choosing too little can leave stale or incorrect DNS data at the edge.

它本应如此,而这正是我们最终实现的方向。然而,证明何时这样做是安全的耗费了大部分工作量。一条记录事件会明确指出什么发生了变更。一条区域事件可能来自多个 Cloudflare 产品,可能未说明区域变更的原因,并且可以更改多个同名区域共享的数据。选择过多的工作会浪费容量;选择过少则可能导致边缘节点保留过时或不正确的 DNS 数据。

We built a targeted build planner that chooses the smallest build we can prove is safe, and a new scheduler that combines work for the same zone. Zone setting changes no longer rebuild zones with tens of millions of records. Together, they cut peak memory by 85%, and the extra headroom let us safely shorten waits the pipeline has always needed for resilience, halving the time from a DNS change to its data being written to Quicksilver.

我们构建了一个定向构建规划器(targeted build planner),它选择我们能够证明是安全的最小构建规模,以及一个新的调度器,它将同一区域的各项工作合并。区域设置变更不再重建包含数千万条记录的区域。两者结合使峰值内存减少了 85%,额外的余量让我们能够安全地缩短管道一直需要的弹性等待时间,将 DNS 变更到其数据写入 Quicksilver 的时间减半。

How DNS changes reach the edge

DNS 变更如何到达边缘节点

A DNS zone is the collection of records and settings for a domain. Cloudflare uses a multi-stage pipeline to turn a change to that zone into data available across our global network.

DNS 区域是某个域名的记录和设置的集合。Cloudflare 使用多阶段管道将该区域的变更转化为全球网络中可用的数据。

  • A customer changes a DNS record through the DNS Records API or dashboard, or another Cloudflare service changes a zone setting.
  • The change is stored in a database.
  • The database change or another system produces a Kafka event.
  • The DNS Kafka Aggregator combines events from several Kafka topics and sends them to the Zone Builder.
  • The Zone Builder reads the required zone data and converts it into keys understood by our authoritative DNS servers.
  • The Zone Builder compares those keys with Quicksilver, our distributed key-value store. It writes only what changed, and Quicksilver propagates those changes across Cloudflare's network.
  • 客户通过 DNS Records API 或仪表板更改 DNS 记录,或者另一个 Cloudflare 服务更改区域设置。
  • 该变更存储在数据库中。
  • 数据库变更或其他系统生成一个 Kafka 事件。
  • DNS Kafka Aggregator 将来自多个 Kafka 主题的事件合并并发送给 Zone Builder。
  • Zone Builder 读取所需的区域数据,并将其转换为我们的权威 DNS 服务器所理解的键。
  • Zone Builder 将这些键与 Quicksilver(我们的分布式键值存储)进行比较。它仅写入发生更改的内容,Quicksilver 随后将这些更改传播到 Cloudflare 的网络中。

This is a simplified view. The Zone Builder does not copy database rows directly to the edge. It combines records with zone settings, applies DNS serving rules, and organizes the result so our authoritative DNS servers can read it quickly.

这是一个简化的视图。Zone Builder 不会直接将数据库行复制到边缘节点。它将记录与区域设置相结合,应用 DNS 服务规则,并整理结果,以便我们的权威 DNS 服务器能够快速读取。

Why full builds stopped scaling

为什么全量构建不再具备可扩展性

The original Zone Builder had one useful property: it did not need to know why a zone changed. It rebuilt the desired state from the current database state.

原始的 Zone Builder 有一个有用的特性:它不需要知道区域为何发生变化。它是从当前数据库状态重建期望状态的。

  • Read the current zone and its settings.
  • Read every DNS record in the zone.
  • Convert those records into Quicksilver keys.
  • Compare the new keys with those already stored.
  • Remove stale keys, write changed keys, and update zone metadata.
  • 读取当前区域及其设置。
  • 读取区域中的每条 DNS 记录。
  • 将这些记录转换为 Quicksilver 键。
  • 将新键与已存储的键进行比较。
  • 移除过期的键,写入已更改的键,并更新区域元数据。

The final write contains only changed keys. However, a full build still reads, encodes, and compares every record, and holds the whole zone in memory while it does so. That is cheap for a small zone. For our largest zones, with tens of millions of records, the zone does not fit in memory at all. I explain how we handle that below.

最终写入仅包含已更改的键。然而,全量构建仍然需要读取、编码和比较每条记录,并在执行过程中将整个区域保留在内存中。这对于小型区域来说成本很低。但对于我们最大的区域(拥有数千万条记录),整个区域根本无法放入内存。我将在下文解释我们如何处理这一问题。

Zone settings made targeting harder. Universal SSL is one example. Enabling or disabling it updates metadata and can change Certification Authority Authorization (CAA) records at the zone apex, the bare domain, such as example.com. CAA records tell certificate authorities whether they may issue a certificate for the domain.

区域设置使得精准定位变得更加困难。通用 SSL 就是一个例子。启用或禁用它会更新元数据,并可能更改区域顶点(即裸域名,如 example.com)处的证书颁发机构授权(CAA)记录。CAA 记录告知证书颁发机构是否可以为该域名颁发证书。

A full build only needed to know that the zone changed. A targeted build must answer three questions:

全量构建只需知道区域发生了变化。而精准构建必须回答三个问题:

  • Which DNS names can change?
  • Can shared metadata or the list of published zones change?
  • What previous state must be removed from Quicksilver?
  • 哪些 DNS 名称可以更改?
  • 共享元数据或已发布区域的列表是否会更改?
  • 必须从 Quicksilver 中移除哪些先前的状态?

Answering those questions safely meant solving five problems, which the rest of this post covers in order:

安全地回答这些问题意味着要解决五个难题,本文的其余部分将按顺序介绍这些内容:

  • Events had to say what changed.
  • Each change had to map to the smallest build that is still correct.
  • Builds had to account for data shared by every zone with the same name.
  • The database could change between the event and the build.
  • Combining work could not lose a Kafka message.
  • 事件必须说明具体发生了什么更改。
  • 每次更改都必须映射到仍保持正确性的最小构建。
  • 构建必须考虑每个同名区域共享的数据。
  • 数据库可能在事件和构建之间发生变化。
  • 合并工作不能丢失任何 Kafka 消息。

Making events say what changed

使事件能够说明具体发生了什么更改

We changed the event producer to include changed zone fields and settings, with previous and new values when available. We then traced each setting through the code that generates DNS output and classified what it could affect.

我们修改了事件生产者,使其包含已更改的区域字段和设置,并在可用时提供旧值和新值。然后,我们追踪了每个设置通过生成 DNS 输出的代码路径,并对其可能产生的影响进行了分类。

Not every event was that specific. Some database functions only update a timestamp to say, in effect, "something about this zone changed." Sometimes that is harmless bookkeeping. Sometimes it means data changed elsewhere and must be read again.

并非每个事件都那么具体。某些数据库函数仅更新一个时间戳,以表明“此区域的某项内容发生了变化”。有时这只是无害的记账操作;有时则意味着其他位置的数据已更改,必须重新读取。

Those cases look identical in the event. Until we can identify the caller and its purpose, a timestamp-only update still causes a full build. The same rule applies to missing details, unknown events, or any change that may affect records anywhere in the zone. The planner never turns uncertainty into less work.

在事件中,这些情况看起来完全相同。在我们能够识别调用者及其目的之前,仅更新时间戳的更新仍会导致完整构建。同样的规则也适用于缺失详细信息、未知事件或可能影响区域内任何记录的任何更改。规划器绝不会将不确定性转化为更少的工作量。

Choosing the smallest safe build

选择最小的安全构建

Quicksilver output has two parts that matter here. Record keys contain the DNS answers for one zone and name. A smaller shared metadata key tells our authoritative DNS servers how to use that zone, including where to find special records such as nameservers and wildcards. Some events change only record keys; others must update both.

Quicksilver 的输出在此处有两个重要部分。记录键包含某个区域和名称的 DNS 答案。一个较小的共享元数据键告知我们的权威 DNS 服务器如何使用该区域,包括在哪里查找特殊记录(如名称服务器和通配符)。某些事件仅更改记录键;而其他事件则必须同时更新两者。

With that distinction, the planner can choose one of five build types:

基于这种区分,规划器可以选择以下五种构建类型之一:

  • Resources only: Rebuild the records at specific DNS names, which we call resources, without changing zone metadata. Ordinary A, AAAA, TXT, and CNAME changes usually take this path.
  • Resources and metadata: Rebuild specific names and shared metadata. Nameserver and wildcard changes use this path.
  • Apex and metadata: Rebuild the zone apex and metadata. Settings such as Universal SSL can use this path.
  • Purge: Remove a zone that should no longer be published.
  • Full zone: Rebuild every record when smaller work cannot be proven safe.
  • 仅资源:重建特定 DNS 名称(我们称之为资源)处的记录,而不更改区域元数据。普通的 A、AAAA、TXT 和 CNAME 更改通常走此路径。
  • 资源和元数据:重建特定名称和共享元数据。名称服务器和通配符更改使用此路径。
  • Apex 和元数据:重建区域 Apex 和元数据。Universal SSL 等设置可使用此路径。
  • 清除:移除不再需要发布的区域。
  • 完整区域:当无法证明较小工作量是安全的时,重建所有记录。

The rule is simple: every key a targeted build writes must be byte-for-byte identical to what a full build would write. If we cannot prove that, we do a full build.

规则很简单:目标构建写入的每个键都必须与完整构建会写入的内容逐字节完全相同。如果我们无法证明这一点,我们就执行完整构建。

Removing old state works as it did for per-record builds in 2022. Record events include deleted records and the previous version of updated ones. The Zone Builder then scans Quicksilver for the existing keys under each name it rebuilds, removing any that the new build did not write.

移除旧状态的方式与 2022 年按记录构建时的方式相同。记录事件包括已删除的记录以及已更新记录的先前版本。然后,Zone Builder 会在 Quicksilver 中扫描它重建的每个名称下的现有键,并移除新构建未写入的任何键。

Full builds remain necessary when a change can affect records anywhere in the zone or when a zone may need to be published for the first time.

当更改可能影响区域内的任何记录,或者区域可能需要首次发布时,完整构建仍然是必要的。

更进一步:量化金融体系

看懂新闻只是起点——沿量化金融路径,把它变成能交付的工程能力

进入量化体系 →

相似阅读

关联信息,但可能不是同一事件