InfluxDB IOx如何管理时间序列数据的数据生命周期

上个月我们宣布InfluxDB IOx(发音:eye-ox),一个新的基于Rust和Apache Arrow的InfluxDB核心.虽然InfluxDB IOx是构建在对象存储之上的柱状数据库,但这只是它的部分作用。除了查询功能外,InfluxDB IOx的一个重要目标是帮助管理时间序列数据的数据生命周期。本文将介绍InfluxDB IOx计划如何管理数据生命周期的设计。

时间序列数据的数据生命周期通常涉及某种实时摄取、用于异步复制和订阅的数据缓冲、用于查询的内存数据,以及以压缩格式写出大块不可变数据。将数据移入/移出内存和对象存储,删除高精度数据以释放空间,这就是InfluxDB IOx在数据生命周期中考虑的大部分内容。删除也被处理,但那些细节是另一篇文章。

用于监控、ETL和近期数据可视化的时间序列数据的实时性是InfluxDB IOx优化的目标。因为InfluxDB IOx使用对象存储和拼花由于它的持久性格式,我们可以将更大规模和更特别的处理推迟到非常适合该任务的系统。

InfluxDB IOx定义api和配置,以便在数据到达后台时管理数据的移动。它们可用于将数据发送到其他InfluxDB IOx服务器进行处理、查询或以提前写日志段或Parquet文件及其摘要的形式发送到对象存储。

数据在逻辑上是如何组织的

可查询的数据属于MutableBuffer、ReadBuffer或ObjectStore。MutableBuffer是实时写入土地的地方。它针对写进行了优化,但也可以查询。ReadBuffer用于保存来自MutableBuffer或ObjectStore的数据块,并针对压缩和查询速度进行优化。最后,ObjectStore以压缩格式保存不可变数据块(Parquet文件)以及数据摘要,以加快查询时间和缓存预热。

无论数据是在MutableBuffer、ReadBuffer还是ObjectStore中,它都有一个一致的逻辑组织来描述它。查询应该跨所有源工作,并在查询时进行组合。实时写入只能写入MutableBuffer,然后可以转换为Parquet文件形式的不可变块及其在对象存储中的摘要,或者在ReadBuffer中转换为具有摘要统计信息的只读内存块。

下面是一个数据如何逻辑组织的例子,其中分区是按天定义的:

在InfluxDB IOx中如何对时间序列数据进行逻辑组织

时间序列数据如何在InfluxDB IOx中进行逻辑组织

分区是由分区键定义的,分区键是在写入每行时为每行生成的字符串。当数据写入数据库或复制到其他服务器时,分区用于分离数据。分区键可以使用表名(度量)、列值(标记或字段)或时间列或任何具有时间数据类型的列的格式化时间字符串的任何组合。

块是数据的集合。Chunk中的所有行共享相同的分区键值。它们由表中存在的表、模式和汇总统计信息(min、max、count)定义。块对于缓冲数据非常有用,以后可以将数据更改为不可变,以便将它们移到ReadBuffer或ObjectStore中。

在分区中,块具有单调递增的标识符。这里的目标是帮助确定如果后来的写入覆盖了分区中较旧块中的某些数据,那么数据是按什么顺序写入的。InfluxDB IOx在与ObjectStore的交互中遵循单写入器、多读取器语义。这意味着InfluxDB IOx服务器可以在没有分布式协调的情况下写入并确保块顺序。但是,分区可以分布在多个写入器上。

虽然上图中的示例具有互斥的分区键,但这并不是严格的要求。生成分区键的规则可以随着时间的推移而改变,并且可以因服务器而异。

管理数据移动到对象存储

当数据写入InfluxDB IOx时,它会落在WAL缓冲区和/或MutableBuffer中。WAL Buffer是不可查询的,仅用于缓冲对数据库的写入和修改。这个缓冲区用于大致在数据到达时处理数据的订阅请求,或者作为一种将数据缓冲到WAL段的方式,然后将其写入对象存储。

每个InfluxDB IOx服务器都有一个唯一标识符,用作写入对象存储的任何文件的路径前缀。这种设计使InfluxDB IOx与ObjectStore的交互具有单写入器、多读取器的语义。这意味着编写人员不需要协调就能完成工作,并且可以在不影响编写人员管道或与之交互的情况下按需扩展读取器。

MutableBuffer可以用来处理查询工作负载,或者作为写入数据的暂存区,直到它被滚动并转换为ObjectStore或ReadBuffer中的chunk。

操作人员可以通过API调用或基于配置显式地控制数据移动。配置可以指定一个滚转事件,并基于以下一个或多个情况传送到对象存储:

  • 行计数(或WAL条目计数)
  • 大小(以字节为单位)(达到此数字后翻转)
  • 自第一次写入以来的时间(在此段或块打开后滚动X次)

在WAL缓冲区中,一个滚转将简单地创建下一个段号,并让新的段接受传入的WAL条目。然后可以将刚刚滚转的段复制到对象存储中。操作员可以定义何时删除旧的WAL段。这可以由请求触发,由时间触发(老化旧段),或者基于段被持久化到对象存储的块完全捕获的时间。

在MutableBuffer中,翻转会将给定Partition中当前打开的Chunk转换为只读的。如果在此之后写入到达该分区,则将使用下一个ID创建一个新块。一旦旧块是只读的,它就可以以Parquet文件的形式写入ObjectStore,并且它的摘要可以转换到ReadBuffer中。如果移动到ReadBuffer,从MutableBuffer Chunk到ReadBuffer Chunk的切换是原子的,因此查询只命中其中一个。

MutableBuffer和对象存储中的数据是按分区组织的,而WAL是为整个逻辑数据库而存在的。对不同分区的写入将落在同一个WAL中,当MutableBuffer中的partitions中的chunk被旋转时,它会独立地滚动。

结束

大部分工作目前正在进行中。这篇博文的细节来自我们正在工作的内部设计文档。我们还没有生产InfluxDB IOx的版本,因为还有很多工作要做。我们的目标是在2021年2月初有文档的alpha版本。我们将继续撰写有关InfluxDB IOx的设计选择的更多内容。

如果你对更多细节感兴趣,请在太平洋时间1月13日周三上午8点加入我们每月的InfluxDB IOx技术讲座和社区办公室时间.如果你错过了上周的InfluxDB IOx科技讲座,点击这里查看录音