T4L2

Time to learn for everything

0%

InfluxDB初探

InfluxDB是一个开源的时序数据库,也是目前Github上最流行、性能最好的开源时序数据库之一。它由Go语言编写,用于存储和查询数据。相比于OpenTSDB,它部署相对简单,不需要额外的外部依赖。当前,influxDB分为1.x和2.x版本,而2.x版本又分为开源版本和企业版本。1.x版本是传统的开源版本,目前已经更新到了1.8.3;2.x开源版本当前还停留在rc(最终测试)版本。两者之间差距较大,本文专注于1.x版本。

1. 名词介绍

timestamp:时间戳,RFC3339格式

filed key/value:相当于一条记录里的值,例如butterflies = 3,一条记录里可以有多个

tag key/value:相当于一条记录里的属性,例如scientist = langstroth,一条记录里可以有多个,会被全索引

field set:filed key/value的集合

tag set:tag key/value的集合

measurement:概念类似传统数据库的表,含有timestamp、filed和tag列

retention police:保留策略,默认为数据永不删除且只有一份数据

series:具有共同retention policy、measurement和tag set的集合

point:唯一存在的一条记录,即timestamp和series的组合唯一存在的field

2. InfluxQL

……

SELECT 语句

select * from “

查询measurement下的所有数据。

select count(““) from “

查询measurement下data非空的数据量。

3. 存储

参考:In-memory indexing and the Time-Structured Merge Tree (TSM)

作为一个热门的时序数据库,influxDB的存储也有其独到之处,它主要有以下组件构成:

  • 内存索引(In-Memory Index):内存中的索引是所有shards公用的,可以快速检索measurements、tags和series。

  • WAL(Write Ahead Log):这是一种针对写优化的存储格式,可持久写入,但查询不易。其文件形式类似于_000001.wal,文件号单增,默认达到10MB后开启一个新文件。其存储写入和删除操作的压缩块。在influxDB重启后,会重新读取wal文件创建内存缓存。

  • 缓存(Cache):WAL存储数据在内存中的副本,在内存中时不压缩,最终存储到TSM中。WAL和缓存是在客户端数据写入时同时写入的,其中WAL主要用于当influxDB宕掉重启后恢复内存中还没来得及持久化到TSM中的数据,即Cache数据;而Cache数据在数据量达到阈值后合并持久化到TSM存储文件中。在查询时,会将内存中的数据和TSM中的数据合并并生成新的副本,因此查询是在内存数据的副本中进行的,查询过程中的写入不会影响查询结果。可以设置缓存阈值,参见本小节参考。

  • TSM文件:压缩存储数据。

  • FileStore:主导对磁盘上所有TSM文件的访问。在influxDB重启后自动导入所有TSM文件,并删除不再使用的TSM文件。

  • 压缩器(Compactor):检测合并机制组件,在后台持续运行,默认每隔1s检查一次,负责将Cache和TSM文件转化为读优化的格式,主要通过压缩series、删除已删除的数据、优化索引和合并小文件。

  • Compaction Planner:确定哪些TSM文件已经准备好进行压缩,并确保多个并发的压缩不会相互干扰。

  • Compression:

  • Writers/Readers:每种文件类型都有各自的Writers/Readers。

存储目录

influxDB的数据存储目录默认情况下有meta、wal和data三个目录,其中meta存储数据库的一些元数据,目录下有一个meta.db文件;wal目录下存放wal文件;data目录下存放tsm文件。

TSM文件

TSM文件是内存映射的只读文件集合,由4部分组成:header、blocks、index和footer。具体结构如下:

1
+--------+------------------------------------+-------------+--------------+
2
| Header |               Blocks               |    Index    |    Footer    |
3
|5 bytes |              N bytes               |   N bytes   |   4 bytes    |
4
+--------+------------------------------------+-------------+--------------+

Header中,magic数字用于区分文件类型,version用于区分版本号。

1
+-------------------+
2
|      Header       |
3
+-------------------+
4
|  Magic  │ Version |
5
| 4 bytes │ 1 byte  |
6
+-------------------+

1
+--------------------------------------------------------------------+
2
│                           Blocks                                   │
3
+---------------------+-----------------------+----------------------+
4
|       Block 1       |        Block 2        |       Block N        |
5
+---------------------+-----------------------+----------------------+
6
|   CRC    |  Data    |    CRC    |   Data    |   CRC    |   Data    |
7
| 4 bytes  | N bytes  |  4 bytes  | N bytes   | 4 bytes  |  N bytes  |
8
+---------------------+-----------------------+----------------------+

索引

1
+-----------------------------------------------------------------------------+
2
│                                   Index                                     │
3
+-----------------------------------------------------------------------------+
4
│ Key Len │   Key   │ Type │ Count │Min Time │Max Time │ Offset │  Size  │...│
5
│ 2 bytes │ N bytes │1 byte│2 bytes│ 8 bytes │ 8 bytes │8 bytes │4 bytes │   │
6
+-----------------------------------------------------------------------------+

footer存储index的起点偏移量。

1
+---------+
2
│ Footer  │
3
+---------+
4
│Index Ofs│
5
│ 8 bytes │
6
+---------+

4. 内存占用

当前,influxDB同样存在许多问题,首当其冲的便是内存占用问题。随着influxDB使用时间/数据量的增长,influxDB的内存占用会成GB地增长,占用大量的资源。

倒排索引

influxDB内存占用最主要的因素在于其使用内存构建索引,因此随着索引量的增加,其内存占用也会不断上涨。InfluxDB的索引默认是基于内存的倒排索引,由两个map组成,分别是map<SeriesID, SeriesKey>map<tagKey, map<tagValue, List<SeriesID\>>>。一个查询过程如下:

  1. 通过第二个map确定符合查询语句各个tag条件的SeriesID的集合;
  2. 各个SeriesID的集合做交集形成完全符合查询语句tag条件的SeriesID的集合;
  3. 通过第一个map找到集合中SeriesID对应SeriesKey的集合;
  4. 根据时间范围找到所有满足条件的时序数据集合。

通过这种基于内存的索引方案会使得查询十分高效,但显然在许多情况下(例如集群监控),serieskey的数量会非常多,导致内存消耗过大;另外,如果influxDB意外宕掉,需要扫描全部的TSM文件再再内存中全量重构索引,恢复时间较长。因此,influxDB推出了基于磁盘存储的索引TSI。

TSI方案将索引持久化到磁盘,并在使用时再加载到内存。

TSI