InfluxDB 内部 101 - 第一部分

导航至

Paul Dix 主导了一系列内部 InfluxDB 101 讲座,向新成员介绍 InfluxDB 的内部机制。我从这些讨论中学到了很多,并希望将这些内容与社区分享。我也在写这篇文章,以组织自己对 InfluxDB 的理解,也许能帮助那些想要学习 InfluxDB 架构的人。这些信息的大部分都来自 InfluxDB 文档——本系列的目的是提供一个综合的 InfluxDB 架构概述。

内容很多,因此分为三部分进行展示。本篇首先解释了数据模型和写入路径。第二篇将解释查询路径。第三篇将解释 InfluxDB Enterprise 集群。

系列目录表

  1. 数据模型和写入路径:向 InfluxDB 添加数据
    • 数据模型术语
    • 从客户端接收点
    • 将点持久化到存储
    • 压缩持久化点
  2. 查询路径:从 InfluxDB 读取数据
    • 为查询索引点
    • 关于 TSI(磁盘索引)的说明
    • 解析和计划
    • 执行查询
    • 关于 IFQL 的说明
    • DELETE 和 DROP - 从 InfluxDB 中删除数据
    • 更新点
  3. 集群:InfluxDB 企业版
    • 理解元服务
    • 理解数据节点
    • 理解数据分布和复制

数据模型和写入路径:向 InfluxDB 添加数据

数据模型和术语

InfluxDB 数据库存储 points。一个点有四个组件:一个 measurement,一个 tagset,一个 fieldset 和一个 timestamp

measurement 提供了一种关联可能具有不同 tagsetfieldset 的相关点的方式。tagset 是一个键值对字典,用于存储与点相关的元数据。fieldset 是一组类型化的标量值——点记录的数据。

点的序列化格式由 行协议 定义(如果您想了解更多细节,请参阅附加示例和解释)。规范中的一个示例点有助于解释术语。

“”温度,机器=单元42,类型=内部=32,外部=100 1434055562000000035

测量值为温度

标签集为机器=单元42,类型=装配。标签集中的键机器类型称为标签键。标签集中的值单元42装配称为标签值

字段集为内部=32,外部=100。字段集中的键内部外部称为字段键。字段集中的值32100称为字段值

每个数据点都存储在恰好一个数据库中,且恰好一个保留策略中。数据库是用户、保留策略和数据点的容器。保留策略配置InfluxDB保留数据点的时长(持续时间)、在集群中存储这些点的副本数量(复制因子)以及分片组覆盖的时间范围(分片组时长)。保留策略使用户(以及数据库)能够轻松删除不再需要的老旧数据。这在时间序列应用中是一种常见的模式。

当我们描述InfluxDB中写入路径的工作原理时,我们会进一步解释复制因子分片组分片

还有一个术语我们需要开始了解:系列。一个系列是一组具有相同测量值 + 标签集 + 字段键的数据点。

您可以参考文档术语表了解这些术语或本博客系列中可能使用到的其他术语。

从客户端接收数据点

客户端通过POST请求(以行协议格式)将数据点发送到InfluxDB的HTTP /write端点。数据点可以单独发送;然而,为了提高效率,大多数应用会将数据点批量发送。一个典型的批量大小从几百到几千个数据点。POST请求通过查询参数指定一个数据库和一个可选的保留策略。如果没有指定保留策略,将使用默认的保留策略。所有在请求体中的数据点都将写入该数据库和保留策略。请求体中的数据点可以来自任意数量的系列;批量中的数据点不必来自同一个测量值或标签集。

当数据库接收到新的数据点时,它必须(1)确保这些数据点的持久性,以便在数据库或服务器崩溃的情况下恢复,以及(2)确保这些数据点可查询。本文重点介绍了第一部分,即确保数据点的持久性。

将数据点持久化到存储

为了确保数据点的持久性,每个批量都会写入并同步到预写日志(WAL)。WAL是一个只读文件,只在数据库恢复期间被读取。为了节省空间和提高磁盘I/O效率,WAL中的每个批量在写入磁盘之前都会使用snappy压缩进行压缩。

虽然WAL格式有效地使传入数据持久化,但它对于读取来说非常低效——使其不适合支持查询。为了允许立即查询新数据,传入的点也被写入内存中的缓存。该缓存是一个内存中的数据结构,它针对查询和插入性能进行了优化。该缓存数据结构是系列到时间排序的字段列表的映射。

WAL使新点持久化。缓存使新点可查询。如果系统在将缓存写入TSM文件之前崩溃或关闭,则数据库启动时将通过读取和重新播放存储在WAL中的批处理来重建。

WAL缓存的组合对于传入数据来说效果很好,但不足以用于长期存储。由于必须在启动时重新播放WAL,因此将其限制在合理大小非常重要。缓存的大小限于RAM的大小,这对于许多时间序列用例也不可取。因此,数据需要组织并写入磁盘上的长期存储块,这些块大小高效(以便数据库可以存储大量点)并且查询效率高。

时间序列查询通常是时间上的聚合——对有限时间范围内的点的扫描,然后通过像平均值、最大值或移动窗口这样的汇总函数进行缩减。列式数据库存储技术,其中数据按列而不是按行组织在磁盘上,非常适合这种查询模式。此外,列式系统压缩数据非常出色,满足存储数据高效的需求。关于列存储有很多文献。《列式数据库系统》是此类概述之一。

时间序列应用通常会在一段时间后从存储中删除数据。例如,许多监控应用将存储最后一个月或两个月的数据以支持监控查询。如果配置的生存时间到期,则需要从数据库中高效删除数据。从列式存储中删除点代价很高,因此InfluxDB还将其列式格式组织成时间限制的块。当生存时间到期时,时间限制的文件可以直接从文件系统中删除,而不是需要对持久化数据进行大量更新。

最后,当InfluxDB作为集群系统运行时,它会跨多个服务器复制数据,以便在发生故障时提供可用性和持久性。

使用InfluxDB的保留策略配置可选的生存时间持续时间、生存时间周期内时间块的大小和副本数量。

CREATE RETENTION POLICY <retention_policy_name> ON <database_name> DURATION <duration> REPLICATION <n> [SHARD DURATION <duration>] [DEFAULT]

duration是可选的生存时间(如果数据不应过期,将duration设置为INF)。SHARD DURATION是生存时间周期内数据的大小。例如,一个一小时的shard duration与24小时的duration配置将数据库配置为存储24个一小时的shard。每小时,最旧的shard将从数据库中过期(删除)。将REPLICATION设置为配置复制因子——集群内应该存在多少个shard的副本。

具体来说,数据库将在磁盘上创建这种物理数据组织。

'' Database director  /db
    '' Retention Policy directory /db/rp
        '' Shard Group (time bounded). (Logical)
            '' Shard directory (db/rp/Id#)
                '' TSM0001.tsm (data file)
                '' TSM0002.tsm (data file)
                '' …

内存中的缓存被刷新到磁盘上的TSM格式。刷新完成后,刷新的点将从缓存中移除,相应的WAL将被截断。(WAL和缓存也是按分片维护的。)TSM数据文件存储列式组织的点。一旦写入,TSM文件就是不可变的。关于TSM文件布局的详细描述可以在[InfluxDB文档]中找到。

压缩TSM数据

缓存是相对较小的数据量。TSM列式格式在可以存储一个系列在单个块中的长值序列时工作得最好。更长的序列既提高了压缩率,又减少了查询字段时的查找次数。TSM格式在很大程度上基于日志结构合并树。新的(一级)TSM文件是通过缓存刷新生成的。这些文件稍后(压缩)合并成二级文件。二级文件进一步合并成三级文件。随着文件变得越来越大,将发生额外的压缩级别,最终变为冷文件(它们覆盖的时间范围不再适合写入。)上述文档参考提供了关于压缩的详细描述。

TSM压缩代码中有很多逻辑和复杂性。然而,高级目标非常简单:将一个系列的值组织在一起,形成长序列,以最佳优化压缩和扫描查询。

第一部分总结

总的来说,批量被POST到InfluxDB。这些批量数据被snappy压缩并写入WAL以实现即时持久性。这些点也写入内存中的缓存,以便新写入的点可以立即查询。缓存定期刷新到TSM文件。随着TSM文件的积累,它们被合并和压缩成更高级别的TSM文件。TSM数据组织成分片。一个分片覆盖的时间范围和集群部署中一个分片的复制因子由保留策略配置。

希望这篇文章能帮助解释InfluxDB如何接收和持久化传入的写入。在下篇文章中,我们将讨论系统如何支持查询、更新和删除操作。