首页 > 数据库 > 数据库开发技术 > 逆转指数增长:我们如何控制硬件使用量
Cathy Chi、Sergey Nuzhdin 和 Christian Endres

超过 20% 的 Web 流量位于 Cloudflare 网络之后,我们的团队——数据团队——负责数据管道,将来自我们全球网络的数据(以及更多数据)传输到适用的中央数据中心。Cloudflare 网络是一个全球分布式系统,支持数万台服务器。为 Cloudflare Logs、SQL API(应用程序编程接口)、可观测性、内部分析等提供支持的数据流经此网络,并使用我们的数据管道为客户提供服务。
今年 5 月,我们每秒提供约 20 亿个事件的数据交付。这包括客户流量以及内部团队发送的数据。年复一年,我们都在应对同一个问题——流量呈指数级增长,而硬件增长却是线性的。我们必须应对这种增长,以控制资源成本。在过去五年中,我们做出了各种改进,以弥补数据量增长与硬件分配之间的差距,相当于推迟了两年半的硬件扩展。本文详细介绍了这些变化:2022 年拆分单体数据模式,2024 年调整压缩,2026 年春季重新架构管道复制,2026 年夏季去中心化采样,以及 2026 年秋季在管道中引入聚合。
我们的管道始于一个名为 Logfwdr 的内部服务,我们从高度分布式的数据源(例如:Workers、FL)收集数据。然后,我们将这些数据馈送到一组集中式接收器,这些接收器最终将数据推送到我们的缓冲系统 Buftee。消费者从 Buftee 获取数据,并将数据分发到最终目的地,例如我们严重依赖的 ClickHouse。

2022 年,我们拆解了我们唯一的模式。此前,只有一个流,其中打包了每个产品的字段,迫使 Cloudflare 内部消费者摄取所有内容,并通过过滤器解复用或丢弃记录。当时,Cloudflare 的大多数数据产品都基于 HTTP、安全和 CDN 元数据构建。2021 年,我们的消息模式如下所示:

这里有些字段属于同一产品,但有些字段彼此完全无关。我们的假设是,这些团队都不需要单体模式中 100% 的字段。换句话说,我们可以为每个产品所需的字段创建小消息。尽管我们会在每条消息中重复某些字段,但用特定于产品的模式替换这个“消防水管”实际上将骨干带宽使用量减少了 35-40%,相当于抵消了大约一年的压缩流量增长。

到 2024 年,随着流量稳步增长,我们每天都在处理网络拥塞问题。为了应对这一问题,我们将压缩算法从 LZ4 改为 zstd。我们之前已经尝试过 zstd 压缩,但当时注意到 CPU 使用率较高。因此,我们谨慎地跟踪指标,以确保这种权衡是值得的。
最初,我们将此更改推广到几台服务器。令我们欣慰的是,我们没有观察到 CPU 使用率有明显差异。

有了更多信心后,我们逐步推广到整个机群,这也显示对 CPU 的影响很小。最终,压缩流量吞吐量减少了近 40%。未压缩字节数保持相同的增长,这意味着我们可以在相同大小的管道中支持超过 1.5 倍的流量。或者换句话说,估计的等效增长减少量让我们回到了大约 10 个月前的水平。

如今,在 2026 年,我们尝试了三种策略来减少未压缩字节数(从而减少压缩后的字节数)。
为了使分析系统能够抵御区域性灾难,我们的系统要求将冗余数据存储在多个集中式区域中(受客户元数据边界约束的数据严格存储在其指定区域内)。过去,实现灾难恢复能力的最简单方法是双写:Logfwdr 将每个非区域性分析事件的两份完整副本——分别传输到每个集中式区域。然后,每个区域独立地通过 ClickHouse 处理一份完整副本。我们还在每个区域应用采样,这是一种极具可扩展性的技术,适用于任何流量条件下的所有数据量。我们对高流量数据进行降采样,同时保留稀有事件。
当只有少数数据流使用辅助区域时,这种基础设施尚可管理。然而,随着我们将灾难恢复能力扩展到几乎所有分析数据流,Logfwdr 的流量全面翻倍。在我们流量指数级增长的背景下,通过广域传输将每个事件发送两次是不可持续的。
我们已经在 Logpush 中解决过类似的挑战。对于 Logpush,Logfwdr 将集中式数据中心视为一个统一、共享的接收器池:每条消息只发送到一个区域,如果某台机器或设施不可达,则故障转移到另一个目的地。该模型已在重大事件中证明了其价值,能够在无需人工干预的情况下将流量无缝地从一个位置转移到另一个位置。这种自动故障转移之所以可行,是因为 Logpush 投递是无状态的,客户目的地不关心是哪个集中式数据中心推送日志。
分析系统则更为棘手。与无状态日志不同,两个区域中的 ClickHouse 集群仍然需要非区域性数据的完整副本,以支持即时、独立的查询故障转移。突破点在于将管道传输与数据库冗余解耦:
1. 共享摄取池:我们将 Logpush 的模型应用于分析数据流。Logfwdr 通过广域传输将每个事件恰好分发一次到任何可用的集中式接收器。
2. 从集中式区域进行延迟复制:不是在源头复制流量,而是在管道中尽可能晚地进行复制。数据落入我们的分布式缓冲层 Buftee,远程插入器将跨数据中心的副本向下游流式传输。
3. 弹性故障处理:如果某个集中式区域宕机,Logfwdr 会立即将所有非区域性流量路由到幸存区域。如果数据中心间连接出现短暂中断,每个集群继续摄取其本地份额而不会产生背压;一旦骨干网恢复,远程插入器会从 Buftee 的保留缓冲区中追赶。

对于我们迁移的数据集,切换消除了约 43 GB/s 的压缩传输流量,同时仅在我们的管道上增加了约 7 GB/s 的跨数据中心复制。两个架构因素解释了这种不对称性:
1. 复制发生在采样下游:在旧模型中,Logfwdr 通过广域传输发送两份未采样的原始事件副本。在新模型中,Logfwdr 向集中式接收器发送一份副本,接收器在缓冲到 Buftee 之前立即应用采样,仅携带这个已经压缩的流。
2. 通过均匀分区实现更好的压缩:源头的数据分散在数千台独立服务器上。集中化之后,数据流被聚合并分区为更宽时间窗口内的均匀批次。这种结构上的均匀性使压缩算法能够实现比 Logfwdr 传输批次高得多的压缩比。
总体而言,这使广域网带宽净减少了 36 GB/s。我们最初将这一方案推广到两个数据集:HTTP analytics 和 Ready-Analytics,后者是我们内部的一键式分析产品。


自春季以来,我们一直在积极将更多数据集迁移到这种负载均衡架构上。
我们采用的另一项策略是进一步扩展采样机制,将关键处理更早地拉入流水线中。采样此前已在我们的集中式服务中使用,尤其是在接收器中,以缓解下游系统的压力。在不牺牲数据质量的前提下,向下游发送更少的数据可以让我们更高效地利用资源。
这里的解决方案很简单:除了在集中式接收器中保留采样外,还在 Logfwdr 中进行采样。简而言之,这里的采样算法工作原理是:每个数据集都有一个由生产团队选择的键,用于对数据进行索引和采样。采样时,我们首先对每个键的记录进行打乱以消除偏差。然后,对于每组记录,我们选择一个等于记录总数平方根的样本大小。无论采样一次还是两次,结果都是具有代表性的样本。为了生成估算值,我们根据采样率对计算进行缩放。例如,如果我们从 100 条记录中采样 10 条,采样率就是 10/100,原始计数的无偏估计就是 10*10 = 100。
为了确保这种方法运行良好,我们将写入 ClickHouse 的行数与使用各种键、在各种流量分布下估算的总计数进行了比较,从而覆盖了从“最少出现”的键到“最多出现”的键的整个范围。

结果是,对于数据量较大的键,采样率会降低。然而,数据量较少的键则得到了相当的采样。因此,我们在交付和存储更少事件的同时,仍然保持了具有代表性的样本。即使交付的数量更少,我们也没有牺牲所交付数据的质量。
如果我们更仔细地观察,使用幂律,可以观察到双重采样(红色)的增长大约为 x 0.319,而单次采样/对照组(蓝色)为 x 0.485。另一种理解方式是,一个键的数据量是另一个键的 100 倍,如果采用单次采样,它存储的行数大约会是后者的 10 倍。现在,它只会存储大约 4 倍的行数。具体来说,总共 1160 万个事件在 ClickHouse 中由 18k 行表示,而不是 79k 行。双重采样减弱了“最多出现”键的存储量,同时仍然为“最少出现”键保留了每个事件的相同细节。

我们最初将这一策略应用于三个最大的数据集。每一个都至少将我们原本通过线路发送到集中式接收器的压缩数据量减半。总计达到 25GB/s,即每天超过 2PB。

Cloudflare 提供多个基于汇总(rollups)构建的分析数据集:即在摄取时计算的原始事件的聚合。这与采样做出了相反的权衡:我们不是近似地回答任何问题,而是在预先选择好维度和指标的前提下,精确地回答一组固定的问题。
例如,在 HTTP 数据集中,我们测量的是给定分钟内 IP 地址的唯一出现次数,而不是单个 IP 本身。另一个例子是,我们按 HTTP 方法分组,汇总给定域名在该分钟内的 GET、POST、PUT 等请求总数。这些计算实际上都不需要等到流水线的末端才开始进行。
历史上,这种聚合发生在管道的末端,即在从 Buftee 读取并插入 ClickHouse 的插入器中。去中心化这种聚合是一个分散负载并减少我们集中处理的数据量的机会。
因此,我们构建了一个聚合功能,它在每一步都被利用,随着数据汇聚,创造了反复合并匹配的部分聚合的机会。就像采样一样,记录按一个键分组,这决定了哪些记录可以被合并。我们在每个 Logfwdr 实例上进行聚合。当部分聚合的事件到达集中式接收器后,我们再次聚合,这些接收器将这些重新聚合的事件推送到专用的分区缓冲区。由于这些缓冲区汇集了来自多个接收器的记录,当 ClickHouse 插入器按批次读取它们后,我们再次聚合。最后,我们在 ClickHouse 中使用聚合表引擎进行聚合。

我们推出这项功能的第一个数据集是针对 HTTP 流量的。仅在这一个数据集中,压缩字节流量就从 9+ GB/s 降至 <2 GB/s。尽管这目前是基数最高的数据集,但对其进行的聚合仍然使我们在网络上减少了大约 80%。

这种聚合功能对于容易折叠的数据集非常强大,尤其适用于像使用指标这样的用例,其中总和与计数的准确性至关重要。这也意味着我们可以为生产者团队提供除采样之外的另一种减少资源使用的选择,我们确实这样做了。就像 Ready-Analytics 一样,我们创建了一个通用的内部一键式聚合分析产品,称为 Ready-Aggregates。随着我们在管道中继续迭代这个新功能,我们预计节省量将继续增加。
这种指数级增长最明显的证明是流量增长消耗余量的速度。
以 Ready-Analytics 为例,其中应用了三种机制中的两种:负载均衡和采样技术。五月中旬,负载均衡使流量减少了 50%,从约 26 GB/s 骤降至约 13 GB/s。两个月后,流量已经开始回升至约 20 GB/s。这大约是减少量的一半,被自然流量增长所抵消。然后,当采样推出时,我们通过将该数据集的吞吐率降低到个位数,约 8GB/s,创造了更多的余量。

如果没有这两项干预,仅 Ready-Analytics 到九月就会突破 60 GB/s。通过在集中式数据中心处理更少的数据,我们还节省了大量的 CPU 和内存。以下图表显示了 Logfwdr 中的负载均衡和采样对仅 Ready-Analytics 接收器的 CPU 和内存使用的影响:减少了约 50%,恢复了约 750 个 CPU 和 3.5 TiB 内存。


在整个管道中,从春季到秋季,负载均衡(节省约 38 GB/s)、采样(在顶级数据集中节省约 25 GB/s)和聚合(到目前为止节省 7+ GB/s),消除了我们骨干网中约 70 GB/s 的压缩流量。这些断崖式下降提供了即时的缓解。

如果我们放眼五年后,仅今年所做的改变其影响与短期收益一样大。我们已经将未来五年内要处理的数据量减半。我们已经并将继续进行的结构和算法优化对于保持硬件需求的可持续性至关重要。

如果你有兴趣帮助我们大规模解决这些挑战,我们正在招聘!
转载声明:本文为转载整理,原文版权归原作者及原站点所有。
原文来源:Cloudflare Blog
原文作者:Christian Endres;如有侵权,请联系管理员删除。