CloudflareDNSInfrastructure

Cloudflare 将 1.1.1.1 DNS 缓存的内存占用削减了 100TB

Leela Kumili··原文链接
收录于 2026/10/14 19:47:01

Cloudflare 重新设计了 1.1.1.1 递归解析器所使用的 DNS 缓存内存表示,将每个条目的基准空间占用减少了 56%,在整个服务器集群中释放了约 100 TB 的工作集内存。这项工作针对 DNS 平台 Big Pineapple 的 Rust 缓存表示形式连续进行了五次迭代优化,最终使缓存插入吞吐量提高 43%,查询延迟降低 19%。

在任何时刻,Big Pineapple 都存储着超过 2500 亿个 DNS 缓存条目。Cloudflare 系统工程师 Sebastiaan Neuteboom 在 LinkedIn 上这样描述这一成果:

能节省 100 TB 的内存,这可不是每天都能遇到的。

五轮迭代优化的技术路径

优化的核心思路是逐层消除 Rust 数据结构中的冗余分配与表示开销:

  1. 堆替换栈上动态数据(Vec/String → Box<[T]>/Box<str>):将插入后固定不变的数据类型从 Vec 和 String 替换为 Box<[T]> 和 Box<str>。这一步的关键洞察在于缓存条目一旦写入即不可变——Vec 和 String 的容量字段(cap)对于只读场景是纯浪费。替换后每个条目节省 64 字节,集群累计释放超过 15 TB。

  2. 记录合并与紧凑偏移量列表:将应答(answer)、权限(authority)及其他记录合并为单一带紧凑偏移量的列表,消除多记录独立分配的元数据开销。

  3. 布尔值位打包:将布尔字段打包成位标志(bit flags),将 8 字节的 bool 对齐浪费压缩到单个 bit。

  4. 省略冗余所有者名称:省略与查询域名匹配的所有者名称(owner name),转而通过缓存键在查询时重建。DNS 缓存条目中所有者名称往往与查询名重复,这一步省去了大量字符串存储。

  5. 枚举装箱的权衡与最终放弃:这是最大的挑战。Cloudflare 最初尝试对较大的 Rust 枚举变体进行装箱(boxing),但独立的内存分配不仅增加了分配器开销,还降低了缓存局部性(cache locality)——指针跳转破坏了 CPU 缓存行预取。一位 Reddit 评论者对此总结道:

许多这种类型的内存优化技巧只有在达到 Cloudflare 的请求量级别时才能发挥作用;在规模比较小的情况下,将变体进行装箱所造成的额外间接访问,对缓存局部性的损害可能大于其实际益处。

最终设计:DNS 有线格式作为存储格式

Cloudflare 的最终方案放弃了自定义 Rust 结构体,转而直接采用 DNS 有线格式(wire format)——将记录数据存储在连续的字节缓冲区中。这一设计的工程价值在于:

  • 消除了枚举变体的内存分配开销和按记录分配的元数据开销;
  • 连续字节布局天然提升缓存局部性,CPU 预取器友好;
  • 常用记录类型可直接 memcpy 到响应缓冲区,零解析开销;
  • 包含域名的记录仍需解析以实现 DNS 名称压缩(name compression),但这是局部而非全局代价。

图1:Cloudflare 的 DNS 缓存使用 DNS 有线格式将记录数据存储为连续的字节缓冲区(图片来源:Cloudflare 博客文章)

与同类递归解析器的架构对比

这一方案与其他递归 DNS 解析器的缓存架构有显著差异:

  • Unbound:维护独立的消息缓存、RRset 缓存、键缓存和负缓存,缓存大小和分块设置均可配置。模块化程度高,但单条目表示开销较大。
  • PowerDNS Recursor:使用多种缓存类型,包括数据包缓存(packet cache)和记录缓存(record cache),分层设计。
  • Cloudflare Big Pineapple:工作重点不在于多级缓存分离,而在于将单条目表示和分配开销压到极致——本质上是在追求"一个缓存条目占用的字节数"这一指标的全局最优。

这种差异本质上反映了不同的工程哲学:Unbound 和 PowerDNS 追求灵活性与可配置性,而 Cloudflare 在超大规模下选择牺牲结构灵活性换取内存效率。

生产环境部署与实测结果

该优化于 2026 年 5 月 18 日至 7 月 6 日期间在生产环境中全面部署。关键指标变化:

  • 单条目内存占用:953 字节 → 420 字节(−56%)
  • 单条目内存分配:1.1 KB → 461 字节
  • 驻留内存(p99):每实例 9.3 GB → 5.3 GB
  • 驻留内存(p90):每实例 6.5 GB → 3.8 GB
  • 插入吞吐量:+43%
  • 查询延迟:−19%
  • 集群级释放内存:约 100 TB

图2:Cloudflare 生产环境内存使用图(图片来源:Cloudflare 博客文章)

Cloudflare 计划利用释放出的 100 TB 内存来增加缓存容量,而非增加整体内存消耗——即在硬件成本不变的前提下提升缓存命中率,形成性能正循环。

工程启示

从架构视角看,这个案例有几个值得注意的点:

  1. 数据不可变性是优化的前提:只有当数据生命周期明确(写入后只读),才能安全地用紧凑布局替换动态容器。这对前端状态管理中的不可变数据模式有类比意义。

  2. 存储格式选择应匹配访问模式:选择有线格式而非自定义结构体,是因为热点路径(常用记录直接复制到响应)受益于零拷贝,而冷路径(域名解析)的代价可接受。格式设计与访问模式对齐是高性能系统的通用原则。

  3. 装箱/指针跳转的局部性代价在规模放大后才显著:小规模下指针跳转的延迟可忽略,但在每秒百万级查询的缓存路径上,缓存行未命中(cache miss)会成为瓶颈。这提醒我们在做性能优化时要区分"逻辑正确"和"物理高效"。

  4. 100 TB 不是一次优化完成的:五轮迭代每轮贡献不同量级,从 64 字节/条目到整体架构重构。大规模系统的优化往往是持续递进而非一蹴而就。

原文链接:https://www.infoq.com/news/2026/09/cloudflare-dns-cache/

评分:
暂无(0 人评分)