InfluxDB schema设计与数据布局
此页面记录了 InfluxDB OSS 的早期版本。InfluxDB OSS v2 是最新的稳定版本。请参阅 InfluxDB v2 文档。
每个 InfluxDB 用例都是独特的,你的 schema 反映了这种独特性。一般来说,专为查询设计的 schema 会导致更简单和更高性能的查询。我们建议针对大多数用例遵循以下设计准则:
数据存储位置(标签或字段)
您的查询应该指导您在 tags 中存储哪些数据,以及在 fields 中存储哪些数据:
- 在标签中存储常见查询和分组(
group()或GROUP BY)的元数据。 - 如果每个数据点包含不同的值,则将数据存储在字段中。
- 将数字值存储为字段(tag values 仅支持字符串值)。
避免过多的系列
InfluxDB 索引以下数据元素以加快读取速度:
标签值是被索引的,而字段值则不是。 这意味着通过标签进行查询的性能优于通过字段进行查询。 然而,当创建的索引过多时,写入和读取都可能开始变慢。
每个独特的索引数据元素集合形成一个 series key。 Tags 包含高度可变的信息,如唯一标识符、哈希和随机字符串,导致大量的 series,也称为高 series cardinality。 高系列基数是许多数据库工作负载高内存使用的主要驱动因素。 因此,为了减少内存消耗,请考虑将高基数值存储在字段值中,而不是在标签或字段键中。
如果对 InfluxDB 的读写开始变慢,您可能有高序列基数(序列太多)。请参阅 如何找到并减少序列高基数。
使用推荐的命名约定
在命名您的标签和字段键时,请使用以下约定:
避免在标签和字段键中使用保留关键字
不必要,但避免在您的标签和字段键中使用保留关键字可以简化查询编写,因为您不必将键用双引号括起来。查看 InfluxQL 和 Flux keywords 以避免。
另外,如果一个标签或字段键包含其他字符而不是 [A-z,_],您必须在 InfluxQL 中将其用双引号括起来,或者在 Flux 中使用 括号表示法。
避免标签和字段同名
避免为标签和字段键使用相同的名称。 这通常在查询数据时导致意外行为。
如果您不小心为一个标签和一个字段添加了相同的名称,请参见 常见问题解答 以获取有关如何可预测地查询数据以及如何解决问题的信息。
避免在测量和键中编码数据
将数据存储在 tag values 或 field values 中,而不是 tag keys、field keys 或 measurements 中。如果您设计您的架构以将数据存储在标签和值字段中,您的查询将更容易编写且更高效。
此外,通过在写入数据时不创建测量和键,您将保持低基数。 要了解高系列基数对性能的影响,请参见 如何寻找和减少高系列基数。
比较模式
比较以下以行协议表示的有效模式。
推荐: 以下架构将元数据存储在单独的 crop、 plot 和 region 标签中。 temp 字段包含可变的数字数据。
Good Measurements schema - Data encoded in tags (recommended)
-------------
weather_sensor,crop=blueberries,plot=1,region=north temp=50.1 1472515200000000000
weather_sensor,crop=blueberries,plot=2,region=midwest temp=49.8 1472515200000000000
不推荐: 以下模式存储多个属性 (crop, plot 和 region) 连接在一起 (blueberries.plot-1.north) ,类似于 Graphite 指标。
Bad Measurements schema - Data encoded in the measurement (not recommended)
-------------
blueberries.plot-1.north temp=50.1 1472515200000000000
blueberries.plot-2.midwest temp=49.8 1472515200000000000
不推荐:以下模式在字段键中存储多个属性(crop,plot 和 region)的连接形式(blueberries.plot-1.north)。
Bad Keys schema - Data encoded in field keys (not recommended)
-------------
weather_sensor blueberries.plot-1.north.temp=50.1 1472515200000000000
weather_sensor blueberries.plot-2.midwest.temp=49.8 1472515200000000000
比较查询
比较以下的 良好测量 和 恶劣测量 方案的查询。
该 Flux 查询计算 北部 区域蓝莓的平均 温度
易于查询: 良好的测量 数据可以通过 region 标签的值轻松过滤,如以下示例所示。
// Query *Good Measurements*, data stored in separate tag values (recommended)
from(bucket: "<database>/<retention_policy>")
|> range(start:2016-08-30T00:00:00Z)
|> filter(fn: (r) => r._measurement == "weather_sensor" and r.region == "north" and r._field == "temp")
|> mean()
查询困难: 不良测量 需要正则表达式来从测量中提取 plot 和 region,如以下示例所示。
// Query *Bad Measurements*, data encoded in the measurement (not recommended)
from(bucket: "<database>/<retention_policy>")
|> range(start:2016-08-30T00:00:00Z)
|> filter(fn: (r) => r._measurement =~ /\.north$/ and r._field == "temp")
|> mean()
复杂的测量使得某些查询变得不可能。例如,计算两个图的平均温度在 Bad Measurements 模式下是不可能的。
InfluxQL 示例查询模式
# Query *Bad Measurements*, data encoded in the measurement (not recommended)
> SELECT mean("temp") FROM /\.north$/
# Query *Good Measurements*, data stored in separate tag values (recommended)
> SELECT mean("temp") FROM "weather_sensor" WHERE "region" = 'north'
避免在一个标签中放入多个信息
将一个包含多个部分的单一标签拆分为单独的标签,可以简化您的查询,并通过减少对正则表达式的需求来提高性能。
考虑以下通过行协议表示的模式。
示例行协议模式
Schema 1 - Multiple data encoded in a single tag
-------------
weather_sensor,crop=blueberries,location=plot-1.north temp=50.1 1472515200000000000
weather_sensor,crop=blueberries,location=plot-2.midwest temp=49.8 1472515200000000000
Schema 1 数据编码了多个独立的参数,plot 和 region 合并为一个长标签值 (plot-1.north)。将其与以下以行协议表示的模式进行比较。
Schema 2 - Data encoded in multiple tags
-------------
weather_sensor,crop=blueberries,plot=1,region=north temp=50.1 1472515200000000000
weather_sensor,crop=blueberries,plot=2,region=midwest temp=49.8 1472515200000000000
使用Flux或InfluxQL计算north区域蓝莓的平均temp。由于使用多个标签,建议使用Schema 2,这样您不需要正则表达式。
查询架构的Flux示例
// Schema 1 - Query for multiple data encoded in a single tag
from(bucket:"<database>/<retention_policy>")
|> range(start:2016-08-30T00:00:00Z)
|> filter(fn: (r) => r._measurement == "weather_sensor" and r.location =~ /\.north$/ and r._field == "temp")
|> mean()
// Schema 2 - Query for data encoded in multiple tags
from(bucket:"<database>/<retention_policy>")
|> range(start:2016-08-30T00:00:00Z)
|> filter(fn: (r) => r._measurement == "weather_sensor" and r.region == "north" and r._field == "temp")
|> mean()
查询模式的 InfluxQL 示例
# Schema 1 - Query for multiple data encoded in a single tag
> SELECT mean("temp") FROM "weather_sensor" WHERE location =~ /\.north$/
# Schema 2 - Query for data encoded in multiple tags
> SELECT mean("temp") FROM "weather_sensor" WHERE region = 'north'
分片组持续时间管理
分片组持续时间概述
InfluxDB 将数据存储在分片组中。 分片组按 保留策略 (RP) 组织,并存储在特定时间间隔内的时间戳数据,该时间间隔称为 分片持续时间。
如果未提供分片组持续时间,则分片组持续时间由创建RP时的duration决定。默认值为:
| RP 时长 | 分片组时长 |
|---|---|
| < 2 天 | 1 小时 |
| >= 2 天并且 <= 6 个月 | 1 天 |
| > 6 个月 | 7 天 |
分片组持续时间在每个RP中也是可配置的。 要配置分片组持续时间,请参见 保留策略管理。
分片组持续时间权衡
确定最佳分片组持续时间需要在以下两个方面找到平衡:
- 更好的整体性能与更长的块
- 通过较短的分片提供的灵活性
长片段组持续时间
更长的分片组持续时间使InfluxDB能够在同一逻辑位置存储更多数据。这减少了数据重复,提高了压缩效率,并在某些情况下提高了查询速度。
短共享组持续时间
较短的碎片组持续时间可以使系统更有效地丢弃数据并记录增量备份。当 InfluxDB 强制执行保留策略时,它会丢弃整个碎片组,而不是单个数据点,即使这些点的时间早于保留策略的持续时间。只有当碎片组的持续时间 结束时间 年长于保留策略的持续时间时,碎片组才会被移除。
例如,如果您的保留策略(RP)持续一天,InfluxDB 将每小时丢弃一小时的数据,并始终保留 25 个分片组。每个分片组对应一天中的一个小时,还有一个部分过期但未删除的额外分片组,直到整个分片组的年龄超过 24 小时才会被删除。
注意:一个需要考虑的特殊用例:按时间过滤架构数据(如标签、系列、测量)。例如,如果您想在一个小时的时间间隔内过滤架构数据,您必须将分片组持续时间设置为1h。有关更多信息,请参阅按时间过滤架构数据。
分片组持续时间建议
默认的分片组持续时间适用于大多数情况。然而,高吞吐量或长时间运行的实例将受益于使用更长的分片组持续时间。
以下是一些关于更长分片组持续时间的建议:
| RP 时长 | 分片组时长 |
|---|---|
| <= 1 天 | 6 小时 |
| > 1天并且<= 7天 | 1天 |
| > 7 天且 <= 3 个月 | 7 天 |
| > 3个月 | 30天 |
| 无限的 | 52周或更长时间 |
注意: 请注意
INF(无限)不是一个 有效的碎片组持续时间。在数据覆盖数十年且永远不会被删除的极端情况下,像1040w(20年)这样的长碎片组持续时间是完全有效的。
在设置分片组持续时间之前需要考虑的其他因素:
用于回填的分片组持续时间
大范围历史数据的批量插入会同时触发大量分片的创建。对数百或数千个分片的并发访问和写入开销很快会导致性能下降和内存耗尽。
在编写历史数据时,我们强烈建议暂时设置更长的分片组持续时间,以减少创建的分片数量。通常,52周的分片组持续时间适合进行数据回填。