InfluxDB v1.x

Table of Contents

1. 运维

Retention policy DURATION 决定 InfluxDB 保留数据的时长。 SHARD DURATION 决定子语句确定分片组覆盖的时间范围。对应关系:

Retention policy DURATION Shard Group Duration
< 2 days 1 hour
>= 2 days and <= 6 months 1 day
> 6 months 7 day

1.8 版本 InfluxDB 占用内存较大解决方,启动时加上 GODEBUG=madvdontneed=1 ,会在 Go 不需要内存的时候及时释放, 这是一个 Go 的参数,并不是 InfluxDB 的,原因:

  1. Go 1.12 将 madvise 策略由 MADV_DONTNEED 改成了 MADV_FREE ,这会导致 runtime 提高效率,但是不会更新 RSS(只有系统 压力较大时才更新),也就是说这是一种用“空间来换时间”的做法;
  2. 后来遇到这个问题的人越来越多了,Go 1.16 之后又改回去了

InfluxDB 1.8 版本用的是 Go 1.13 ,所以恰好在这个版本范围内。

2. InfluxQL 使用

2.1. SELECT 语句

SELECT <field_key>[,<field_key>,<tag_key>] FROM <measurement_name>[,<measurement_name>]

当 SELECT 中包含 tag 时,只要需要同时包含一个 field。当 tag 和 field 的名字相同的时候可以携带标识符类型来区分。 比如: "<field_key>"::field 表示 field, "<tag_key>::tag" 表示 tag。

2.2. FROM 语句

FROM 语句支持一个或者多个 measurement(s):

  • FROM <measurement_name> 查询单个表
  • FROM <measurement_name>,<measurement_name> 查询多个表
  • FROM <database_name>.<retention_policy_name>.<measurement_name> 指定数据库和保留策略
  • FROM <database_name>..<measurement_name> 指定数据库,使用默认的保留策略

2.2.1. 引号

如果标识符包含除了 [A-z,0-9,_] 以外的字符、以数字开头或者是 InfluxQL 关键则,那么标识符必须用双引号引起来。 虽然不总是必要,但是建议你使用双引号。

2.2.2. 范例

查询所有的 fields SELECT *::field ,但是不能通过这个方法来查询所有的 tags。

数学运算: SELECT ("water_level" * 2) + 4 FROM "h2o_feet"

常见 SELECT 问题:在 SELECT 中只包含 tag,会查询不到数据。

2.3. WHERE 语句

WHERE 基于 fields,tags 和 timestamps 的过滤。

SELECT_clause FROM_clause WHERE <conditional_expression> [(AND|OR) <conditional_expression> [...]]

注意 InfluxDB 不支持在 WHERE 语句中用多个时间范围之间用 OR 运算。如下语句会返回空:

> SELECT * FROM "absolutismus" WHERE time = '2016-07-31T20:07:00Z' OR time = '2016-07-31T23:07:17Z'

2.3.1. Fields

field_key <operator> ['string' | boolean | float | integer]

field 值支持字符串,布尔,浮点型和整型比较。 WHERE 中字符串使用单引号。

支持的比较运算符:

Operator Meaning
= 等于
<> 不等于
!= 不等于
> 大于
>= 大于等于
< 小于
<= 小于等于

2.3.2. Tags

tag_key <operator> ['tag_value']

tags 的值要使用单引号。支持的运算符:

Operator Meaning
= 等于
<> 不等于
!= 不等于

2.3.3. Timestamps

对于大部分的 SELECT 语句,默认的时间范围是 1677-09-21T00:12:43.145224194Z2262-04-11T23:47:16.854775806Z 之间。

SELECT 使用 GROUP BY time() 时,默认的时间范围是 1677-09-21T00:12:43.145224194Znow() 之间。

2.4. GROUP BY 语句

GROUP BY 对查询结果进行分组:

  • 基于一个或者多个 tags
  • 指定时间间隔

注意: 你不可以对 fields 使用 GROUP BY

2.4.1. GROUP BY tags

SELECT_clause FROM_clause [WHERE_clause] GROUP BY [* | <tag_key>[,<tag_key]]

GROUP BY * 按照所有 tag 分组

GROUP BY <tag_key> 按照单个 tag 分组

GROUP BY <tag_key>,<tag_key> 多个 tag 分组,tag 的顺序无关紧要

如果包含 WHERE 语句, GROUP BY 语句必须出现在 WHERE 之后

2.4.2. GROUP BY time intervals

2.4.2.1. Basic GROUP BY time() syntax
SELECT <function>(<field_key>) FROM_clause WHERE <time_range> GROUP BY time(<time_interval>),[tag_key] [fill(<fill_option>)]
  • time(time_interval) 按照持续时间进行分组
  • fill(<fill_option>) 可选的,它会更改为没有数据的时间间隔报告的值
2.4.2.2. Advanced GROUP BY time() syntax
SELECT <function>(<field_key>) FROM_clause WHERE <time_range> GROUP BY time(<time_interval>,<offset_interval>),[tag_key] [fill(<fill_option>)]

2.5. INTO 语法

INTO 将查询结果写入到用户指定的 measurment。

SELECT_clause INTO <measurement_name> FROM_clause [WHERE_clause] [GROUP_BY_clause]

measurement_name 与 FROM 后紧跟的库表语法规范类似。

2.6. ORDER BY time DESC

SELECT_clause [INTO_clause] FROM_clause [WHERE_clause] [GROUP_BY_clause] ORDER BY time DESC

如果包含 GROUP BY 条件的话, ORDER by time DESC 必须出现在 GROUP BY 之后。如果查询包含 WHERE 但是没有 GROUP BY 条件, ORDER by time DESC 必须在 WHERE 之后。

2.7. LIMIT 和 SLIMIT 语句

LIMITSLIMIT 限制 points 和 series 查询的返回数量。

2.7.1. LIMIT 语句

SELECT_clause [INTO_clause] FROM_clause [WHERE_clause] [GROUP_BY_clause] [ORDER_BY_clause] LIMIT <N>

注意 LIMIT 必须放在上面所有语句的最后。

2.7.2. SLIMIT 语句

SELECT_clause [INTO_clause] FROM_clause [WHERE_clause] GROUP BY *[,time(<time_interval>)] [ORDER_BY_clause] SLIMIT <N>

2.8. OFFSET 和 SOFFSET 语句

OFFSET <N> 对查询结果进行 N points 的分页。

SELECT_clause [INTO_clause] FROM_clause [WHERE_clause] [GROUP_BY_clause] [ORDER_BY_clause] LIMIT_clause OFFSET <N> [SLIMIT_clause]

OFFSET 需要和 LIMIT 一起使用,否则会导致查询结果不一致。整体表达的是: OFFSET 之后的 LIMIT 个元素。

2.9. 时区(time zone)语句

tz() 语句指定时区1

SELECT_clause [INTO_clause] FROM_clause [WHERE_clause] [GROUP_BY_clause] [ORDER_BY_clause] [LIMIT_clause] [OFFSET_clause] [SLIMIT_clause] [SOFFSET_clause] tz('<time_zone>')

默认情况下,InfluxDB 存储和返回 UTC 时间戳。

3. 监控

3.1. InfluxDB _internal 1.x 表和字段

https://docs.influxdata.com/platform/monitoring/influxdata-platform/tools/measurements-internal/

默认情况下,InfluxDB 生成内部的指标保存到 _internal 库中。

3.1.1. 在生产环境下禁用 _internal 库

InfluxData 不推荐在生产集群中使用 _internal 。它带来了不必要的开销,特别是集群比较忙的情况下,会加重集群的复杂。 _internal 数据库中存储的指标主要衡量工作负载性能,只能在非生产环境使用。

InfluxDB 配置文件将 [monitor] 下的 store-enabled 设置成 false 可以关闭 _internal 数据库。

# ...
[monitor]
  # ...
  # Whether to record statistics internally.
  store-enabled = false
  #...

3.1.2. 将内部指标存储在外部监控中

在生产的集群中 InfluxDB _internal 指标,使用 Telegraf 和 influxdb 输入插件 来捕获 /debug/vars 端点下的指标然后存储在外部的 InfluxDB 监控实例中。具体看:配置监控的监控

3.1.3. 那 InfluxDB 生产的实例到底怎么监控呢?

  1. InfluxDB 实例会暴露 http://localhost:8086/debug/vars
  2. 本机的 Telegraf 添加 InfluxDB Input 插件
  3. Telegraf 配置数据暴露给 Prometheus
  4. Prometheus 新增 Target

4. FAQ

4.1. InfluxDB 写入时,tag 和 field 的 values 不支持换行符。

https://docs.influxdata.com/influxdb/v1.8/write_protocols/line_protocol_reference/

<measurement>[,<tag_key>=<tag_value>[,<tag_key>=<tag_value>]] <field_key>=<field_value>[,<field_key>=<field_value>] [<timestamp>]

Line protocol 对于 \n 和空格比较敏感:

  • 空格用来分隔 tag、field 和 timestamp;
  • 换行符用来分隔两个 point(在批量写入的时候),所以当 fields 中出现换行符时,会分隔当前的 point 数据;

https://github.com/influxdata/influxdb/issues/9966 这个帖子中也有。

4.2. InfluxDB 如何处理重复的点?

Point(点)由表名,tag 集合和时间戳唯一标识。如果你提交的一个 point 和现有的 point 有相同的标识,fields 集合会变成新的 field 和老的 field 的合集,关联关系会指向新的 field 集合。这是预料中的事。

比如:

  • Old point: cpu_load,hostname=server02,az=us_west val_1=24.5,val_2=7 1234567890000000
  • New point: cpu_load,hostname=server02,az=us_west val_1=5.24 1234567890000000

提交新的 point 之后,InfluxDB 会覆写 val_1 的新值, 不管 val_2 。最终的结果是:

> SELECT * FROM "cpu_load" WHERE time = 1234567890000000
name: cpu_load
--------------
time                      az        hostname   val_1   val_2
1970-01-15T06:56:07.89Z   us_west   server02   5.24    7

为了存储这两个 points:

  • 引入一个任意的新标签来强制保持唯一

Old point: cpu_load,hostname=server02,az=us_west,uniq=1 val_1=24.5,val_2=7 1234567890000000

New point: cpu_load,hostname=server02,az=us_west,uniq=2 val_1=5.24 1234567890000000

在 New point 写入到 InfluxDB 之后:

> SELECT * FROM "cpu_load" WHERE time = 1234567890000000
name: cpu_load
--------------
time                      az        hostname   uniq   val_1   val_2
1970-01-15T06:56:07.89Z   us_west   server02   1      24.5    7
1970-01-15T06:56:07.89Z   us_west   server02   2      5.24
  • 时间上增加一个纳秒

Old point: cpu_load,hostname=server02,az=us_west,uniq=1 val_1=24.5,val_2=7 1234567890000000

New point: cpu_load,hostname=server02,az=us_west,uniq=2 val_1=5.24 1234567890000000

在 New point 写入到 InfluxDB 之后:

> SELECT * FROM "cpu_load" WHERE time >= 1234567890000000 and time <= 1234567890000001
name: cpu_load
--------------
time                             az        hostname   val_1   val_2
1970-01-15T06:56:07.89Z          us_west   server02   24.5    7
1970-01-15T06:56:07.890000001Z   us_west   server02   5.24

Footnotes:

First created: 2021-04-23 14:02:41
Last updated: 2022-12-11 Sun 12:49
Power by Emacs 29.0.91 (Org mode 9.6.6)