On this page
Aggregation
OpenTSDB 旨在在查询执行期间有效地组合多个不同的时间序列。这样做的原因是,当用户查看其数据时,通常他们会从较高的级别开始询问诸如“我的数据中心总吞吐量是多少?”之类的问题。或“按区域划分的当前功耗是多少?”。在查看了这些较高的值之后,可能会突出一个或多个值,因此用户可以向下钻取更细粒度的数据集,例如“我的 LAX 数据中心中的主机吞吐量是多少?”。我们希望轻松回答这些高级问题,但仍然允许深入了解更多细节。
但是,如何将多个单独的时间序列合并为一个数据序列呢?聚合函数提供了将不同时间序列 math 合并为一个的方法。过滤器用于按标签对结果进行分组,然后将汇总应用于每个组。聚合类似于 SQL 的GROUP BY子句,用户可以选择 sched 义的聚合函数将多个记录合并为单个结果。但是,在 TSD 中,每个时间戳和组会汇总一组记录。
每个聚合器都有两个组件:
功能 -应用的 math 计算,例如对所有值求和,计算平均值或选择最高值。
插值 -一种处理丢失值的方法,例如当时间序列* A 在 T1 处有值,而时间序列 B *没有值时。
本文档重点介绍如何在* group by *上下文中使用聚合器,即在将多个时间序列合并为一个时。此外,可以使用聚合器对时间序列进行下采样(即返回较低分辨率的结果集)。有关更多信息,请参见Downsampling。
Aggregation
在将每个时间序列集合进行“聚合”或“分组”时,每个时间序列中的时间戳将对齐。然后,对于每个时间戳,所有时间序列中的值都将汇总为一个新的数值。也就是说,聚合器将在每个时间戳上跨所有时间序列“工作”。将原始数据视为矩阵或表格,如以下示例所示,该示例说明sum聚合器在两个时间序列A和B上工作以产生新的时间序列Output。
| Time Series | t0 | t0+10s | t0+20s | t0+30s | t0+40s | t0+50s |
|---|---|---|---|---|---|---|
| A | 5 | 5 | 10 | 15 | 20 | 5 |
| B | 10 | 5 | 20 | 15 | 10 | 0 |
| Output | 15 | 10 | 30 | 30 | 30 | 5 |
对于时间戳t0,将A和B的数据点相加,即5 + 10 == 15。接下来,将ts1的两个值相加在一起得出10,依此类推。在 SQL 中,这看起来像SELECT SUM(value) FROM ts_table GROUP BY timestamp。
Interpolation
在上面的示例中,时间序列A和B在每个时间戳上都有数据点,它们排列整齐。但是,如果两个系列不对齐怎么办?同步所有数据源以在完全相同的时间进行写入可能很困难,有时甚至是不希望的。例如,如果我们有 10,000 台服务器每 5 分钟发送 100 个系统 Metrics,那将在一秒钟内爆发 10M 数据点。我们需要一个功能强大的网络和群集来容纳该流量。更不用说系统将闲置 4 分钟 59 秒。取而代之的是随着时间的推移扩展写操作更为有意义,因此我们平均每秒可以进行 3333 次写操作,以减少硬件和网络需求。
Missing Data
“丢失”仅表示时间序列在给定的时间戳上没有数据点。通常,数据只是在请求的时间戳之前或之后进行时移,但是如果源或 TSD 遇到错误并且未记录数据,则实际上可能会丢失数据。某些时间序列 DB 可能允许在时间戳上存储NaN来表示不可记录的值,但 OpenTSDB 尚不允许此值。
您如何“求和”或找到一个数不存在的“平均值”?一个人的本能是只返回有效的数据点并完成它。但是,如果您要像上面那样处理成千上万个数据点完全不对齐的源,该怎么办?例如,下图显示了一个时间序列,其中写入未对齐,从而导致锯齿状的线条使读取变得混乱:

或者,您可以简单地忽略给定时间戳记中所有时间序列的数据点,其中任何序列都缺少数据。但是,如果您有两个时间序列并且它们只是未对齐,那么即使存储中有良好的数据,查询也会返回一个空的数据集,因此不一定很有用。
另一种选择是定义一个标量值(例如0或 Long 的最大值),以便在缺少数据点时使用。 OpenTSDB 2.0 和更高版本提供了一些聚合方法,这些方法可以用标量值替代丢失的数据点,实际上,上图是使用zimsum聚合器生成的,该聚合器将未对齐的值替换为零。当使用不同的价值时间序列(例如,给定时间的销售总数)时,这种替换很有用,但在处理平均值或视觉上验证图表看起来“不错”时,这种替换无效。
OpenTSDB 提供的一个答案是使用定义明确的数字分析方法interpolation来猜测该时间点的值。插值使用时间序列的现有数据点来计算请求的时间戳时的“最佳猜测”值。使用 OpenTSDB 的线性插值,我们可以平滑未对齐的图形以获得:

对于一个数字示例,请看一下这两个时间序列,其中源每 20 秒发布一次值,而数据仅偏移 10 秒:
| Time Series | t0 | t0+10s | t0+20s | t0+30s | t0+40s | t0+50s | t0+60s |
|---|---|---|---|---|---|---|---|
| A | na | 5 | na | 15 | na | 5 | na |
| B | 10 | na | 20 | na | 10 | na | 20 |
当 OpenTSDB 计算聚合时,它从为任何系列找到的第一个数据点开始,在这种情况下,它将是B在t0的数据。我们在t0处请求A的值,但那里没有任何数据。我们知道在t0+10s处有A的数据,但是由于在此之前没有任何值,因此我们无法猜测它的值。因此,我们只需返回B的值。
接下来,我们在时间t0+10s遇到A的值。我们要求时间序列B中的t0+10s的值,但没有一个。但是B知道t0+20s处有一个值,而我们在t0处有一个值,因此我们现在可以计算t0+10s的猜测值。线性插值的公式为y = y0 + (y1 - y0) * ((x - x0) / (x1 - x0)),其中对于系列B,y0 = 10,y1 = 20,x = t0+10s (or 10),x0 = t0 (or 0)和x1 = t0+20s (or 20)。因此,我们有y = 10 + (20 - 10) * ((10 - 0) / (20 - 0),它将减少到y = 10 + 10 * (10 / 20),进一步减少到y = 10 + 10 * .5和y = 10 + 5。因此B将在t0+10s给我们一个15的估计值。
遍历每个时间戳的迭代都会 continue 进行,每个时间戳都会为作为查询一部分返回的每个序列找到一个数据点。使用 sum 聚合器的结果系列如下所示:
| series | t0 | t0+10s | t0+20s | t0+30s | t0+40s | t0+50s | t0+60s |
|---|---|---|---|---|---|---|---|
| A | na | 5 | na | 15 | na | 5 | na |
| B | 10 | na | 20 | na | 10 | na | 20 |
| Interpolated A | 10 | 10 | |||||
| Interpolated B | 15 | 15 | 15 | na | |||
| Summed Result | 10 | 20 | 30 | 25 | 20 | 20 | 20 |
更多示例: 对于图形倾斜的用户,我们有以下示例。一个名为m的虚构度量记录在 OpenTSDB 中。 “ m 之和”是由类似start=1h-ago&m=sum:m的查询产生的顶部的蓝线。它由host=foo的红线和host=bar的绿线之和组成:

从上图可以直观看出,如果“堆叠”红线和绿线,则会得到蓝线。在任何离散的时间点,蓝线的值等于当时红线和绿线的值之和。如果不进行插值,则您会变得有些不直观,更难以理解,并且也没有那么有意义和有用:

请注意,蓝线如何在 18:46:48 下降到绿色数据点。无需成为 math 家或参加高级 math 类即可看到需要插值来正确地将多个时间序列聚合在一起并获得有意义的结果。
目前,OpenTSDB 主要支持linear interpolation(有时简称“ lerp”)以及一些聚合器,这些聚合器将简单地替换零或最大值或最小值。欢迎那些想添加其他插值方法的人使用补丁。
仅当发现多个时间序列与查询匹配时,才在查询时间执行插值。许多度量标准收集系统都在* write *上进行插值,因此永远不会记录您的原始值。 OpenTSDB 存储您的原始值,并允许您随时检索它。
这是来自邮件列表的另一个稍微复杂的示例,描述了如何平均计算多个时间序列:

带有三角形的蓝色粗线是根据查询start=1h-ago&m=avg:duration_seconds具有多个时间序列的avg函数的集合。如我们所见,结果时间序列在其汇总的所有基础时间序列的每个时间戳上都有一个数据点,并且该数据点是通过对该时间点上所有时间序列的值取平均值来计算的。对于平方紫色时间序列的孤独数据点也是如此,它暂时提高了平均值直到下一个数据点。
Note
聚合函数根据 Importing 数据点返回整数或双精度值。如果两个源值在存储中都是整数,则结果计算将是整数。这意味着计算得出的任何小数值将被舍弃,不会进行舍入。如果任一数据点都是浮点值,则结果将是浮点。但是,如果启用了降采样或速率,则结果将始终是浮点型。
Downsampling
如上所述,插值是处理丢失数据的一种方法。但是一些用户讨厌线性插值是一种说谎数据的方式,因为它会生成幻像值。相反,处理未对齐值的一种方法是通过下采样。例如,如果源每分钟报告一个值,但在该分钟内它们的时间偏斜,则对源数据上的每个查询在 1 分钟内进行下采样。这样的结果是将值捕捉到每个时间序列中的相同时间戳,从而主要避免了插值。当下采样* bucket *缺少值时,插值仍然会发生。
有关避免插值的详细信息和示例,请参见Downsampling。
Note
通常,对每个要包含多个时间序列的查询进行下采样是一个很好的理想选择。
Available Aggregators
以下是 OpenTSDB 中可用的聚合功能的描述。请注意,有些仅应用于分组,而另一些仅用于下采样。
| Aggregator | TSD Version | Description" | Interpolation |
|---|---|---|---|
| avg | 1.0 | 平均数据点 | Linear Interpolation |
| count | 2.2 | 集合中原始数据点的数量 | 如果丢失,则为零 |
| dev | 1.0 | 计算标准偏差 | Linear Interpolation |
| ep50r3 | 2.2 | 使用 R-3 方法计算估计的 50%* | Linear Interpolation |
| ep50r7 | 2.2 | 用 R-7 方法计算估计的 50%* | Linear Interpolation |
| ep75r3 | 2.2 | 用 R-3 方法计算估计的第 75 个百分位数* | Linear Interpolation |
| ep75r7 | 2.2 | 用 R-7 方法计算估计的第 75 个百分位数* | Linear Interpolation |
| ep90r3 | 2.2 | 使用 R-3 方法计算估计的 90%* | Linear Interpolation |
| ep90r7 | 2.2 | 使用 R-7 方法计算估计的 90%* | Linear Interpolation |
| ep95r3 | 2.2 | 使用 R-3 方法计算估计的 95%* | Linear Interpolation |
| ep95r7 | 2.2 | 使用 R-7 方法计算估计的 95%* | Linear Interpolation |
| ep99r3 | 2.2 | 用 R-3 方法计算估计的 99%* | Linear Interpolation |
| ep99r7 | 2.2 | 用 R-7 方法计算估计的 99%* | Linear Interpolation |
| ep999r3 | 2.2 | 使用 R-3 方法计算估计的第 999 个百分点* | Linear Interpolation |
| ep999r7 | 2.2 | 使用 R-7 方法计算估计的第 999 个百分点* | Linear Interpolation |
| first | 2.3 | 返回集合中的第一个数据点。仅适用于下采样,不适用于汇总。 | Indeterminate |
| last | 2.3 | 返回集合中的最后一个数据点。仅适用于下采样,不适用于汇总。 | Indeterminate |
| mimmin | 2.0 | 选择最小的数据点 | 如果丢失则最大 |
| mimmax | 2.0 | 选择最大的数据点 | 最小(如果丢失) |
| min | 1.0 | 选择最小的数据点 | Linear Interpolation |
| max | 1.0 | 选择最大的数据点 | Linear Interpolation |
| none | 2.3 | 跳过所有时间序列的分组。 | 如果丢失,则为零 |
| p50 | 2.2 | 计算第 50 个百分位数 | Linear Interpolation |
| p75 | 2.2 | 计算第 75 个百分位数 | Linear Interpolation |
| p90 | 2.2 | 计算第 90 个百分位数 | Linear Interpolation |
| p95 | 2.2 | 计算第 95 个百分位数 | Linear Interpolation |
| p99 | 2.2 | 计算第 99 个百分位数 | Linear Interpolation |
| p999 | 2.2 | 计算第 999 个百分位数 | Linear Interpolation |
| sum | 1.0 | 将数据点加在一起 | Linear Interpolation |
| zimsum | 2.0 | 将数据点加在一起 | 如果丢失,则为零 |
*有关百分位数的计算,请参阅Wikipedia文章。对于高基数计算,使用估计的百分位数可能更有效。
Avg
计算下采样时段或多个时间序列中所有值的平均值。此函数将在时间序列上执行线性插值。对于查看量表 Metrics 很有用。
Note
即使计算通常会得出浮点值,但如果将数据点记录为整数,则返回的整数将失去一些精度。
Count
返回存储在系列或范围中的数据点数。当用于汇总多个系列时,零将被替换。与下采样一起使用时,它将反映每个下采样* bucket *中的数据点数。当用于分组聚合时,以给定时间的值反映时间序列的数量。
Dev
计算时段或时间序列中的standard deviation。此函数将在时间序列上执行线性插值。对于查看量表 Metrics 很有用。
Note
即使计算通常会得出浮点值,但如果将数据点记录为整数,则返回的整数将失去一些精度。
Estimated Percentiles
使用选择的算法计算各种百分位数。这些对于包含许多数据点的序列很有用,因为某些数据可能会被排除在计算之外。当用于汇总多个序列时,该函数将执行线性插值。有关详情,请参见Wikipedia。通过Apache Math 库。实现
第一和最后
这些聚合器将在下采样间隔中返回第一个或最后一个数据点。例如。如果缩减采样桶包含系列2, 6, 1, 7,则first聚合器将返回1,而last将返回7。请注意,此聚合器仅对下采样器有用。
Warning
当用作分组聚合器时,结果是不确定的,因为从存储检索到并保存在内存中的时间序列的 Sequences 在 TSD 与 TSD 或执行与执行之间不一致。
Max
min的倒数,它返回所有时间序列或某个时间范围内的最大数据点。此函数将在时间序列上执行线性插值。这对于查看 Metrics 的上限很有用。
MimMin
“如果缺少最小值,则最大值”功能仅返回所有时间序列或时间 Span 内的最小数据点。该函数将不执行插值,如果缺少该值,它将返回指定数据类型的最大值。这将返回 Long.MaxValue(整数点)或 Double.MaxValue(浮点值)。有关详情,请参见原始数据类型。这对于查看 Metrics 的下限很有用。
MimMax
“如果缺少最大值,则最小值”功能仅返回所有时间序列或时间范围内的最大数据点。该函数将不执行插值,如果缺少该值,它将返回指定数据类型的最小值。这将返回 Long.MinValue(整数点)或 Double.MinValue(浮点值)。有关详情,请参见原始数据类型。这对于查看 Metrics 的上限很有用。
Min
仅返回所有时间序列或时间范围内的最小数据点。此函数将在时间序列上执行线性插值。这对于查看 Metrics 的下限很有用。
None
按汇总跳过组。该聚合器对于从存储中获取* raw *数据很有用,因为它将为每个与过滤器匹配的时间序列返回一个结果集。请注意,如果与降采样器一起使用,查询将引发异常。
Percentiles
计算各种百分位数。当用于汇总多个序列时,该函数将执行线性插值。通过Apache Math 库。实施
Sum
计算来自所有时间序列的所有数据点的总和,或者在向下采样的时间范围内。这是 GUI 的默认聚合功能,因为在组合多个时间序列(例如仪表或计数器)时,它通常是最有用的。当数据点无法对齐时,它将执行线性插值。如果您要累加一系列独特的值,并且不需要插值,请查看zimsum
ZimSum
从所有时间序列或时间 Span 中计算指定时间戳上所有数据点的总和。该函数不执行插值,而是用0代替丢失的数据点。在使用离散值时,这很有用。
Listing Aggregators
通过在 TSD 上运行的 HTTP API,用户可以查询/api/aggregators以获得在 TSD 上实现的聚合器列表。