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 的,原因:
- Go 1.12 将 madvise 策略由
MADV_DONTNEED
改成了MADV_FREE
,这会导致 runtime 提高效率,但是不会更新 RSS(只有系统 压力较大时才更新),也就是说这是一种用“空间来换时间”的做法; - 后来遇到这个问题的人越来越多了,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.145224194Z
和 2262-04-11T23:47:16.854775806Z
之间。
SELECT
使用 GROUP BY time()
时,默认的时间范围是 1677-09-21T00:12:43.145224194Z
和 now()
之间。
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 语句
LIMIT
和 SLIMIT
限制 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 生产的实例到底怎么监控呢?
- InfluxDB 实例会暴露 http://localhost:8086/debug/vars
- 本机的 Telegraf 添加 InfluxDB Input 插件
- Telegraf 配置数据暴露给 Prometheus
- 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 数据;
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