InfluxDB 是一个时间序列数据库,用于处理海量写入与负载查询。InfluxDB旨在用作涉及大量时间戳数据的任何用例(包括DevOps监控,应用程序指标,物联网传感器数据和实时分析)的后端存储。
在 InfluxDB 中,我们可以粗略的将要存入的一条数据看作一个虚拟的 key 和其对应的 value(field value),格式如下:
cpu_idle,host=k0614v,region=us-west value=83.13 1524730697000000000
虚拟的 key 包括以下几个部分: database, retention policy, measurement, tag sets, field name, timestamp
,database和retention policy在上面的数据中并没有体现,通常在插入数据时在 http 请求的相应字段中指定。
database
InfluxDB 中可以创建多个数据库,不同数据库中的数据文件是隔离存放的,存放在磁盘上的不同目录。
retention policy
存储策略,用于设置数据保留的时间、集群中存放副本数量以及shard group覆盖的时间范围。每个数据库刚开始会自动创建一个默认的存储策略 autogen,数据保留时间为永久,副本数量为1,shard group持续时间为7天,之后用户可以自己设置。InfluxDB 会定期清除过期的数据。
measurement
measurement作为tags,fields和time列的容器,measurement也是存储在相关字段中的数据的描述
tag sets
tags 在 InfluxDB 中会按照字典序排序,不管是 tag key 还是 tag value,只要不一致就分别属于两个 key,例如 host=k0614v,region=us-west 和 host=k0615v,region=us-west 就是两个不同的 tag sets
field name
例如上面数据中的 value 就是 fieldName,InfluxDB 中支持一条数据中插入多个fieldName,这其实是一个语法上的优化,在实际的底层存储中,是当作多条数据来存储。
timestamp
每一条数据都需要指定一个时间戳,在 TSM 存储引擎中会特殊对待,以为了优化后续的查询
InfluxDB 中单条插入语句的数据结构,series + timestamp 可以用于区别一个 point,也就是说一个 point 可以有多个 field name 和 field value。
series 相当于是 InfluxDB 中一些数据的集合,在同个 database 中,retention policy、measurement、tag完全相同的数据同属于一个 series,同个series的数据在物理上会按照时间顺序排列存储在一起。
series的key为measurement + 所有 tags 的序列化字符串,这个key在之后会经常用到。
shard是在 tsm 存储引擎之上的一个概念。在 InfluxDB 中按照数据的时间戳所在的范围,会去创建不同的 shard,每一个 shard 都有自己的 cache、wal、tsm file 以及 compactor,这样做的目的就是为了可以通过时间来快速定位到要查询数据的相关资源,加速查询的过程,并且也让之后的批量删除数据的操作变得非常简单且高效。
每个shard有且只有一个shard group。 单个shard group中可能存在多个shard。 每个shard包含特定的series集合。
Shard duration决定了每个shard group的时间跨度。具体由retention policy的 SHARD DURATION
决定
shard group按照time、retention policy进行组织。每个包含数据的retention policy至少有一个关联的shard group。给定的shard group包含时间区间内所有shard数据。 每个shard group跨越的间隔是shard duration。
CQ 是预先配置好的一些查询命令,定期自动执行这些命令并将查询结果写入指定的 measurement 中,这个功能主要用于数据聚合。
InfluxDB存储引擎看起来非常类似于LSM树。它主要由cache、wal、tsm file、compactor组成
cache是当前存储在WAL中的所有数据的内存副本。point由metric,tag和唯一字段组成。每个字段保持其自己的时间有序范围。cache中的数据未被压缩。对存储引擎的查询将合并Cache和TSM中的数据。
当influxDB启动时,会遍历所有的wal文件,重新构造cache,这样即使系统出现故障,也不会导致数据的丢失。
wal的内容与cache相同,其作用就是为了持久化数据,当系统崩溃后可以通过wal文件恢复还没有写入到tsm文件中的数据。
由于数据是被顺序插入到wal文件中,所以写入效率非常高。但是如果写入的数据没有按照时间顺序排列,而是以杂乱无章的方式写入,数据将会根据时间路由到不同的shard中,每一个shard都有自己的wal文件,这样就不再是完全的顺序写入,对性能会有一定影响。官方社区有说后续会进行优化,只使用一个 wal,而不是为每一个shard 创建 wal。
wal单个文件达到一定大小后会进行分片,创建一个新的wal分片文件用于写入数据。
TSM文件是内存映射的只读文件的集合。 这些文件的结构看起来与LevelDB或其他LSM树变体中的SSTable非常相似。
一个TSM文件由4个区域组成:header,blocks,index,footer
┌────────┬────────────────────────────────────┬─────────────┬──────────────┐ │ Header │ Blocks │ Index │ Footer │ │5 bytes │ N bytes │ N bytes │ 4 bytes │ └────────┴────────────────────────────────────┴─────────────┴──────────────┘
┌───────────────────┐ │ Header │ ├─────────┬─────────┤ │ Magic │ Version │ │ 4 bytes │ 1 byte │ └─────────┴─────────┘
0x16D116D1
1
┌───────────────────────────────────────────────────────────┐ │ Blocks │ ├───────────────────┬───────────────────┬───────────────────┤ │ Block 1 │ Block 2 │ Block N │ ├─────────┬─────────┼─────────┬─────────┼─────────┬─────────┤ │ CRC │ Data │ CRC │ Data │ CRC │ Data │ │ 4 bytes │ N bytes │ 4 bytes │ N bytes │ 4 bytes │ N bytes │ └─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘
Blocks 是一系列crc32和数据块组成。crc32可以用来恢复,确保data的完整性。block的长度保存在索引中。
┌────────────────────────────────────────────────────────────────────────────┐ │ Index │ ├─────────┬─────────┬──────┬───────┬─────────┬─────────┬────────┬────────┬───┤ │ Key Len │ Key │ Type │ Count │Min Time │Max Time │ Offset │ Size │...│ │ 2 bytes │ N bytes │1 byte│2 bytes│ 8 bytes │ 8 bytes │8 bytes │4 bytes │ │ └─────────┴─────────┴──────┴───────┴─────────┴─────────┴────────┴────────┴───┘
索引由一系列索引条目组成,先按照 key 的字典序排序,再按照 time 排序。 每条索引都以key len、key开始,count是文件中块的数量。
以下部分为block索引,根据count数量重复出现。
┌─────────┐ │ Footer │ ├─────────┤ │Index Ofs│ │ 8 bytes │ └─────────┘
最后是Footer,它主要是存放索引的开始位置。
compactor是一个持续的过程,优化存储,提升查询性能,具体做以下几件事: