InfluxDB 3.0:系统架构
作者:Nga Tran / Paul Dix / Andrew Lamb / Marko Mikulicic / 产品
2023年6月27日
导航到
InfluxDB 3.0(之前称为InfluxDB IOx)是一个(云)可扩展数据库,提供高性能的数据加载和查询,专注于时间序列用例。本文描述了数据库的系统架构。
图1展示了InfluxDB 3.0的架构,包括四个主要组件和两个主要存储。
这四个组件几乎独立运行,分别负责
-
数据摄入(以蓝色表示),
-
数据查询(以绿色表示),
-
数据压缩(以红色表示),和
-
垃圾回收(以粉色表示)。
对于这两种存储类型,一种是名为目录的集群元数据,另一种更大,用于存储实际数据,称为对象存储,例如Amazon AWS S3。除了这些主要存储位置之外,还有称为预写日志(WAL)的小型数据存储,仅供摄入组件在数据加载时的崩溃恢复使用。
图中的箭头显示了数据流向;如何进行数据拉取或推送的通信超出了本文的范围。对于已经持久化的数据,我们设计了系统,使目录和对象存储成为唯一的状态,并使每个组件只需读取这些存储,而无需与其他组件通信。对于尚未持久化的数据,数据摄入组件在查询到来时管理状态,将其发送到数据查询组件。让我们通过逐个分析每个组件来深入了解这种架构。
数据摄入
图2展示了InfluxDB 3.0中数据摄入的设计。用户将数据写入摄入路由器,该路由器将数据分片到摄入器之一。集群中摄入器的数量可以根据数据工作量进行扩展和缩减。我们使用这些扩展原则来分片数据。每个摄入器都附加了一个存储,例如Amazon EBS,用作写入前日志(WAL),用于崩溃恢复。
每个摄入器执行以下主要步骤
-
识别数据表:与许多其他数据库不同,用户在将数据加载到InfluxDB之前不需要定义它们的表及其列模式。它们将被发现并由摄入器隐式添加。
-
验证数据模式:用户写入提供的数据类型将与写入请求严格同步验证。这可以防止类型冲突传播到系统其他部分,并使用户能够立即获得反馈。
-
数据分区:在InfluxDB等大规模数据库中,对数据进行分区有很多好处。Ingest器负责分区任务,目前它通过“时间”列按日对数据进行分区。如果摄入数据没有时间列,Ingest Router会隐式地添加它,并设置其值为数据加载时间。
-
数据去重:在时间序列用例中,经常会看到相同的数据被多次摄入,因此InfluxDB 3.0执行去重过程。Ingest器为去重任务构建了一个高效的多列排序合并计划。因为InfluxDB使用DataFusion进行查询执行,并使用Arrow作为其内部数据表示,构建排序合并计划仅涉及将DataFusion的排序和合并算子组合在一起。在多个列上有效运行该排序合并计划是InfluxDB团队为DataFusion做出的贡献的一部分。
-
持久化数据:处理和排序后的数据然后持久化为Parquet文件。因为如果对基数最小的列进行排序,数据可以非常有效地编码/压缩,所以Ingest器找到并选择基数最小的列作为上述排序的排序顺序。因此,文件的大小通常比其原始形式小10-100倍。
-
更新目录:Ingest器随后更新目录关于新创建文件的存在。这是通知其他两个组件——查询器和压缩器——新数据已到达的信号。
尽管Ingest器执行了多个步骤,但InfluxDB 3.0优化了写入路径,将写入延迟保持在毫秒级别。这可能导致系统中有很多小文件。然而,我们不会长时间保留它们。在下一节中描述的压缩器在后台压缩这些文件。
Ingest器还支持容错,这超出了本文的范围。Ingest器的详细设计和实现值得单独的博客文章。
数据查询
图3显示了InfluxDB 3.0如何查询数据。用户将SQL或InfluxQL查询发送到将它们转发到查询路由器的查询器,查询器读取所需数据,为查询构建计划,运行计划,并将结果返回给用户。根据查询负载可以使用与Ingest器设计相同的扩展原则向上或向下扩展查询器的数量。
每个查询器执行以下主要任务
-
缓存元数据:为了有效地支持高查询负载,查询器保持与其中央目录的元数据缓存同步,以保持最新的表及其摄入元数据。
-
读取和缓存数据:当查询到达时,如果其数据不在查询器的数据缓存中,查询器会首先将数据读入缓存,因为我们知道从统计数据中,相同的文件将被多次读取。查询器只会缓存回答查询所需文件的正文;根据查询器的剪枝策略,查询不需要的文件其他部分永远不会被缓存。
-
从聚合器获取尚未持久化的数据:因为聚合器中可能存在尚未持久化到对象存储的数据,查询器必须与相应的聚合器通信以获取该数据。通过这次通信,查询器还可以从聚合器中了解到是否有更新的表和数据需要使缓存失效并更新,以获得整个系统的最新视图。
-
构建和执行最优查询计划:与许多其他数据库一样,InfluxDB 3.0 查询器包含一个查询优化器。查询器构建最佳的查询计划(也称为最优计划),该计划在缓存和聚合器中的数据上执行,并尽可能快地完成。类似于聚合器的设计,查询器使用 DataFusion 和 Arrow 来构建和执行针对 SQL(以及很快的 InfluxQL)的定制查询计划。查询器利用在聚合器中执行的数据分区来并行化其查询计划,并在执行计划之前剪枝不必要的数据。查询器还应用了 谓词和投影下推 等常见技术,以尽可能快地剪枝数据。
尽管每个文件中的数据本身不包含重复项,但来自聚合器的不同文件以及尚未持久化发送到查询器的数据可能包含重复项。因此,在查询时也需要进行去重过程。类似于聚合器,查询器使用上面描述的相同的多列排序合并操作符进行去重工作。与为聚合器构建的计划不同,这些操作符只是构建来执行查询的更大和更复杂查询计划的一部分。这确保了去重后的数据流经计划的其余部分。
值得注意的是,即使具有高级的多列排序合并操作符,其执行成本也不容小觑。查询器进一步优化计划,仅对可能发生重复的重复文件进行去重。此外,为了在查询器中提供高查询性能,InfluxDB 3.0 通过事先压缩数据来尽量减少查询时的去重。下一节将描述压缩过程。
上述简要描述的查询器任务的详细设计和实现值得单独的博客文章。
数据压缩
正如“数据摄取”部分所述,为了减少摄取延迟,聚合器将每个文件中处理和持久化的数据量非常小。这导致在对象存储中存储了许多小文件,这在查询时会产生显著的 I/O,并降低查询性能。此外,正如“数据查询”部分所述,重叠文件可能包含在查询时需要去重的重复项,这会降低查询性能。数据压缩的工作是将聚合器摄取的许多小文件压缩成更少、更大且不重叠的文件,以提高查询性能。
图4展示了数据压缩的架构,其中包括一个或多个压缩器。每个压缩器运行一个后台任务,读取新导入的文件并将它们压缩成更少、更大且不重叠的文件。压缩器的数量可以根据压缩工作量进行调整,这取决于具有新数据文件的表的数量、每个表中新文件的数量、文件的大小、新文件与现有文件重叠的数量以及表的大小(即表中的列数)。
在文章《压缩器:数据库性能的隐藏引擎》(链接:https://www.infoworld.com/article/3685496/compactor-a-hidden-engine-of-database-performance.html)中,我们描述了压缩器的详细任务:如何构建一个优化的去重计划以合并数据文件、帮助去重的不同列文件的排序顺序、使用压缩级别实现非重叠文件同时最小化重新压缩,以及在查询器中对非重叠和重叠文件混合构建一个优化的去重计划。
与导入器和查询器的设计类似,压缩器使用DataFusion和Arrow构建和执行自定义查询计划。实际上,这三个组件共享同一个压缩子计划,涵盖了数据去重和合并。
将小型或重叠的文件压缩成大型和非重叠的文件后,必须删除以回收空间。为了避免删除查询器正在读取的文件,压缩器永远不会进行硬删除。相反,它在目录中将文件标记为软删除,另一个名为垃圾回收器的后台服务最终删除软删除的文件以回收存储空间。
垃圾回收
图5展示了InfluxDB 3.0垃圾回收的设计,它负责数据保留和空间回收。垃圾回收器运行后台任务,安排软删除和硬删除数据。
数据保留
InfluxDB为用户提供了一个选项,可以定义他们的数据保留策略并将其保存在目录中。垃圾回收器的计划后台任务读取目录以查找超出保留期的表,并在目录中将它们的文件标记为软删除。这向查询器和压缩器发出信号,表明这些文件不再可用于查询和压缩。
空间回收
垃圾回收器的另一个计划后台任务读取目录以查找一定时间前已软删除的文件元数据。然后它从对象存储中删除相应的数据文件,并从目录中删除相应的元数据。
请注意,软删除的文件来自不同的来源:压缩器删除的压缩文件、垃圾回收器本身删除的超出保留期的文件,以及InfluxDB 3.0计划在将来支持通过删除命令删除的文件。硬删除任务不需要知道软删除的来源,并对待它们相同。
软删除和硬删除是另一个大话题,涉及到导入器、查询器、压缩器和垃圾回收器的工作,值得一篇单独的博客文章。
InfluxDB 3.0集群设置
除了查询器向其对应的摄取器请求尚未持久化的数据之外,这四个组件之间不直接通信。所有通信都通过目录和对象存储进行。摄取器和查询器甚至不知道压缩器和垃圾回收器的存在。然而,如上所述,InfluxDB 3.0 是设计为让所有四个组件共存以提供高性能数据库的。
除了这些主要组件之外,InfluxDB 还提供其他服务,如 计费,根据客户的使用情况向其收费。
目录存储
InfluxDB 3.0 目录包括数据的元数据,如数据库(又称命名空间)、表、列和文件信息(例如文件位置、大小、行数等)。InfluxDB 使用兼容 PostgreSQL 的数据库来管理其目录。例如,本地集群设置可以使用 PostgreSQL,而 AWS 云设置可以使用 Amazon RDS。
对象存储
InfluxDB 3.0 数据存储仅包含 Parquet 文件,这些文件可以存储在本地磁盘上的本地设置中,或者在 AWS 云设置中使用 Amazon S3。数据库还支持 Azure Blob Storage 和 Google Cloud Storage。
InfluxDB 3.0 集群操作
InfluxDB 3.0 客户可以设置多个专用集群,每个集群独立运行,以避免“嘈杂邻居”问题并包含潜在的可靠性问题。每个集群都使用自己的专用计算资源,可以在单个或多个 Kubernetes 集群上运行。这种隔离也限制了由于另一个集群中的活动而可能出现的可靠性问题的潜在影响范围。
我们创新的升级基础设施的方法是将就地更新与整个 Kubernetes 集群的完整蓝/绿滚动发布相结合。由于 InfluxDB 3.0 集群的大部分状态都存储在 Kubernetes 集群之外,例如在 S3 和 RDS 中,这简化了此过程。
我们的平台工程系统使我们能够在数百个集群之间进行操作,并允许客户控制特定集群参数,这些参数决定了性能和成本。持续监控每个集群的健康状况是我们操作的一部分,允许小团队在快速发展的软件环境中有效地管理多个集群。