因为最近在做关于监控相关工作,在使用时序数据库存储监控数据时(neflow, telemery),选择了influxdb2.x版本,下面简单说下influxdb2.x的特点,以及适配于新版的flux语法
系统常用名词概念
- organization:这是一个2.x版本新增的名词,表示工作区概念,服务目标是一组用户群体。influxdb的每一bucket、dashboard,、taskmember等都必须从属于一个organization
- bucket:bucket是用来存放每一条时序数据记录的最终位置,每个bucket都可以设定其存放的时序数据保留周期,即最大保留时间点1 influxdb里面的每一条记录,可以称为point,每一条point包含如下信息
- measurement:类似于关系型数据库里表名的概念
- tag:每一个tag有key和value2个字段,都必须是字符串类型,针对tag字段,更多是用来做查询条件用,例如需要group条件之类的情况,但如果tag的value会随着时间不断变化或者很多,建议更换为field字段
- field:同tag,每一个field也有key和value2个字段,其中只有key字段必须是字符串类型,value字段用来存储值。注意不要使用field作为查询条件,因为influxdb使用field字段的值做查询条件会扫描所有相关field。
- timstamp:Unix时间戳,可以精细到纳秒级别 以go为例,写一条point记录到influxdb,可以清晰的看到每一个系统名词的意义
Influxdb Storage Engine 这里简单介绍一下influxdb的数据引擎,可以增加我们进行数据结构设计时的理解 存储引擎主要包含下面几个组件
-
WAL(Write Ahead Log)
如果要理解WAL,那我们就需要明白数据是如何写入到influxdb里的。首先,每一个时间点的数据需要按照Line Protocol格式在终端通过http协议传入,这些时间点数据会分批的送往influxdb,进行压缩,然后生成一个WAL,同时,时间点数据也会被写入到内存变为立即可查询状态,内存中的数据会定期的按照TSM的格式写入到磁盘里,随着TSM文件时间点的积累增多,存储引擎将会将TSM文件合并为更高级别的TSM文件
WAL的作用即使为了确保在发生不可预期的错误时,确保数据的完整性,下面是数据引擎是如何将数据详细写入到磁盘里的
- 在生成WAL后,会有一个写入的请求在WAL文件的末尾
- 数据通过fsync()函数写入
- 内存里数据进行更新
- 当成功将数据写入到磁盘后,有一个确认写入成功的响应
*fsync() *: fsync函数是发生在系统级别的调用,它有一个内核上下文切换,需要比较大的数据量,但是上下文保证了数据的安全性
Line Protocol: line protocol实际上是一个文本数据的格式化
// Syntax <measurement>[,<tag_key>=<tag_value>[,<tag_key>=<tag_value>]] <field_key>=<field_value>[,<field_key>=<field_value>] [<timestamp>] // Example myMeasurement,tag1=value1,tag2=value2 fieldKey="fieldValue" 1556813561098000000虽然每个时间点数据都可以立即被发送到写入请求,但是为了效率,在做程序设计时应注意将时间点数据分批进行写入
-
Cache
通过上面对WAL的讲解,可以知道,缓存时对存放在WAL里面的数据的一个数据副本,二者相互独立
缓存的特点:
- 根据时间点数据的key(measurement, tag set, and unique field),每一个field的值字段都存储在自己的时间范围内
- 存放的时未压缩的数据
- 每一次数据引擎重启都会重新从WAL文件获取更新,查询时会于TSM文件进行合并
- 使用内存的最大值
-
TSM(Time-Structed Merge Tree)
为了有效地压缩和存储数据,存储引擎按series key对field值进行分组,然后按时间对这些值进行排序。一个series key由mesurement, tag key and value, field value决定
TSM 文件以柱状格式存储压缩的序列数据。为了提高效率,存储引擎只存储序列中值之间的差异(或增量)。面向列的存储允许引擎通过系列键读取并省略无关数据
在数据成功的被存入的TSM文件后,将截断 WAL 并清除缓存
-
TSI(Time Series Index)
官方文档只是简单说了下随着数据的series 的增多,那么查询就会越慢。根据官方文档,TSI存储了所有的series key
常用的flux语法
这里我以交换机设备的流量为例进行示范
简单的tag和field查询:下面是原始的数据表结构, 有2个tagSet 分别是Device和Port, 以及2个fieldSet SendBits和ReceiveBits, measurement以及时间戳序列
-
查询fields
可以看到,根据不同series key,将field的值数据按照时间序列存储在自己的时间范围内
-
查询tag
增加了tag字段,结果如下
-
使用derivative函数对查询到的field值做处理
上面我们可以看到,每一次新增新的函数如filter以及derivative都会对原有的查询结果进行处理,因此要特别注意函数之间的执行顺序,接下来我们看另外个查询,我这边以netflow的流量记录为例,数据结构中除了netflow来源设备Agent以及BgpNextHop作为tag字段,其余源IP,目的IP,源端口等都作为fields字段,这里是考虑到这些字段的值太多会引起series key的成倍增长导致查询速度过慢才如此设计
-
简单查询
-
统计BgpNextHop的出口流量: 这里使用group函数将BgpNextHop tag字段作为条件以及aggregateWindow函数对数据进行处理
- 统计最大的10个源IP流量: 因为SrcIP和Bit都是field字段,注意都先要全部查出来,然后使用pivot函数进行反转,并使用group将srcIP作为条件,去处理数据,最后使用highestMax函数得到最大的几个值结果
后续还有多表数据聚合,涉及到多表的联合查询,不过这里个人没有相关实例就略过了