Link Search Menu Expand Document

InfluxDB 数据模型

目录

  1. InfluxDB 数据元素
    1. 测量
    2. 标签集
    3. 字段集
  2. 序列和数据点
  3. 假设和约定
    1. 本书使用的约定
    2. 示例的元语法
  4. IOx 数据模型介绍
    1. TSM 和 IOx 数据模型之间的相似之处
      1. 数据元素
      2. Flux 兼容性
      3. 线路协议兼容性
    2. 从线路协议到磁盘上的表
      1. 线路协议、字段和表
    3. 添加标签
    4. 时间戳
    5. 更新插入

本节的目标是为读者提供 InfluxDB 数据模型的坚实基础,特别是

  • 理解 InfluxDB 输入格式(线路协议)。
  • 理解 InfluxDB 输出格式(带注释的 CSV)。
  • 这两种格式之间的关系。
  • 理解 InfluxDB 存储引擎如何将数据持久化到磁盘上的表中

InfluxDB 数据元素

InfluxDB 中的所有数据都会写入到一个桶中。一个 是一个容器,可以容纳任意数量测量的点。桶有一些重要的属性:

  1. 它们可以根据您的需要命名(在合理的范围内)。
  2. 您可以创建令牌来控制桶的读写权限,仅限于特定桶。
  3. 您必须在创建桶时设置保留期限。保留期限 决定 InfluxDB 在该桶中存储时间序列数据的时长。保留期限对于时间序列数据库管理至关重要。它们为用户提供了一个方便的解决方案,可以自动过期旧的、无用的数据,从而使用户能够专注于最近的、有价值的数据,同时降低存储成本。

这些主题将在后面的章节中详细介绍,现在只需知道测量值存储在桶中并从桶中读取即可。

测量

测量 是桶内最高级别的数据结构。InfluxDB 每个点接受一个测量值。使用测量来组织类似的数据。在某些方面,您可以将其视为类似于传统数据库中的表。测量值也被索引,这使您在过滤特定测量值时可以更快地查询测量值中的数据。测量值必须是字符串类型。测量名称不能以下划线开头。

为了进一步理解测量,假设您正在构建一个天气应用程序,并将多个城市的气温数据写入 InfluxDB。对于这个时间序列用例,您可以创建一个名为“air_temperature”的测量。

标签集

标签集 由键值对组成,其中值始终是字符串。标签本质上是元数据,通常对数据的来源进行编码。

假设您正在构建一个天气应用程序,并将多个城市的气温数据写入 InfluxDB。对于这个时间序列用例,您可以向数据中添加一个名为“location”的标签键,其中“location”标签键包含您正在监控天气城市的标签值。这样,您可以轻松地查询“洛杉矶”的所有温度数据,例如,通过过滤具有“洛杉矶”标签值的“location”标签键。

至关重要的是,标签已编入索引,因此它们是设计查询性能的重要元素。但是,标签也是可选的。标签键不能以下划线开头,因为 InfluxDB 保留前导下划线供自己使用。

字段集

字段集 由键值对组成,其中值可以是字符串、整数或浮点数。字段是要存储、可视化、用于计算等的实际数据。

继续以天气应用程序为例,温度读数就是字段的一个示例。

InfluxDB 需要字段集。这是您存储时间序列数据值的地方。字段值可以是整数、浮点数或字符串类型。由于字段值几乎总是不同的,因此字段键通常简称为字段。字段未编入索引。字段也不能以下划线开头。

序列和数据点

序列由测量、标签集和字段的唯一组合定义。数据点是特定时间戳下序列中的一个数据点。如果您使用相同的测量、标签集、字段和时间戳值重写重复的数据点,则此写入将覆盖您之前的数据点。如果您尝试将新数据点写入同一序列,但更改了字段类型,则此写入将失败。

假设和约定

在深入探讨有关 InfluxDB 数据模型的更细微和更专业的主题之前,让我们花点时间建立一些基线假设和约定。

本书使用的约定

本书中的章节通常会使用抽象和简化的示例介绍概念,然后使用真实世界的数据进行详细示例。

示例的元语法

对于抽象和简化的示例,我们将使用以下形式的名称

attributeorvaluen

其中“attributeorvalue”指的是表的列名或点中的值,“n”是一个数字,用于区分相同角色的多个标识符。角色可以包含以下任何一项

  • 测量
  • 标签
  • 标签值
  • 字段

示例通常还包括

  • 字段值
  • 时间戳

字段值将由实际值表示。时间戳采用以下时间戳格式

  • Unix:Unix 时间戳是一种将时间作为秒的累积总数进行跟踪的方法,例如 1465839830100400200
  • RFC3339:互联网工程任务组 (IETF) 的征求意见文档中日期和时间表示的标准,例如 2019-08-28T22:00:000000000Z
  • 相对持续时间:-1h
  • 持续时间:1h

时间戳将由实际值或 unixtime1rfc3339time1 表示。如果我们想在同一个示例中引用另一个时间戳,我们将使用 unixtime2rfc3339time2

要在示例中引用测量,我们将使用:measurement1。如果我们想在同一个示例中引用另一个测量,我们将使用 measurement2,依此类推。

线路协议(稍后将详细解释)的示例可能如下所示

measurement1,tag1=tagvalule1,tag2=tagvalue2 field1=1i,field2=2 1628858104

有时,示例可能侧重于理解类型。在这种情况下,我们将使用“atype”形式,其中“type”是所关注的数据类型。例如,如果我们正在讨论字段名称始终是字符串,我们可能会说

r._field == "astring"

或者,如果我们正在讨论类型冲突,我们可能会说

aint == afloat

而不是带有特定值的示例,例如

1i == 1.0

IOx 数据模型介绍

InfluxDB 正在使用新的 *IOx 数据模型* 进行重大升级。

阅读本节可以充分理解使用 IOx 桶的新 InfluxDB 数据模型,尤其要注意 *IOx 数据模型* 与 *TSM 数据模型* 的区别。

**注意:**IOx 仍在测试中。请继续关注 influxdata.com 以了解我们何时正式将新的 IOx 数据模型推广到所有 InfluxDB Cloud 生产集群。

TSM 和 IOx 数据模型之间的相似之处

数据元素

IOx 保留了用户在 InfluxDB 中习惯使用的相同数据元素,即

  • 用于存储数据的桶。
  • 用于将类似数据分组在一起的测量。
  • 标签集,与时间戳一起,标识表中的唯一行。
  • 用于存储实际数据的字段。
  • 当然,还有用于按时间维度对数据进行排序的时间戳。

这些元素的当前文档可在此处此处获取,并将更新以反映与 IOx 相关的任何更改。

Flux 兼容性

拥有现有 Flux 脚本并且这些脚本运行良好的用户可以放心,这些脚本将继续有效,无需修改。在 IOx 的整个开发过程中,这种向后兼容性一直是一个重点。但是,用户应该注意,通过对其 Flux 进行一些小的更改(稍后将进行描述),他们将能够使用 IOx 实现显著的性能改进。

线路协议兼容性

与 Flux 类似,我们投入了大量精力以确保保留 InfluxDB 行协议兼容性。因此,此处提供的有关行协议的文档仍然适用,但需要注意的是,如果用户想要充分利用 IOx,则应以不同的方式考虑磁盘持久性和使用 Table Flux 的输出格式。本文档将从那里继续,介绍将数据持久化到磁盘的模型。

从行协议到磁盘上的表

在以前版本的 InfluxDB 中,将数据库设想为按序列存储数据最为实用,每个序列都在一个单独的表中。IOx 数据模型可以说更直观,因为它构建了 Table Flux 返回的表。

与之前的 TSM 一样,IOx 是一个“写入时模式”数据库引擎。这意味着您可以在部署应用程序后随意写入带有新测量值、标签、标签值和字段的数据,IOx 将接受这些写入并将它们持久化为表。请注意,关于写入时模式有一些重要的注意事项,例如,您不能仅通过写入具有新类型的值来更改字段的类型。

IOx 中的表由测量名称定义。表中的列包括

  • 标签名称
  • 字段名称
  • 单个时间列

因此,行包含

  • 标签值
  • 字段值
  • 单个时间戳

行由其标签值和时间戳标识。这在理解 Upserts 时变得很重要。

在以下示例中,我们将探讨如何在 IOx 中通过写入创建表。

行协议、字段和表

最简单的行协议是一个测量值和一个带有值的字段。如果省略时间戳,我们可以允许数据库通过从行协议中省略它来添加时间戳

measurement1 field1=1i

这将由 IOx 持久化为一个表

名称:measurement1
field1time
1itimestamp1

如您在上面的示例中看到的,该表由测量名称定义,并包含一个名为“field1”的列和一行数据。写入更多类似的数据将按预期扩展表。如果我们再写一行行协议

measurement1 field1=2i
名称:measurement1
field1time
1itimestamp1
2itimestamp2

如果我们写入第三行行协议,这次使用不同的字段名称,IOx 会将该字段添加到表中,并将之前的写入值设为空值。

measurement1 field2=3i
名称:measurement1
field1field2time
1inulltimestamp1
2inulltimestamp2
null3itimestamp3

当然,IOx 仍然支持在单行行协议中写入多个字段,因此我们可以编写如下行协议

measurement1 field1=4i,field2=4i
名称:measurement1
field1field2time
1inulltimestamp1
2inulltimestamp2
null3itimestamp3
4i4itimestamp4

添加标签

从表面上看,标签和字段在 IOx 中似乎是等效的。例如,一段带有单个标签和字段的简单行协议将生成一个包含 3 列的表,一列用于标签,一列用于字段,一列用于时间。考虑以下行协议和生成的表。

measurement1,tag1=tagvalue1 field1=1i
名称:measurement1
field1tag1time
1itagvalue1timestamp1

与之前的数据模型不同,添加新的标签值会被添加到同一个表中

measurement1,tag1=tagvalue2 field1=2i
名称:measurement1
field1tag1time
1itagvalue1timestamp1
2itagvalue2timestamp2

现在,如果我们进行新的写入,但使用不同的标签名称,类似于添加字段,这将使用标签的新列更新表,并且缺少的标签值将设置为 null。

measurement1,tag2=tagvalue3 field1=3i
名称:measurement1
field1tag1tag2time
1itagvalue1nulltimestamp1
2itagvalue2nulltimestamp2
3inulltagvalue3timestamp3

我们可以通过根据需要引入新的标签和字段,以这种方式继续添加到 measurement1 表中。

measurement1,tag1=tagvalue1,tag2=tagvalue3,tag3=tagvalue4 field1=4i,field2=true
名称:measurement1
field1field2tag1tag2tag3time
1inulltagvalue1nullnulltimestamp1
2inulltagvalue2nullnulltimestamp2
3inullnulltagvalue3nulltimestamp3
4itruetagvalue1tagvalue3tagvalue4timestamp4

仍然可以写入最小的行协议,并将其添加到表中

measurement1 field1=1i
名称:measurement1
field1field2tag1tag2tag3time
1inulltagvalue1nullnulltimestamp1
2inulltagvalue2nullnulltimestamp2
3inullnulltagvalue3nulltimestamp3
4itruetagvalue1tagvalue3tagvalue4timestamp4
1inullnullnullnulltimestamp5

时间戳

如上所述,行由时间戳和标签值的组合标识。因此,只要标签值不同,重复的时间戳就是有效的。例如,我们可以通过改变标签值来添加多个具有 timestamp5 的行。考虑以下行协议,它具有重复的时间戳。

measurement1,tag1=tagvalue1 field1=1i timestamp5

记住一行由其标签值定义,尽管时间戳和字段相同,但这仍然代表一个新行

名称:measurement1
field1field2tag1tag2tag3time
1inulltagvalue1nullnulltimestamp1
2inulltagvalue2nullnulltimestamp2
3inullnulltagvalue3nulltimestamp3
4itruetagvalue1tagvalue3tagvalue4timestamp4
1inullnullnullnulltimestamp5
1inulltagvalue1nullnulltimestamp5

当您发送一行行协议时,写入会考虑**整个**标签值集。只要单个标签值不同,即使所有字段和时间戳都相同,写入仍将导致添加新行。

例如,以下行与现有行相同,只是 tag3 的值为 tagvalue5 而不是 tagvalue4。因此,这将导致添加新行。

measurement1,tag1=tagvalue1,tag2=tagvalue3,tag3=tagvalue5 field1=4i,field2=true timestamp4
名称:measurement1
field1field2tag1tag2tag3time
1inulltagvalue1nullnulltimestamp1
2inulltagvalue2nullnulltimestamp2
3inullnulltagvalue3nulltimestamp3
4itruetagvalue1tagvalue3tagvalue4timestamp4
4itruetagvalue1tagvalue3tagvalue5timestamp4
1inullnullnullnulltimestamp5
1inulltagvalue1nullnulltimestamp5

Upserts(更新插入)

将对 InfluxDB 的所有写入视为 Upserts 很有用。“Upsert”一词的意思是写入时“更新或插入”。如果它与现有记录匹配,它将更新;如果没有匹配的现有记录,它将插入新记录。

由于 Upserts 匹配时间戳和标签值,因此无法更新标签值!只有字段值可以更新。

这行行协议不包含标签,具有重复的时间戳和重复的字段名称,但字段值不同。因此,这与时间戳和标签集(恰好为空)匹配。因此,这将导致更新表。

measurement1 field1=2i timestamp5
名称:measurement1
field1field2tag1tag2tag3time
1inulltagvalue1nullnulltimestamp1
2inulltagvalue2nullnulltimestamp2
3inullnulltagvalue3nulltimestamp3
4itruetagvalue1tagvalue3tagvalue4timestamp4
4itruetagvalue1tagvalue3tagvalue5timestamp4
2inullnullnullnulltimestamp5
1inulltagvalue1nullnulltimestamp5

以下行协议也匹配现有时间戳和标签集,因此将导致更新。虽然行协议中只存在一个字段,但行仍然匹配,因此该字段将被更新。

measurement1,tag1=tagvalue1,tag2=tagvalue3,tag3=tagvalue5 field2=false timestamp4
名称:measurement1
field1field2tag1tag2tag3time
1inulltagvalue1nullnulltimestamp1
2inulltagvalue2nullnulltimestamp2
3inullnulltagvalue3nulltimestamp3
4itruetagvalue1tagvalue3tagvalue4timestamp4
4ifalsetagvalue1tagvalue3tagvalue5timestamp4
2inullnullnullnulltimestamp5
1inulltagvalue1nullnulltimestamp5

可以类似地引入新字段。以下行协议匹配现有行的时间戳和所有标签值,因此该行将被更新,以及新的字段值。正如预期的那样,所有没有新字段的现有行的该字段都将设置为 null。

measurement1,tag1=tagvalue1,tag2=tagvalue3,tag3=tagvalue5 field3=0.0 timestamp4
名称:measurement1
field1field2field3tag1tag2tag3time
1inullnulltagvalue1nullnulltimestamp1
2inullnulltagvalue2nullnulltimestamp2
3inullnullnulltagvalue3nulltimestamp3
4itruenulltagvalue1tagvalue3tagvalue4timestamp4
4ifalse0.0tagvalue1tagvalue3tagvalue5timestamp4
2inullnullnullnullnulltimestamp5
1inullnulltagvalue1nullnulltimestamp5

下一节