时序数据库 InfluxDB
InfluxDB 是使用 Go 编写的基于时间序列的数据库,用于存储大量带有时间戳的数据,报错 DevOps 监控,日志数据,应用程序的指标、数据分析数据等等。通过 InfluxDB 自动保存数据,你不需要删除和清理,只需要定义一段时间 DB 会帮你自动清理。
关键概念
基本概念
InfluxDB 和传统数据库(如:MySQL)的一些区别
| InfluxDB | 传统数据库中的概念 |
|---|---|
| database | 数据库 |
| measurement | 数据库中的表 |
| points | 表里面的一行数据 |
特有概念
-
tag–标签,在 InfluxDB 中,tag 是一个非常重要的部分,表名+tag 一起作为数据库的索引,是“key-value”的形式
-
field–数据,field 主要是用来存放数据的部分,也是“key-value”的形式
-
timestamp–时间戳,作为时序型数据库,时间戳是 InfluxDB 中最重要的部分,在插入数据时可以自己指定也可留空让系统指定
说明:在插入新数据时,tag、field 和 timestamp 之间用空格分隔
-
series–序列,所有在数据库中的数据,都需要通过图表来展示,而这个 series 表示这个表里面的数据,可以在图表上画成几条线。具体可以通过
SHOW SERIES FROM "表名"进行查询 -
Retention policy–数据保留策略,可以定义数据保留的时长,每个数据库可以有多个数据保留策略,但只能有一个默认策略
-
Point–点,表示每个表里某个时刻的某个条件下的一个 field 的数据,因为体现在图表上就是一个点,于是将其称为 point。Point 由时间戳(time)、数据(field)、标签(tags)组成
| Point 属性 | 传统数据库中的概念 |
|---|---|
| time | 每个数据记录时间,是数据库中的主索引 (会自动生成) |
| fields | 表中的列(没有索引的属性)也就是记录的值:温度, 湿度 |
| tags | 表中的索引:地区,海拔 |
端口服务
- 8083:Web admin 管理服务的端口, http://localhost:8083
- 8086:HTTP API 的端口
- 8088:集群端口 (目前还不是很清楚, 配置在全局的 bind-address,默认不配置就是开启的)
安装部署
|
|
客户端命令操作
数据库操作
创建
CREATE DATABASE {NAME};
|
|
- 这时候我们发现数据库有一个表“_internal”,其实这个表是 influxdb 数据库的一些指标存储库。有点类似 mysql 数据库的 mysql 库。
删除
DROP DATABASE {NAME};
|
|
使用
USE {DB}
|
|
数据表和数据操作
建库的操作可以发现非常类似于 MySQL 下的操作。而在 InfluxDB 下没有细分的表的概念,InfluxDB 下的表在插入数据库的时候自动会创建。可以通过 show measurements 命令查看所有的表,这个类似于 MySQL 下的show tables
显示所有表
|
|
新建表(写数据)
标准格式,注意在写数据的时候如果不添加时间戳,系统会默认添加一个时间。InfluxDB 中没有显式的新建表的语句,只能通过 insert 数据的方式来建立新表。
- 语法格式
|
|
- 示例
|
|
删除表
|
|
读数据
查询语句与 SQL 一样,不用过多的学习
- 查询数据
|
|
- 每个表输出一行(支持 Go 语言的正则表达式、支持类似于 MySQL 中的 limit 语句)
|
|
修改和删除数据
InfluxDB 属于时序数据库,没有提供修改和删除数据的方法。
但是删除可以通过 InfluxDB 的数据保存策略(Retention Policies)来实现
update 更新语句没有,不过有 alter 命令,在 influxdb 中,删除操作用和更新基本不用到 。在针对数据保存策略方面,有一个特殊的删除方式,这个后面再提。
series 操作
series 表示这个表里面的数据,可以在图表上画成几条线,series 主要通过 tags 排列组合算出来。
我们可以查询表的 series,如下所示:
|
|
用户操作
|
|
influxdb 的权限设置比较简单,只有读、写、ALL 几种。
HTTP API 操作
接口地址
| 接口路径 | 描述 |
|---|---|
| /debug/pprof | debug 排查问题使用 |
| /debug/requests | 使用这个请求监听最近是否有请求 |
| /debug/vars | 查询 influxdb 收集到静态信息 |
| /ping | 检测 influxdb 状态 |
| /query | 查询数据接口(同时可以创建库) |
| /write | 写入数据接口(一个已存在数据库) |
状态码
- 2xx:服务请求正常
- 4xx:代表请求语法有问题
- 5xx:服务端出问题,导致超时等故障
创建数据库
|
|
写入数据
|
|
写入多个数据点
|
|
从文件导入数据库
从文件导入时候建议不要超过 5000 条,如果超过请对文件进行切割,因为 http api 的接口 5s 会超时,请求数据过多会导致数据无法确认是否成功。
文件 cpu_data.txt 内容如下:
|
|
数据保存策略(Retention Policies)
InfluxDB 每秒可以处理成千上万条数据,要将这些数据全部保存下来会占用大量的存储空间,有时我们可能并不需要将所有历史数据进行存储。InfluxDB 没有提供直接删除 Points 的方法,但是它提供了 Retention Policies,用来让我们自定义数据的保留时间。
查看
|
|
创建
|
|
其中:
- rp_name:策略名
- db_name:具体的数据库名
- 30d:保存 30 天,30 天之前的数据将被删除
它具有各种时间参数,比如:h(小时),w(星期) - REPLICATION 1:副本个数,这里填 1 就可以了
- DEFAULT 设为默认的策略
修改
ALTER RETENTION POLICY "rp_name" ON db_name" DURATION 3w DEFAULT
删除
DROP RETENTION POLICY "rp_name" ON "db_name"
常用函数
InfluxDB 提供了很多的有用的函数,这里列举了常用的三个维度函数,Use InfluxQL functions to aggregate, select, and transform data.
| Aggregations | Selectors | Transformations |
|---|---|---|
| COUNT() | BOTTOM() | CEILING() |
| DISTINCT() | FIRST() | DERIVATIVE() |
| INTEGRAL() | LAST() | DIFFERENCE() |
| MEAN() | MAX() | ELAPSED() |
| MEDIAN() | MIN() | FLOOR() |
| SPREAD() | PERCENTILE() | HISTOGRAM() |
| SUM() | TOP() | MOVING_AVERAGE() |
| NON_NEGATIVE_DERIVATIVE() | ||
| STDDEV() |
聚合类函数
COUNT() 函数
返回一个(field)字段中的非空值的数量。
语法:
|
|
示例:
> SELECT COUNT(water_level) FROM h2o_feet
name: h2o_feet
--------------
time count
1970-01-01T00:00:00Z 15258
说明 water_level 这个字段在 h2o_feet 表中共有 15258 条数据。
注意:InfluxDB 中的函数如果没有指定时间的话,会默认以 epoch 0 (1970-01-01T00:00:00Z) 作为时间。
可以在 where 中加入时间条件,如下:
|
|
DISTINCT() 函数
返回一个字段(field)的唯一值。
语法:
|
|
使用示例
|
|
这个例子显示 level description 这个字段共有四个值,然后将其显示了出来,时间为默认时间。
MEAN() 函数
返回一个字段(field)中的值的算术平均值(平均值)。字段类型必须是长整型或 float64。
语法格式:
|
|
使用示例
|
|
说明 water_level 字段的平均值为4.286791371454075,时间为默认时间,当然,你也可以加入 where 条件。
MEDIAN() 函数
从单个字段(field)中的排序值返回中间值(中位数)。字段值的类型必须是长整型或 float64 格式。
语法:
|
|
使用示例
|
|
说明表中 water_level 字段的中位数是 4.124
SPREAD() 函数
返回字段的最小值和最大值之间的差值。数据的类型必须是长整型或 float64。
语法:
|
|
使用示例
|
|
SUM() 函数
返回一个字段中的所有值的和。字段的类型必须是长整型或 float64。
语法:
|
|
使用示例:
|
|
此语句计算出了 h2o_feet 表中 所有 water_level 字段的和。
选择类函数
TOP() 函数
作用:返回一个字段中最大的 N 个值,字段类型必须是长整型或 float64 类型。
语法:
|
|
使用示例
|
|
这个例子返回表中 water_level 字段中最大的三个值。
BOTTOM() 函数
作用:返回一个字段中最小的 N 个值。字段类型必须是长整型或 float64 类型。
语法:
|
|
使用示例
|
|
这个例子返回表中 water_level 字段中最小的三个值。
也可将关联 tag 放在一起查询,但如果 tag 值少于 N 的值,则返回的值的个数只会取 tag 中字段值少的那个。
如下所示:
|
|
语句取最小的三个值,然而结果只返回了 2 个值,因为 location 这个 tag 只有 两个取值。
FIRST() 函数
作用:返回一个字段中最老的取值。
语法:
|
|
示例:
|
|
这个语句返回了 在 location 为 santa_monica 条件下,最旧的那个 water_level 字段的取值和时间。
LAST() 函数
作用:返回一个字段中最新的取值。
语法:
|
|
示例:
|
|
MAX() 函数
作用:返回一个字段中的最大值。该字段类型必须是长整型,float64,或布尔类型。
语法:
|
|
示例:
|
|
MIN() 函数
作用:返回一个字段中的最小值。该字段类型必须是长整型,float64,或布尔类型。
语法:
|
|
示例:
|
|
PERCENTILE() 函数
作用:返回排序值排位为 N 的百分值。字段的类型必须是长整型或 float64。
百分值是介于 100 到 0 之间的整数或浮点数,包括 100。
语法:
|
|
示例:
|
|
就是将 water_level 字段按照不同的 location 求百分比,然后取第五位数据。
变换类函数
DERIVATIVE() 函数
作用:返回一个字段在一个 series 中的变化率。
InfluxDB 会计算按照时间进行排序的字段值之间的差异,并将这些结果转化为单位变化率。其中,单位可以指定,默认为 1s。
语法:
|
|
其中,unit取值可以为以下几种:
|
|
DERIVATIVE() 函数还可以在 GROUP BY time() 的条件下与聚合函数嵌套使用,格式如下:
|
|
示例:
假设 location = santa_monica 条件下数据有以下几条:
|
|
计算每一秒的变化率:
|
|
第一行数据的计算公式为(2.116 - 2.064) / (360s / 1s)
计算每六分钟的变化率
|
|
第一行数据的计算过程如下:(2.116 - 2.064) / (6m / 6m)
计算每 12 分钟的变化率:
|
|
第一行数据计算过程为:(2.116 - 2.064 / (6m / 12m)
计算每 12 分钟最大值的变化率
|
|
这个函数功能非常多,也非常复杂,更多对于此功能的详细解释请看官网:https://docs.influxdata.com/influxdb/v0.13/query_language/functions/#derivative
DIFFERENCE() 函数
作用:返回一个字段中连续的时间值之间的差异。字段类型必须是长整型或 float64。
最基本的语法:
|
|
与 GROUP BY time() 以及其他嵌套函数一起使用的语法格式:
|
|
其中,函数可以包含以下几个:
|
|
计算water_level间的差异:
|
|
数据类型都为 float 类型。
ELAPSED() 函数
作用:返回一个字段在连续的时间间隔间的差异,间隔单位可选,默认为 1 纳秒。
单位可选项如下:
| Units | Meaning |
|---|---|
| ns | nanoseconds (1 billionth of a second) |
| u or µ | microseconds (1 millionth of a second) |
| ms | milliseconds (1 thousandth of a second) |
| s | second |
| m | minute |
| h | hour |
| d | day |
| w | week |
语法:
|
|
示例:
计算 h2o_feet 字段在纳秒间隔下的差异。
|
|
在一分钟间隔下的差异率:
|
|
注意:如果设置的时间间隔比字段数据间的时间间隔更大时,则函数会返回 0,如下所示:
|
|
MOVING_AVERAGE() 函数
作用:返回一个连续字段值的移动平均值,字段类型必须是长整形或者 float64 类型。
语法:
基本语法
|
|
与其他函数和 GROUP BY time() 语句一起使用时的语法
|
|
此函数可以和以下函数一起使用:
|
|
示例:
|
|
NON_NEGATIVE_DERIVATIVE() 函数
作用:返回在一个 series 中的一个字段中值的变化的非负速率。
语法:
|
|
其中 unit 取值可以为以下几个:
Valid time specifications for unit are:
umicrosecondsssecondsmminuteshhoursddayswweeks
与聚合类函数放在一起使用时的语法如下所示:
|
|
此函数示例请参阅:DERIVATIVE()``函数
STDDEV() 函数
作用:返回一个字段中的值的标准偏差。值的类型必须是长整型或 float64 类型。
语法:
|
|
示例:
|
|
示例 2:
|
|
连续查询
定义
InfluxDB 的连续查询是在数据库中自动定时启动的一组语句,语句中必须包含 SELECT关键词和GROUP BY time()关键词。
InfluxDB 会将查询结果放在指定的数据表中。
目的
使用连续查询是最优的降低采样率的方式,连续查询和存储策略搭配使用将会大大降低 InfluxDB 的系统占用量。
而且使用连续查询后,数据会存放到指定的数据表中,这样就为以后统计不同精度的数据提供了方便。
操作
只有管理员用户可以操作连续查询。
1)新建连续查询
新建连续查询的语法如下所示:
CREATE CONTINUOUS QUERY <cq_name> ON <database_name> [RESAMPLE [EVERY <interval>] [FOR <interval>]] BEGIN SELECT <function>(<stuff>)[,<function>(<stuff>)] INTO <different_measurement> FROM <current_measurement> [WHERE <stuff>] GROUP BY time(<interval>)[,<stuff>] END
查询部分被 CREATE CONTINUOUS QUERY […] BEGIN 和 END 所包含,主要的逻辑代码也是在这一部分。
使用示例:
> CREATE CONTINUOUS QUERY cq_30m ON telegraf BEGIN SELECT mean(used) INTO mem_used_30m FROM mem GROUP BY time(30m) END
> SHOW CONTINUOUS QUERIES
name: telegraf
--------------
name query
cq_30m CREATE CONTINUOUS QUERY cq_30m ON telegraf BEGIN SELECT mean(used) INTO telegraf."default".mem_used_30m FROM telegraf."default".mem GROUP BY time(30m) END
name: _internal
---------------
name query
示例在 telegraf 库中新建了一个名为 cq_30m 的连续查询,每三十分钟取一个 used 字段的平均值,加入 mem_used_30m 表中。使用的数据保留策略都是 default。
2)显示所有已存在的连续查询
查询所有连续查询可以使用如下语句:
> SHOW CONTINUOUS QUERIES
name: telegraf
--------------
name query
cq_30m CREATE CONTINUOUS QUERY cq_30m ON telegraf BEGIN SELECT mean(used) INTO telegraf."default".mem_used_30m FROM telegraf."default".mem GROUP BY time(30m) END
name: _internal
---------------
name query
可以看到其连续查询的名称以及 语句等信息。
3)删除 Continuous Queries
删除连续查询的语句如下:
DROP CONTINUOUS QUERY <cq_name> ON <database_name>
其他说明
在 InfluxDB 中,将连续查询与数据存储策略一起使用会达到最好的效果。
比如,将精度高的表的存储策略定为一个周,然后将精度底的表存储策略定的时间久一点,这要就可以实现高低搭配,以满足不同的工作需要。
再谈连续查询
连续查询语法
连续查询的语法如下:
CREATE CONTINUOUS QUERY <cq_name> ON <database_name> [RESAMPLE [EVERY <interval>] [FOR <interval>]] BEGIN SELECT <function>(<stuff>)[,<function>(<stuff>)] INTO <different_measurement> FROM <current_measurement> [WHERE <stuff>] GROUP BY time(<interval>)[,<stuff>] END
指定连续查询的时间范围
可以使用 RESAMPLE FOR 关键词来指定连续查询的时间范围,比如,每次执行都对 1 小时内的数据进行连续查询:
CREATE CONTINUOUS QUERY vampires_1 ON transylvania RESAMPLE FOR 60m BEGIN SELECT count(dracula) INTO vampire_populations_1 FROM raw_vampires GROUP BY time(30m) END
这个语句每次会将 1 小时的数据执行连续查询,也就是说,每次执行时,会将 now() 到 now()-30m 和 now()-30m 到 now()-60m 分别做连续查询,这样我们就可以手动指定连续查询的时间范围了。
指定连续查询的执行频次
可以使用 RESAMPLE EVERY 关键词来指定连续查询的执行频次,比如,指定连续查询的执行频次为每 15m 执行一次:
CREATE CONTINUOUS QUERY vampires ON transylvania RESAMPLE EVERY 15m BEGIN SELECT count(dracula) INTO vampire_populations FROM raw_vampires GROUP BY time(30m) END
这样,连续查询会每隔 15m 执行一次。
同时指定连续查询的范围和频次
将 RESAMPLE FOR 和 EVERY 关键词同时使用,可以同时指定连续查询的范围和频次,如下:
CREATE CONTINUOUS QUERY vampires_2 ON transylvania RESAMPLE EVERY 15m FOR 60m BEGIN SELECT count(dracula) INTO vampire_populations_2 FROM raw_vampires GROUP BY time(30m) END
这个语句指定连续查询每 15m 执行一次,每次执行的范围为 60m。