文档

InfluxQL 内部原理

了解 InfluxQL 的实现,以理解结果是如何处理的以及如何创建高效的查询

查询生命周期

  1. InfluxQL 查询字符串被标记化,然后解析为抽象语法树 (AST)。这是查询本身的代码表示。

  2. AST 被传递给 QueryExecutor,它将查询定向到适当的处理程序。例如,与元数据相关的查询由 元服务 执行,而 SELECT 语句由分片本身执行。

  3. 查询引擎然后确定与 SELECT 语句的时间范围匹配的分片。从这些分片中,为语句中的每个字段创建迭代器。

  4. 迭代器被传递给发射器,发射器消耗它们并连接生成的结果点。发射器的任务是将简单的时间/值点转换为返回给客户端的更复杂的结果对象。

理解迭代器

迭代器提供了一个简单的接口,用于循环遍历一组点。例如,这是一个 Float 点的迭代器

type FloatIterator interface {
    Next() *FloatPoint
}

这些迭代器通过 IteratorCreator 接口创建

type IteratorCreator interface {
    CreateIterator(opt *IteratorOptions) (Iterator, error)
}

IteratorOptions 提供了关于字段选择、时间范围和维度的参数,迭代器创建器在规划迭代器时可以使用这些参数。IteratorCreator 接口在多个级别上使用,例如 ShardsShardEngine。这允许在适用时执行优化,例如返回预先计算的 COUNT()

迭代器不仅仅用于从存储中读取原始数据。迭代器可以组合,以便它们围绕输入迭代器提供额外的功能。例如,DistinctIterator 可以计算输入迭代器每个时间窗口的唯一值。或者 FillIterator 可以生成输入迭代器中缺失的额外点。

这种组合也非常适合聚合。例如,在以下 SQL 中,MEAN(value) 是一个 MeanIterator,它包装了来自底层分片的迭代器

SELECT MEAN(value) FROM cpu GROUP BY time(10m)

以下示例使用额外的迭代器 (DERIVATIVE()) 包装 MEAN(value),以确定平均值的导数

SELECT DERIVATIVE(MEAN(value), 20m) FROM cpu GROUP BY time(10m)

游标

游标 通过分片在元组(时间,值)中标识单个序列(measurement, tag set 和 field)的数据。游标遍历以日志结构合并树形式存储的数据,并处理跨级别的去重、已删除数据的 tombstone 以及合并缓存(Write Ahead Log)。游标按时间升序或降序对 (time, value) 元组进行排序。

例如,一个查询评估 3 个分片上 1,000 个序列的一个字段,将构造至少 3,000 个游标(每个分片 1,000 个)。

辅助字段

由于 InfluxQL 允许用户使用选择器函数,例如 FIRST()LAST()MIN()MAX(),因此引擎必须提供一种方法,在返回所选点的同时返回相关数据。

让我们看一下以下查询

SELECT FIRST(value), host FROM cpu GROUP BY time(1h)

我们正在选择每小时发生的第一个 value,但我们也想检索与该点关联的 host。由于 Point 类型为了效率只指定一个类型化的 Value,我们将 host 推送到点的辅助字段中。这些辅助字段附加到点上,直到它被传递到发射器,在那里字段被拆分到它们自己的迭代器。

内置迭代器

有许多辅助迭代器可以帮助我们构建查询

  • Merge Iterator - 此迭代器将一个或多个迭代器组合成一个相同类型的新迭代器。此迭代器保证在一个窗口内的所有点将在开始下一个窗口之前输出,但不提供窗口内的排序保证。这允许对不需要更强排序保证的聚合查询进行快速访问。

  • Sorted Merge Iterator - 与 MergeIterator 类似,此迭代器将一个或多个迭代器组合成一个相同类型的新迭代器。但是,此迭代器保证每个点的时间顺序。这使其比 MergeIterator 慢,但这种排序保证对于返回原始数据点的非聚合查询是必需的。

  • Limit Iterator - 此迭代器限制每个名称或标签组的点数。这是 LIMITOFFSET 语法的实现。

  • Fill Iterator - 如果输入迭代器中缺少点,则此迭代器会注入额外的点。它可以提供 null 点、具有先前值的点或具有特定值的点。

  • Buffered Iterator - 此迭代器提供了将点“取消读取”回缓冲区的功能,以便下次可以再次读取它。这广泛用于为窗口化提供预读。

  • Reduce Iterator - 此迭代器为窗口中的每个点调用一个归约函数。当窗口完成时,将输出该窗口的所有点。这用于简单的聚合函数,例如 COUNT()

  • Reduce Slice Iterator - 此迭代器首先收集窗口的所有点,然后一次性将它们全部传递给归约函数。结果从迭代器返回。这用于聚合函数,例如 DERIVATIVE()

  • Transform Iterator - 此迭代器为来自输入迭代器的每个点调用一个转换函数。这用于执行二进制表达式。

  • Dedupe Iterator - 此迭代器仅输出唯一点。由于它资源密集型,因此此迭代器仅用于小型查询,例如元查询语句。

调用迭代器

InfluxQL 中的函数调用在两个级别上实现

  • 某些调用可以在多个层级包装以提高效率。例如,COUNT() 可以在分片级别执行,然后多个 CountIterator 可以用另一个 CountIterator 包装,以计算所有分片的计数。这些迭代器可以使用 NewCallIterator() 创建。

  • 某些迭代器更复杂,或者需要在更高的级别上实现。例如,DERIVATIVE() 函数需要在执行计算之前检索窗口的所有点。此迭代器由引擎本身创建,并且永远不会被要求由较低级别创建。


此页是否对您有帮助?

感谢您的反馈!


Flux 的未来

Flux 即将进入维护模式。您可以继续像现在一样使用它,而无需对您的代码进行任何更改。

阅读更多

现已全面上市

InfluxDB 3 Core 和 Enterprise

快速启动。更快扩展。

获取更新

InfluxDB 3 Core 是一个开源、高速、近实时数据引擎,可以实时收集和处理数据,并将其持久化到本地磁盘或对象存储。InfluxDB 3 Enterprise 构建在 Core 的基础上,增加了高可用性、读取副本、增强的安全性以及数据压缩,从而实现更快的查询和优化的存储。InfluxDB 3 Enterprise 的免费层级可供非商业家庭或业余爱好者使用。

有关更多信息,请查看