Workers Analytics Engine 支持写入大量数据并快速检索,成本极低或为零。为以合理成本写入大量数据,Workers Analytics Engine 采用加权自适应采样 ↗。
使用采样时,您不需要每个数据点都能回答有关数据集的问题。对于足够大的数据集,所需样本量 ↗不取决于原始总体的大小,而取决于测量值的方差、您分析的子组大小以及估计值必须达到的精度。
对 Analytics Engine 而言,这意味着我们可以将非常大的数据集压缩为更少的观测值,但仍能以非常高的精度回答大多数查询。这使我们能够提供能够以可预测的低价格测量极高使用率、无界基数的分析服务。
采样的高层工作原理如下:
- 写入时,如果数据点写入某个 index 的速度过快,我们会进行采样。
- 查询时,如果查询过于复杂,我们会再次采样。
在以下部分中,您将了解:
Cloudflare 的数据采样类似于 Google Maps 等在线地图服务在不同缩放级别渲染地图的方式。查看整个大陆的卫星影像时,地图服务会根据用户屏幕和网速提供适当大小的图像。
地图上的每个像素代表较大区域,例如数平方公里。如果用户尝试放大截图,结果图像会模糊。相反,当用户放大到特定城市时,地图服务会选择更高分辨率的图像。总像素数保持相对恒定,但每个像素现在代表较小区域,例如几平方米。
关键是,地图质量不仅取决于分辨率或每个像素代表的区域。它由用于渲染最终视图的总像素数决定。
映射服务处理分辨率的方式与 Cloudflare Analytics 使用自适应样本提供分析之间存在相似之处:
- 数据如何存储:
- 映射服务:以不同分辨率存储影像。
- Cloudflare Analytics:以不同采样率存储事件。
- 如何向用户显示数据:
- 映射服务:对于给定屏幕尺寸,总像素数大致恒定,无论所选区域大小如何。
- Cloudflare Analytics:无论数据集大小或所选时间长度如何,每个查询读取的事件数大致相同。
- 如何选择分辨率:
- 映射服务:每个像素代表的区域取决于所渲染地图的大小。在更缩小的地图中,每个像素代表更大区域。
- Cloudflare Analytics:结果中每个事件的采样间隔取决于底层数据集的大小和所选时间长度。对于大数据集或长时间范围的查询,每个采样事件可能代表许多类似事件。
要有效编写查询并分析数据,首先了解 Workers Analytics Engine 中如何读取采样数据会很有帮助。
在 Workers Analytics Engine 中,每个事件都记录 _sample_interval 字段。采样间隔是采样率的倒数。例如,如果应用 1% 的采样率,sample_interval 将设置为 100。
用映射示例简单来说,采样间隔代表给定采样数据点(像素)所代表的"未采样数据点"(公里或米)数量。
采样间隔是与 Workers Analytics Engine 中存储的每行关联的属性。由于公平采样的实现,每行的采样间隔可能不同。因此,查询数据时需要考虑采样间隔字段。简单地将查询结果乘以恒定采样因子是不够的。
以下是一些常见采样数据查询的示例。
| 用例 | 无采样示例 | 采样示例 |
|---|---|---|
| 统计数据集中的事件数 | count() |
sum(_sample_interval) |
| 对数量求和,例如字节数 | sum(bytes) |
sum(bytes * _sample_interval) |
| 计算数量平均值 | avg(bytes) |
sum(bytes * _sample_interval) / sum(_sample_interval) |
| 计算分位数 | quantile(0.50)(bytes) |
quantileExactWeighted(0.50)(bytes, _sample_interval) |
请注意,结果的准确性不取决于采样间隔,类似于前面提到的映射类比。高采样间隔仍可提供精确结果。相反,准确性取决于查询的数据点总数及其分布。
要确定每个事件的采样间隔,请注意大多数分析都有一些重要的子组类型,需要以准确结果进行分析。例如,您可能想分析用户使用情况或特定 hostnames 的流量。Analytics Engine 用户可以在写入事件时填充 index 字段来定义这些组。这允许在指定组内进行更有针对性的精确分析。
下一个观察是,这些 index 值写入的事件数量可能差异很大。事实上,大多数 Web 服务的使用遵循帕累托分布 ↗,意味着少数头部用户占绝大多数使用量。帕累托分布很常见,看起来像这样:
如果对此数据取 1% 的简单随机样本 ↗并应用于整个总体,您可能能够准确跟踪最大客户——但会失去对小客户活动的可见性:
请注意,较大的柱看起来或多或少不变,且仍然相当准确。但在分析较小客户时,结果会被量化 ↗,甚至可能完全四舍五入为 0。
这表明,虽然大总体的 1% 或更小的样本可能足够,但我们可能需要为小总体存储更大比例的事件以获得准确结果。
我们通过称为公平采样的技术来实现这一点。这意味着我们会均衡存储每个唯一 index 值的事件数量。对于相对不常见的 index 值,我们可能会写入通过 writeDataPoint() 获得的所有数据点。但如果您向单个 index 值写入大量数据点,我们将开始采样。
以下是相同分布,但现在应用了(模拟的)公平采样:
您可能注意到此图与第一张图非常相似。但它只需要存储 <10% 的数据。较大系列的采样率实际上远低于 10%(即我们存储更大的采样间隔),但较小系列的采样率更高。
回顾上面的映射类比。无论显示地图区域大小如何,每个 index 值存储的数据点总数保持恒定。然而,地图的分辨率——每个像素代表的区域——会根据显示区域而变化。同样在这里,每个存储数据点代表的数据量会根据 index 中的数据点总数而变化。
公平采样确保在特定时间范围内为每个 index 维护相等数量的数据。然而,查询针对的时间跨度可能差异很大。有些查询可能只需要 10 分钟的数据快照,而其他查询可能需要分析跨越 10 周的数据——时间长 10,000 倍。
为解决此问题,我们采用称为 adaptive bit rate ↗(ABR)的方法。使用 ABR,覆盖更长时间范围的查询会从更高的采样间隔检索数据,使其能在固定时间限制内完成。简单来说,就像映射类比中屏幕尺寸或带宽是固定资源一样,完成查询所需的时间也是固定的。因此,无论涉及的数据量如何,我们都需要限制扫描的总行数以提供查询答案。这有助于确保公平:无论查询的底层数据集大小如何,我们都确保所有查询获得等量的可用计算时间份额。
为此,我们以多种分辨率(即不同详细程度,例如 100%、10%、1%)存储从公平采样数据派生的数据。查询时,我们根据查询复杂度选择最合适的数据分辨率。查询复杂度由要检索的行数和查询在 N 秒指定时间限制内完成的概率决定。通过动态选择适当的分辨率,我们优化查询性能并确保其在分配的时间预算内完成。
ABR 的显著优势是,无论数据大小或时间跨度如何,我们都能始终在固定查询预算内提供查询结果。这使其区别于在处理大型数据集时面临超时、错误或高成本的系统。
要在采样数据中获得准确结果,请选择适当的值作为 index。index 应匹配用户查询和查看数据的方式。例如,如果用户经常基于特定设备或 hostname 查看数据,建议将这些属性纳入 index。
index 具有以下属性,选择 index 时需要考虑:
- 获取整个数据集(跨所有 index 值)的准确汇总统计信息。
- 准确统计 index 唯一值的数量。
- 获取特定 index 值内准确的汇总统计信息(例如 count、sum)。
- 查看不在 index 中的特定字段的
Top N值。 - 筛选大多数字段。
- 运行其他聚合,如分位数。
需要考虑的一些限制和权衡:
- 您可能无法获得不在 index 中的字段的准确唯一计数。
- 例如,如果您在
hostname上建立 index,可能无法计数唯一 URL 的数量。
- 例如,如果您在
- 您可能无法观察到不在 index 中的字段的非常罕见的值。
- 例如,如果您在 host 上建立 index 且有数百万唯一 URL,则特定 hostname 的特定 URL。
- 您可能无法同时对多个 index 运行准确查询。
- 例如,您可能只能一次查询一个 host(或所有 host)并期望准确结果。
- 无法保证可以检索任何单个记录。
- 您不一定能重建确切的事件序列。
对于大多数用例,不建议在每行写入唯一的 index 值(如 UUID)。虽然这可以非常快速地检索单个数据点,但会减慢大多数聚合和时间序列查询。
有关采样的常见问题,请参阅 Workers Analytics Engine 常见问题中的采样。