
要点
InfluxDB 3 是对核心数据库引擎的全面重构,旨在通过提升基数、提供更经济的对象存储以及添加 SQL 支持来扩展现有产品的功能。
团队没有沿用原有的技术栈,而是选择了 FDAP 技术栈(Arrow Flight、DataFusion、Apache Arrow 和 Parquet)。
Rust 因其卓越的性能、内存安全性和“无畏并发”而被选为 InfluxDB 3 的核心开发语言,这解决了之前使用 Go 语言实现 InfluxDB 时遇到的各种挑战。
最新版本增强了分析查询功能,支持无限基数数据,并将 SQL 定位为主要查询语言,从而更高效地与第三方工具集成。
在未来的更新中,我们将集成 Apache Iceberg,使 InfluxDB 中采集的数据可供数据湖和数据仓库(包括 Databricks 和 Snowflake)使用。
四年前,InfluxData 开始研发 InfluxDB 的新核心,以应对现代时间序列负载日益增长的需求。这个决定并非轻率作出,而是由支持特定客户需求的需要驱动的。这些需求包括无限的基数、更便宜的对象存储(用于历史数据)、对 SQL 语言的支持,以及对我们文件格式和标准的更广泛的生态系统支持。
这些努力的成果是 InfluxDB 3,一个为时间序列优化的实时、列式数据库,使用 Rust 语言和 FDAP 堆栈(Apache Flight、DataFusion、Arrow 和 Parquet)构建。新核心代表了我们核心数据库技术的显著改进。它移除了基数限制,以便用户可以引入大量时间序列数据,还能实现无限扩展,具备 SQL 查询能力、分层数据存储和快速分析查询。
这篇文章重点介绍了这些核心技术选项和 InfluxDB 3 提供的新功能。
从一开始,InfluxDB 的愿景就不只是做一个时间序列数据库。我们想要一个能够大规模存储原始事件、处理所有形式的观测数据,并按需生成时间序列以满足多样化的分析任务的平台,无论是实时还是历史背景。我们的目标是创建一个能够管理时间序列、观测和历史数据的数据库,将其从单纯的指标存储转变为高级分析的全面解决方案。
InfluxDB 的演变
当我们在 2016 年发布 InfluxDB 1.0 时,它是用 Go 语言编写的,并且有一个我们从头开始构建并特别对指标负载优化的自研存储引擎。我们称之为时间结构化合并树(TSM),是日志结构化合并树(LSM)的一个变体。TSM 的设计将时间序列存储与内存中倒排索引配对,将元数据映射到底层的时间序列。
这为低至中等基数负载提供了出色的性能,但随着倒排索引中元数据量的增加,数据库性能受到了影响。其他时间序列数据库也广泛采用了类似的结构,如 Facebook Gorilla、Prometheus 等。
基数限制一直是时间序列数据库面临的挑战,因为包含大量个别时间序列的数据集会导致性能下降。我们引入了时间序列索引(TSI)来解决这个问题,将索引扩展到跨越磁盘和内存。该功能在 2017 年 11 月发布的 1.4 版本中正式发布,我们可以支持基数在数千万到可能的一亿的负载。尽管如此,它仍然无法为我们所需的分析查询提供足够的性能。
我们在 2020 年的下一个版本,InfluxDB 2.x,通过新的脚本语言、UI 和多租户、基于使用的 SaaS 平台扩展了核心功能。然而,用户需要的是无限的基数、更实惠的对象存储和增强的查询性能,而不是新的脚本语言。实现这些需求需要在底层架构上进行根本性的转变。
2020 年 11 月,我们宣布了 InfluxDB IOx(最终成为 InfluxDB 3),我们的计划是重新设计数据库以满足高分辨率负载的需求。我们认识到,要完全实现我们对 InfluxDB 的愿景,需要对数据库进行彻底的重新架构,我们之前已经确定了几种可能改变游戏规则的 OLAP 技术。在验证了这些好处之后,我们使用 Rust 和 Apache Arrow、Apache DataFusion、Apache Parquet 和 Arrow Flight 重建了新核心。我们创造了 FDAP 堆栈这个术语来描述这个堆栈。随着时间的推移,这种基础工具的选择演变成了一个复杂的分析系统构建堆栈。这些构建块是开放数据系统、实时分析、数据湖和数据仓库架构的未来。
InfluxDB 3 的发布提供了一个强大、灵活且高性能的数据库,满足了我们处理所有形式的时间序列、观测和历史数据的原始愿景,具有无与伦比的性能和规模。我们还整合了客户请求的功能:支持高基数数据、同时对多个时间序列进行分析查询、更经济的用于历史数据的对象存储,以及其他增强功能。我们的目标是与更广泛的第三方工具集成,并主要支持 SQL 作为一流的查询语言。
为未来重建:为什么选择 Rust?
在 2020 年初,我对 Rust 非常感兴趣,并认为它将是实现高性能、服务端软件的首选语言。当我们评估 InfluxDB 的未来时,很明显,实现我们的长期愿景需要根本性的重构。考虑到这一点,我们选择使用 2020 年最好的工具来构建,而不是 2013 年我们创建 InfluxDB 1.0 时可用的最佳语言,即 Go。Go 的简单性和性能为我们服务得很好;它非常适合构建 InfluxDB 所需的并发、分布式系统。我们将继续在 InfluxData 的许多项目中使用它。
然而,当涉及到 v3 时,使用 Rust 构建核心以实现最大效率是至关重要的。Rust 提供了卓越的性能、内存安全性,以及 Rust 社区所说的无畏并发性。Rust 为无畏并发性提供的保证是颠覆性的,消除了在其他语言(比如 Go)中难以追踪和修复的一整个类别的错误。与 Go 类似,Rust 没有受到与 C/C++系统相关的众所周知的安全和稳定性问题的困扰。Rust 使用一种新颖的“借用检查器”系统在编译时验证安全性,这比 Go 的内存管理器更快。Rust 的包管理与crates.io及其强大的生态系统使我们能够利用现有的库和工具,加快了我们的开发过程。
最后一点,DataFusion 查询引擎用 Rust 编写,这使我们决定将其作为 InfluxDB 3 的查询引擎,而不是采用用 C++编写的引擎。DataFusion 与 Rust 的性能优势和高级 SQL 执行能力的一致性使其成为理想选择。这种集成允许 InfluxDB 3 利用 Rust 的性能优势和 DataFusion 的 SQL 能力,增强了数据库的查询和处理能力。
FDAP 堆栈:InfluxDB 3 的核心组件
我们在开发 InfluxDB 3 时的一个目标是尽可能多地使用其他地方的开源库和工具。我们希望围绕更大的社区项目构建,为它们做出贡献,而不是在每个数据库组件上重新发明轮子。
当我们开始围绕 FDAP 技术重建 InfluxDB 基础时,我们赌它们会获得一个积极的社区,这将显著促进它们的成熟度、性能和功能。当我们在 2020 年选择这些项目作为数据库核心时,还很难预料它们会像过去四年多以来那样被如此广泛地采用和贡献。
Apache Arrow Flight
对于 Core 和 Enterprise,我们采用了 Flight SQL 作为高性能查询选项。Flight SQL 因其能够快速从像 InfluxDB 这样的分析数据库传输数百万行数据而在数据科学社区越来越受欢迎。我们还增强了我们的 HTTP 接口,以支持查询并以 JSONL、CSV 和 Parquet 响应格式返回结果。Parquet 因其能够高效传输大型数据集而脱颖而出,使其成为扩展数据工作流程的理想选择。
DataFusion
DataFusion 是一个基于 Rust 的 SQL 解析器、规划器、优化器和执行引擎,它使用 Apache Arrow 作为其内存模型。它提供了高性能的查询处理,包括流式向量化执行、自动并行化和查询优化。
我们的工程师团队在 InfluxDB 3 的开发过程中与一个大型全球社区紧密合作,对 DataFusion 做出了重大贡献。当我们在 2020 年中期开始 InfluxDB 重构时,该项目仍处于早期开发阶段。然而,由于数百人多年的开发和无数的工程小时,它已经取得了显著进展。它最近被指定为 Apache软件基金会的顶级项目。性能一直是 DataFusion 社区的核心关注点,速度吸引了来自活跃且不断增长的社区的显著贡献。
DataFusion 随着额外的功能增强和性能改进而成熟,这些功能直接集成到 InfluxDB 3 和其他基于 DataFusion 的系统中。这种一致性使我们能够与一群热情的工程师合作,高效快速地在 DataFusion 中开发先进的数据库技术。
Apache Arrow
Apache Arrow 是 InfluxDB 3 用于高效数据表示和处理的列式内存数据格式。Arrow 在核心使用最佳实践和缓存高效的列式布局标准化内存中的数据表示。它简化了复杂数据类型的表示,提高了性能和易用性。
当我们开始使用 Arrow 的 Rust 实现 arrow-rs时,它相对较新。随着时间的推移,InfluxData 和其他许多贡献者投入了大量时间和专业知识,使其成为最好的 Arrow 实现之一。这包括许多高度优化的计算内核和完整的类型支持。如果我们试图自己重新实现这一点,我们不太可能在 InfluxDB 3 中拥有这样的功能。
Apache Parquet
Parquet 是与其他系统和 InfluxDB 3 进行批量数据交换的主要格式。Arrow 是用作 Flight 的内存和跨线格式,而 Parquet 实现了高效的批量数据传输和与外部工具和系统(如 lakehouses、Apache Iceberg 和许多数据仓库)的无缝集成。
这标志着从 InfluxDB 作为一个独立系统向一个为互操作性而设计的系统转变。像 Snowflake、Databricks 和 Spark 这样的工具可以直接读取 Parquet 文件,从而可以更容易地集成,而不需要转换层。
通过采用 Parquet 作为支持新兴表格标准如 Apache Iceberg 和 Delta Lake(并具有灵活性以采用其他标准,如 XTable)的标准交换格式,InfluxDB 3 正成为现代数据生态系统中的一级公民,构建时旨在与更广泛的数据湖和分析栈集成。
每个组件都为其特定功能精心设计,通过从坚实的基础开始,我们的团队可以将大部分精力集中在确保它们无缝协作上。它们支持了我们所需的高性能时间序列用例。实现这一点需要深入了解每个组件的能力和限制,以及工程解决方案,例如专门的时间序列优化,这些可以弥合这些差距,形成一个连贯且高效的系统。

图 1:InfluxDB 3 查询架构
重构的收益
选择 FDAP 堆栈显著提高了数据库的性能,实现了更快、更高效且灵活的架构。它在摄取效率、可扩展性、数据压缩、存储成本和高基数数据的查询性能方面带来了显著提升。通过消除基数限制,用户可以同时引入无限量的时间序列数据和针对许多时间序列的分析查询,即使数据复杂性和基数增加。
对于开发人员来说,在 FDAP 堆栈上构建意味着构建一个数据处理引擎,该引擎可以高效地处理查询,并管理数据存储和检索以最大化不同负载的性能。在操作上,它涉及设置一个系统,该系统可以处理并发数据读写,确保数据完整性和一致性,并提供强大的容错机制。在架构上,它是一个可以水平和垂直扩展的设计,可以无缝适应不同的负载和数据大小。
许多现代数据工具和技术可以与 FDAP 堆栈的各个部分集成以增强其能力。例如,需要快速查询执行的分析工具可以从 DataFusion 和 Arrow 的快速数据处理功能中受益。需要高效数据传输的系统可以利用 Arrow Flight,而需要优化存储的系统可以利用 Parquet。
Apache Iceberg 和 FIDAP 堆栈
未来,我们将增加对 Iceberg 的支持。Iceberg 为 Parquet 支持的数据集带来了表格级抽象和强大的元数据管理,使得可以直接从数据湖和仓库(如 Databricks、Snowflake 和 AWS Athena)访问。通过将数据以 Parquet 格式写入并通过 Iceberg 暴露,InfluxDB 3 使时间序列数据完全可查询,无需自定义连接器或转换层。
开源 InfluxDB 3
有了这个基础,我们将 InfluxDB 3 的架构、性能和互操作性带给了开源社区。最新的 InfluxDB 3 Core 是一个基于 Rust 的、MIT/Apache 2 许可的时间序列引擎,构建在与我们的商业产品相同的 FDAP 堆栈和无状态架构上。它专为提供开发人员强大的实时引擎以应对现代数据工作负载而设计,支持我们的企业级部署的相同创新。
InfluxDB 3 Core 是一个高性能的实时数据引擎。这种专注的方法使 Core 能够为实时监控、数据收集和流分析用例提供卓越的性能。通过特别针对这种模式进行优化,我们实现了最后值查询的查询响应时间在 10 毫秒以下,小时范围查询在 50 毫秒以下。Core 还将数据持久化到 Parquet 文件中,以供第三方系统长期存储和访问。
InfluxDB 3 Enterprise 在 Core 的基础上增加了压实能力,使用户能够高效地在任何时间范围内进行查询,适用于需要历史分析的用户。这种分离允许 Core 保持其性能特性,而 Enterprise 处理管理历史数据的复杂要求。
Core 和 Enterprise 的一个关键特性是它们的“无磁盘”架构,使用对象存储作为唯一的持久层。虽然它们可以使用本地磁盘,但它们与对象存储的无状态操作使数据能够无缝地被第三方系统访问,这些系统可以直接从对象存储中读取。
这两种产品还包括了新的处理引擎,允许用户定义 Python 脚本来收集、处理、转换和监控数据,直接在数据库内实时进行。插件 API 包括查询数据库、将数据写回数据库以及连接到 Python 生态系统中的任何第三方服务的能力。我们对插件系统将带来的众多可能性感到兴奋,特别是当它与快速的最近数据查询引擎和最后值缓存配对时。
InfluxDB 3.2 和 InfluxDB 3.3 都带来了 InfluxDB 3 Explorer,这是一个用于查询、探索和可视化数据的 UI,以及用于处理引擎的托管插件,以处理常见的时间序列任务。最新版本 InfluxDB 3.4 适用于 Core 和 Enterprise,并包括用于设置和工作流程的自动化功能。

图 2:使用 WAL 刷新插件的写入路径:在处理引擎中定义的插件可以拦截预写式日志事件,使得在数据刷新到对象存储之前能够进行实时处理。
可扩展设计:为现代负载设计的无状态、无磁盘架构
Core 和 Enterprise 版引入了一种无状态、基于组件的架构,将计算与存储分离,并完全运行在对象存储上——我们称之为“无磁盘”架构。虽然仍然支持本地磁盘,但两个版本都设计为将所有状态持久化到像 S3、GCS 或 Azure Blob 这样的服务。写入操作首先进入内存,在那里进行验证和缓冲,然后作为 Parquet 格式刷新到对象存储以确保持久性。一个可查询的缓冲区保存了最近的数据,使得低延迟查询无需等待文件。这种设计提供了操作简便性、水平可扩展性和开箱即用的持久性,无需复杂的集群逻辑或数据复制层。

图 3:InfluxDB 3 写入路径。
这种架构的核心是模块化服务,它们处理不同的职责:
摄取器处理实时写入负载。它们缓冲传入的数据,在内存中去重,并将其作为小的 Parquet 文件持久化到对象存储中。
查询器执行低延迟的分析查询,扫描持久化的 Parquet 数据或查询由摄取器在内存中保存的热数据。
压缩器通过将数据重新排列成按时间序列排序的更大时间块来优化数据布局,提高读取性能并启用长期历史分析。
在对象存储上实现的中央目录(跨所有组件共享)跟踪模式元数据,允许系统在保持一致性和协调的同时完全无状态。
数据通过这些组件高效流动。摄取器在写入前验证模式并将数据按时间分区。表模式在写入时自动推断(用户不需要提前定义表或列)。自定义的多列排序合并去重策略(基于 DataFusion 操作符)在保持写入吞吐量的同时去除重复行。
为了保持数据老化时的查询性能,压缩器在后台持续将小文件合并成更大的、不重叠的 Parquet 文件。这种文件合并减少了存储开销,使查询期间能够快速修剪,并避免了不必要的重新计算。压缩级别有助于平衡频率和计算成本,确保系统在规模上保持性能。
查询器同时提供最近和历史数据。它们从对象存储中提取持久化的 Parquet 文件,并根据需要从摄取器查询最近的内存缓冲区。查询计划使用 DataFusion 构建,支持 SQL 和 InfluxQL,并从 DataFusion 的矢量化执行、谓词下推和对 Parquet 的原生支持中受益。
这种架构的一个关键特性是最后值缓存(LVC)和不同值缓存(DVC),它们是为加速熟悉的时间序列查询模式而设计的内存优化。LVC 保留了可配置标签层次结构的最新值,使得“最后已知值”查询的响应时间在 10 毫秒以内。DVC 提供了标签值的超快速查找,提高了 UI 响应性和探索性工作流程。
按设计,这种架构从关键路径中消除了本地状态,简化了升级,实现了动态扩展,并允许组件独立恢复。这种关注点分离还使得企业部署中的工作负载隔离成为可能,其中摄取、查询、处理和压缩组件可以分别进行扩展和调度。
综上所述,这些能力使得 InfluxDB 3 Core 可以作为一个轻量级、针对最近数据优化的实时分析引擎运行。由于这些性能特性,我们设置了一个配置选项,将查询计划限制为 432 个 Parquet 文件,对应于 72 小时的时间范围,时间块是十分钟。Enterprise 版取消了这个限制,因此提供了长期查询性能、高可用性和高级多节点部署功能。这在 Enterprise 版中是可能的,因为它的压缩器将十分钟的文件重写为更大的时间块。
结语
包括 Parquet 和 DataFusion 在内的 Apache Arrow 生态系统将作为未来 OLAP 和大规模数据处理系统的基础。除了 nfluxDB 3 Core,我们还在这些标准上投入我们的开源工作——有时领导这些上游项目——以便社区继续增长,Apache Arrow 项目集变得更易用,增加了新的功能和特性。我们获得了更可靠的软件,因为它已经在各种环境和用例中得到了验证。这就是开源的力量——一种封闭的专有系统根本无法匹敌的成熟度和韧性水平。
这标志着一个为期四年半的努力达到了高潮,我们从头开始重新构建系统,以满足现代时间序列工作负载的需求。有了 InfluxDB 3,我们建立了一个基础,它可以处理所有形式的时间序列、观测和历史数据,并且具备我们的用户所需的规模、性能和灵活性。这不仅仅是为了解决今天的挑战,而是为了确保 InfluxDB 是为了解决开发者今天正在解决的问题以及他们接下来将面临的问题而构建的。
原文链接:
Engineering a Time Series Database Using Open Source: Rebuilding InfluxDB 3 in Apache Arrow and Rust
评论