三、原理

文件目录


# wal 目录结构
-- wal
   -- mydb
      -- autogen
         -- 1
            -- _00001.wal
         -- 2
            -- _00035.wal
      -- 2hours
         -- 1
            -- _00001.wal
 
# data 目录结构
-- data
   -- mydb
      -- autogen
         -- 1
            -- 000000001-000000003.tsm
         -- 2
            -- 000000001-000000001.tsm
      -- 2hours
         -- 1
            -- 000000002-000000002.tsm

LSM Tree

核心思想的核心就是放弃部分读能力,换取写入的最大化能力。它的核心思路其实非常简单,就是先将最新的数据驻留在内存中,等到积累到最后多之后,再使用归并排序的方式将内存内的数据合并追加到磁盘队尾

对磁盘来说,能够最大化的发挥磁盘技术特性的使用方式是:一次性的读取或写入固定大小的一块数据,并尽可能的减少随机寻道这个操作的次数。

存储引擎的变迁

LevelDB

会产生大量的shard文件描述符,将系统资源耗尽。

BoltDB

某些环境下会产生随机写,导致写入性能下降

时序数据
influxDB系列(四)TSM引擎(存储原理)_缓存

可以认为SeriesKey就是一个数据源

InfluxDB在内存中使用一个Map来存储时间线数据,这个Map可以表示为<Key, List>。其中Key表示为seriesKey+fieldKey,Map中一个Key对应一个List,List中存储时间线数据。其实这是个非常自然的想法,并没有什么高深的难点。基于Map这样的数据结构,时序数据写入内存流程可以表示为如下三步:

  1. 时间序列数据进入系统之后首先根据measurement + tags拼成seriesKey

  2. 根据这个seriesKey以及待查fieldKey拼成Key,再在Map中根据Key找到对应的时间序列集合,如果没有的话就新建一个新的List

  3. 找到之后将Timestamp|Value组合值追加写入时间线数据链表中

TSM 存储引擎

TSM 存储引擎主要由几个部分组成: cache、wal、tsm file、compactor

cache、wal

插入数据时,实际上是同时往 cache 与 wal 中写入数据,可以认为 cache 是 wal 文件中的数据在内存中的缓存。当 InfluxDB 启动时,会遍历所有的 wal 文件,重新构造 cache,这样即使系统出现故障,也不会导致数据的丢失。

**cache 中的数据并不是无限增长的,有一个 maxSize 参数用于控制当 cache 中的数据占用多少内存后就会将数据写入 tsm 文件。**如果不配置的话,默认上限为 25MB,每当 cache 中的数据达到阀值后,会将当前的 cache 进行一次快照,之后清空当前 cache 中的内容,再创建一个新的 wal 文件用于写入,剩下的 wal 文件最后会被删除,快照中的数据会经过排序写入一个新的 tsm 文件中。

目前的 cache 的设计有一个问题,当一个快照正在被写入一个新的 tsm 文件时,当前的 cache 由于大量数据写入,又达到了阀值,此时前一次快照还没有完全写入磁盘,InfluxDB 的做法是让后续的写入操作失败,用户需要自己处理,等待恢复后继续写入数据

TSM文件

单个 tsm 文件的主要格式如下

主要分为四个部分: Header, Blocks, Index, Footer

其中 Index 部分的内容会被缓存在内存中,下面详细说明一下每一个部分的数据结构。

influxDB系列(四)TSM引擎(存储原理)_存储引擎_02

influxDB系列(四)TSM引擎(存储原理)_数据_03

influxDB系列(四)TSM引擎(存储原理)_数据_04

influxDB系列(四)TSM引擎(存储原理)_缓存_05

compactor

compactor 组件在后台持续运行,每隔 1 秒会检查一次是否有需要压缩合并的数据。

主要进行两种操作,一种是 cache 中的数据大小达到阀值后,进行快照,之后转存到一个 tsm 文件中。

另外一种就是合并当前的 tsm 文件,将多个小的 tsm 文件合并成一个,使每一个文件尽量达到单个文件的最大大小,减少文件的数量,并且一些数据的删除操作也是在这个时候完成。

读写流程

读流程

influxDB系列(四)TSM引擎(存储原理)_数据_06

  1. 首先根据Key找到对应的SeriesIndex Block,因为Key是有序的,所以可以使用二分查找来具体实现

  2. 找到SeriesIndex Block之后再根据查找的时间范围,使用[MinTime, MaxTime]索引定位到可能的Series Data Block列表

  3. 将满足条件的Series Data Block加载到内存中解压进一步使用二分查找算法查找即可找到

写流程
  1. httpd 服务解析出要插入的所有 Points,以及数据库,存储策略等内容,之后调用 PointsWriter 的 WritePoints 方法插入数据。
  2. WritePoints 函数会根据 Point 的时间戳判断出其属于哪一个 Shard,之后调用 writeToShard 函数批量将 Points 分别写入到不同的 Shard 中。

硬件推介
influxDB系列(四)TSM引擎(存储原理)_数据_07