InfluxDB IOx 如何管理时间序列数据的数据生命周期
作者 Paul Dix / 产品, 用例, 开发者
2020年12月17日
导航至
上个月,我们发布了 InfluxDB IOx(发音:eye-ox),这是一个基于 Rust 和 Apache Arrow 的 InfluxDB 新核心。虽然 InfluxDB IOx 是一个构建在对象存储之上的列式数据库,但这只是其角色的一部分。除了查询功能外,InfluxDB IOx 的一个重要目标是帮助管理时间序列数据的数据生命周期。本文将介绍 InfluxDB IOx 计划如何管理数据生命周期的设计。
时间序列数据的数据生命周期通常涉及某种实时摄取、用于异步复制和订阅的数据缓冲、用于查询的内存数据,以及以压缩格式写出大量不可变数据块。再加上数据在内存和对象存储之间的移动、移除高精度数据以释放空间,这就是 InfluxDB IOx 在数据生命周期方面考虑的大部分内容。删除操作也已处理,但这些细节将在另一篇文章中介绍。
对于监控、ETL 和最近数据的可视化,时间序列数据的实时性是 InfluxDB IOx 优化的重点。由于 InfluxDB IOx 使用对象存储和 Parquet 作为其持久化格式,我们可以将更大规模和更临时的处理推迟到更适合该任务的系统。
InfluxDB IOx 定义了 API 和配置,以管理数据在到达时以及定期在后台的移动。这些 API 和配置可用于将数据发送到其他 InfluxDB IOx 服务器进行处理、查询,或以预写日志段或 Parquet 文件及其摘要的形式发送到对象存储。
数据如何进行逻辑组织
可查询的数据分为 MutableBuffer、ReadBuffer 或 ObjectStore。MutableBuffer 是实时写入数据落入的地方。它针对写入进行了优化,但也可以进行查询。ReadBuffer 是保存来自 MutableBuffer 或 ObjectStore 的数据块并针对压缩和查询速度进行优化的地方。最后,ObjectStore 是以压缩格式(Parquet 文件)保存不可变数据块以及数据摘要以加快查询时间和缓存预热的地方。
无论数据是在 MutableBuffer、ReadBuffer 还是 ObjectStore 中,它都具有描述它的统一逻辑组织。查询应跨所有来源工作,并在查询时进行组合。实时写入只能写入到 MutableBuffer 中,然后可以将其转换为不可变的块,以 Parquet 文件及其摘要的形式存储在对象存储中,或者作为带有摘要统计信息的只读内存块存储在 ReadBuffer 中。
这是一个数据如何逻辑组织的示例,其中分区已按天定义
<figcaption> 时间序列数据在 InfluxDB IOx 中如何进行逻辑组织</figcaption>
分区由其分区键定义,分区键是一个字符串,在写入每一行数据时生成。分区用于分隔写入数据库或复制到其他服务器的数据。分区键可以使用表名(measurement)、列值(标签或字段)的任意组合,或者来自时间列或任何具有时间数据类型的列的格式化时间字符串。
Chunk 是数据的集合。一个 Chunk 中的所有行共享相同的分区键值。它们由其中存在的表、它们的模式和它们的摘要统计信息(最小值、最大值、计数)定义。Chunk 可用于缓冲数据,这些数据稍后可以更改为不可变的,以便可以将它们移动到 ReadBuffer 或 ObjectStore。
在一个分区内,chunk 具有单调递增的标识符。这里的目标是帮助确定数据的写入顺序,如果稍后的写入覆盖了分区内较旧 chunk 中的某些数据。InfluxDB IOx 在与 ObjectStore 交互时遵循单写多读语义。这意味着 InfluxDB IOx 服务器可以写入并确保 chunk 顺序,而无需分布式协调。但是,分区可以分布在多个写入器中。
虽然上面图表中的示例具有互斥的分区键,但这并不是严格的要求。生成分区键的规则可能会随时间变化,并且可能因服务器而异。
管理数据移动到对象存储
当数据写入 InfluxDB IOx 时,它会落入 WAL Buffer 和/或 MutableBuffer 中。WAL Buffer 不可查询,仅用于缓冲写入和对数据库的修改。此缓冲区对于处理数据到达时的大致订阅请求或作为将数据缓冲到 WAL 段中的一种方式非常有用,然后将其写入对象存储。
每个 InfluxDB IOx 服务器都有一个唯一标识符,该标识符用作写入对象存储的任何文件路径中的前缀。这种设计赋予 InfluxDB IOx 与 ObjectStore 的交互单写多读的语义。这意味着写入器无需协调即可完成其工作,并且可以根据需要扩展读取器,而不会对写入器管道产生任何影响或交互。
MutableBuffer 可用于处理查询工作负载,或用作写入数据的暂存区,直到将其滚动并转换为 ObjectStore 或 ReadBuffer 中的 Chunk。
操作员可以通过 API 调用显式控制此数据移动,也可以基于配置进行控制。配置可以指定基于以下一个或多个条件进行滚动事件和传输到对象存储
- 行数(或 WAL 条目数)
- 字节大小(达到此数字后滚动)
- 自首次写入以来的时间(此段或 chunk 已打开 X 时间后滚动)
在 WAL Buffer 中,滚动只会创建下一个段号,并使新段接受传入的 WAL 条目。刚滚动的段随后可以复制到对象存储。操作员可以定义何时删除旧的 WAL 段。这可以由请求、时间(旧段老化)触发,或者基于段何时被已持久化到对象存储的 Chunk 完全捕获。
在 MutableBuffer 中,滚动会将给定分区中当前打开的 Chunk 转换为只读。如果在此之后有写入到达该分区,则将使用下一个 ID 创建一个新的 chunk。一旦较旧的 chunk 变为只读,就可以以 Parquet 文件形式写入 ObjectStore,并且可以将其摘要转换为 ReadBuffer。如果移动到 ReadBuffer,则从 MutableBuffer Chunk 到 ReadBuffer Chunk 的切换是原子的,以便查询仅命中其中一个。
虽然 MutableBuffer 和对象存储中的数据按分区组织,但 WAL 存在于整个逻辑数据库中。对不同分区的写入将落入同一 WAL 中,该 WAL 的滚动独立于 MutableBuffer 中分区的 Chunk 何时轮换。
总结
这项工作的大部分目前正在进行中。这篇博文的详细信息来自我们正在使用的内部设计文档。我们尚未生成 InfluxDB IOx 的构建版本,因为还有很多工作要做。我们的目标是在 2021 年 2 月初发布带有文档的 alpha 构建版本。我们将随着工作的进行撰写更多关于 InfluxDB IOx 设计选择的文章。
如果您有兴趣了解更多细节,请于 1 月 13 日星期三太平洋时间上午 8 点参加我们的下一次每月 InfluxDB IOx 技术讲座和社区办公时间。 如果您错过了上周的 InfluxDB IOx 技术讲座,请点击此处观看录像。