Kapacitor 作为一个持续查询引擎
Kapacitor 可以用于执行与 InfluxDB 中的连续查询 (CQ) 相同的工作。今天我们将探讨选择使用其中一个而不是另一个的原因,以及使用 Kapacitor 处理 CQ 类型工作负载的基本知识。
一个示例
首先,我们来看看一个简单的CQ,并将其重写为Kapacitor TICKscript。
这是一个计算每5分钟cpu.usage_idle的平均值并将其存储在新测量mean_cpu_idle中的CQ。
CREATE CONTINUOUS QUERY cpu_idle_mean ON telegraf BEGIN SELECT mean("usage_idle") as usage_idle INTO mean_cpu_idle FROM cpu GROUP BY time(5m),* END
要在这里使用Kapacitor做同样的事情,这里是一个流式的TICKscript。
dbrp "telegraf"."autogen"
stream
|from()
.database('telegraf')
.measurement('cpu')
.groupBy(*)
|window()
.period(5m)
.every(5m)
.align()
|mean('usage_idle')
.as('usage_idle')
|influxDBOut()
.database('telegraf')
.retentionPolicy('autogen')
.measurement('mean_cpu_idle')
.precision('s')
在Kapacitor中也可以作为批处理任务完成相同的事情。
dbrp "telegraf"."autogen"
batch
|query('SELECT mean(usage_idle) as usage_idle FROM "telegraf"."autogen".cpu')
.period(5m)
.every(5m)
.groupBy(*)
|influxDBOut()
.database('telegraf')
.retentionPolicy('autogen')
.measurement('mean_cpu_idle')
.precision('s')
这三种方法将产生相同的结果。
问题
在这一点上,有几个问题我们应该回答:
- 我们什么时候应该使用Kapacitor而不是CQs?
- 我们何时应该在Kapacitor中使用流任务与批处理任务?
我们什么时候应该使用Kapacitor而不是CQs?
有几个理由可以选择使用Kapacitor而不是CQs。
- 您正在执行大量的 CQ,并希望将工作负载隔离开来。 通过使用 Kapacitor 进行聚合,InfluxDB 的性能特征可以保持更加稳定,并与 Kapacitor 的性能隔离。
- 您需要做的不仅仅是执行查询,例如,您可能只是想存储聚合中的异常值,而不是全部。
Kapacitor可以对数据执行比CQs显著更多的操作,因此您在转换数据时拥有更大的灵活性。
在一些使用场景中,使用CQs几乎总是有意义的。
- 为保留策略进行降采样。 这正是 CQs 的设计目的,并且做得很好。 如果您不需要,没必要在基础设施中添加另一个移动组件(即 Kapacitor)。 保持简单。
- 你只有少量的CQ,再次保持简单,除非你需要,不要在你的设置中增加更多的移动部件。
我们何时在Kapacitor中使用流任务与批处理任务?
基本上,答案归结为两个方面:可用的内存和所使用的时间段。
流任务必须在指定的时间内将所有数据保存在RAM中。如果这个时间段对于可用的RAM来说太长,那么您首先需要将数据存储在InfluxDB中,然后通过批处理任务进行查询。
流任务确实有一个小优势,因为它正在监视数据流,它通过数据上的时间戳理解时间。因此,对于给定点是否会进入窗口没有竞争条件。如果您正在使用批处理任务,仍然有可能一个点迟到而在窗口中被遗漏。
另一个例子
创建一个持续查询以跨保留策略进行下采样。
CREATE CONTINUOUS QUERY cpu_idle_median ON telegraf BEGIN SELECT median("usage_idle") as usage_idle INTO "telegraf"."sampled_5m"."median_cpu_idle" FROM "telegraf"."autogen"."cpu" GROUP BY time(5m),* END
流 TICKscript:
dbrp "telegraf"."autogen"
stream
|from()
.database('telegraf')
.retentionPolicy('autogen')
.measurement('cpu')
.groupBy(*)
|window()
.period(5m)
.every(5m)
.align()
|median('usage_idle')
.as('usage_idle')
|influxDBOut()
.database('telegraf')
.retentionPolicy('sampled_5m')
.measurement('median_cpu_idle')
.precision('s')
还有批处理 TICKscript:
dbrp "telegraf"."autogen"
batch
|query('SELECT median(usage_idle) as usage_idle FROM "telegraf"."autogen"."cpu"')
.period(5m)
.every(5m)
.groupBy(*)
|influxDBOut()
.database('telegraf')
.retentionPolicy('sampled_5m')
.measurement('median_cpu_idle')
.precision('s')
总结
Kapacitor 是一个强大的工具。 如果你需要比 CQs 提供的更大的灵活性,使用它。 有关从 InfluxQL 查询编写 TICKscripts 的更多信息和帮助,请查看这些 docs 在 Kapacitor 的 InfluxQL 节点上。 InfluxDB 查询语言中的每个函数都可以在 Kapacitor 中使用,因此你可以将任何查询转换为 Kapacitor TICKscript。
重要事项
连续查询和Kapacitor任务可能产生不同的结果
对于某些类型的查询,CQs(InfluxDB)和TICKscripts(Kapacitor)可能由于各自选择时间边界的方式而返回不同的结果。Kapacitor选择最大时间戳(tMax),而InfluxDB选择最小时间戳(tMin)。在InfluxDB中使用tMax或tMin之间的选择在某种程度上是任意的,但对于Kapacitor来说则不能这样说。
Kapacitor 有能力在重叠时间窗口上执行复杂的连接操作。 例如,如果您要将上个月的平均值与前一天的平均值连接起来, 您需要它们的结果值在相同时间出现,使用最近的时间 tMax。 然而,Kapacitor 会使用 tMin,结果值不会在相同时间出现。 一个将在上个月的开始,而另一个将在前一天的开始。
考虑以下查询,作为InfluxQL查询和TICKscript运行:
InfluxQL
SELECT mean(*) FROM ... time >= '2017-03-13T17:50:00Z' AND time < '2017-03-13T17:51:00Z'
TICKscript
batch
|query('SELECT queryDurationNs FROM "_internal".monitor.queryExecutor')
.period(1m)
.every(1m)
.align()
|mean('queryDurationNs')
查询结果
| 查询方法 | 时间 | 平均值 |
|---|---|---|
| 连续查询 | 2017-03-13T17:50:00Z | 8.083532716666666e+08 |
| TICKscript | 2017-03-13T17:51:00Z | 8.083532716666666e+08 |
请注意返回的时间戳之间的差异。
这是一个在问题 #1258中讨论的已知问题。