InfluxDB TSM存储引擎之TSMFile

本篇文章主要介绍InfluxDB TSM存储引擎之TSMFile。为了保证时序数据写入的高效,InfluxDB采用LSM结构,数据先写入内存以及WAL,当内存容量达到一定阈值之后flush成文件,文件数超过一定阈值执行合并。这个套路与其他LSM系统(比如HBase)大同小异。不过,InfluxDB在LSM体系架构的基础上针对时序数据做了针对性的存储改进,官方称改进后的存储引擎为TSM(Time-Structured Merge Tree)结构引擎。本篇文章主要集中介绍TSM引擎中文件格式针对时序数据做了哪些针对性的改进,才使得InfluxDB在处理时序数据存储、读写方面表现的如此优秀。

TSM引擎核心基石-时间线

InfluxDB在时序数据模型设计方面提出了一个非常重要的概念:SeriesKey。SeriesKey实际上就是measurement+datasource(tags)。时序数据写入内存之后按照SeriesKey进行组织:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dYem47q8-1597660672522)(http://note.youdao.com/yws/res/11340/WEBRESOURCEb4328c94ee9b8355544b15cb8e6c4bfc)]

举个简单的例子,SeriesKey可以认为是智能手环,智能手环可以有多个采集组件,比如说心跳采集器、脉搏采集器等,每个采集器好比上图中field1、field2。心跳采集器可以不间断的采集用户的心跳信息,心跳信息就是紫色方框表示的时序数据序列。当然,智能手环非常之多,使用SeriesKey要唯一表示某个智能手环,就必须使用标签唯一刻画出该智能手环,所以SeriesKey设计为measurement+tags,其中measurement表示智能手环(类似于通常意义上的表),tags用多组维度来唯一表示该智能手环,比如用智能手环用户+智能手环型号两个标签来表示。

TSM引擎工作原理-时序数据写入

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

  1. 时间序列数据进入系统之后首先根据measurement + tags拼成seriesKey
  2. 根据这个seriesKey以及待查fieldKey拼成Key,再在Map中根据Key找到对应的时间序列集合,如果没有的话就新建一个新的List
  3. 找到之后将Timestamp|Value组合值追加写入时间线数据链表中

TSM文件结构

每隔一段时间,内存中的时序数据就会执行flush操作将数据写入到文件(称为TSM文件),整个文件的组织和HBase中HFile基本相同,对HFile文件比较了解的童鞋会很容易理解。相同点主要在于两个方面:

  1. 数据都是以Block为最小读取单元存储在文件中
  2. 文件数据块都有相应的类B+树索引,而且数据块和索引结构存储在同一个文件中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PROLHhBH-1597660672531)(http://note.youdao.com/yws/res/11351/WEBRESOURCE815cd4a0361f11c1eb37047992939ae5)]

TSM文件最核心的由Series Data Section以及Series Index Section两个部分组成,其中前者表示存储时序数据的Block,而后者存储文件级别B+树索引Block,用于在文件中快速查询时间序列数据块。

Series Data Block

上文说到时序数据在内存中表示为一个Map:<Key, List<Timestamp|Value>>, 其中Key = seriesKey + fieldKey。这个Map执行flush操作形成TSM文件。

Map中一个Key对应一系列时序数据,因此能想到的最简单的flush策略是将这一系列时序数据在内存中构建成一个Block并持久化到文件。然而,有可能一个Key对应的时序数据非常之多,导致一个Block非常之大,超过Block大小阈值,因此在实际实现中有可能会将同一个Key对应的时序数据构建成多个连续的Block。但是,在任何时候,同一个Block中只会存储同一种Key的数据

另一个需要关注的点在于,Map会按照Key顺序排列并执行flush,这是构建索引的需求。Series Data Block文件结构如下图所示:

在这里插入图片描述

Series Data Block由四部分构成:TypeLengthTimestamps以及Values,分别表示意义如下:

  • Type:表示Values中的数据类型,数值数据类型通常为int、long、float以及double等。不同的数据类型对应不同的编码方式。
  • Length:len(Timestamps),用于读取Timestamps区域数据,解析Block。
  • Timestamps:时间值存储在一起形成的数据集,通常来说,时间序列中时间值的间隔都是比较固定的,比如每隔一秒钟采集一次的时间值间隔都是1s,这种具有固定间隔值的时间序列压缩非常高效,TSM采用了Facebook开源的Geringei系统中对时序时间的压缩算法:delta-delta编码。
  • Values:指标值存储在一起形成的数据集,同一种Key对应的指标值数据类型都是相同的,由Type字段表征,相同类型的数据值可以很好的压缩,而且时序数据的特点决定了这些相邻时间序列的数据值基本都相差不大,因此也可以非常高效的压缩。需要注意的是,不同数据类型对应不同的编码算法。

时序数据的时间值以及指标值在一个Block内部是按照列式存储的:所有的时间值存储在一起,所有的指标值存储在一起。使用列式存储可以极大提高系统的压缩效率。

Series Index Block

很多时候用户需要根据Key查询某段时间(比如最近一小时)的时序数据,如果没有索引,就会需要将整个TSM文件加载到内存中才能一个Data Block一个Data Block查找,这样一方面非常占用内存,另一方面查询效率非常之低。为了在不占用太多内存的前提下提高查询效率,TSM文件引入了索引,其实TSM文件索引和HFile文件索引基本相同。TSM文件索引数据由一系列索引Block组成,每个索引Block的结构如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5twxXnYk-1597660672540)(http://note.youdao.com/yws/res/11367/WEBRESOURCE3879d2ca2f15e22d89403c050c6c58f8)]

Series Index BlockIndex Block Meta以及一系列Index Entry构成:

  • Index Block Meta:最核心的字段是Key,表示这个索引Block内所有IndexEntry所索引的时序数据块都是该Key对应的时序数据。
    • keyLengthKey的长度
    • Key:表示该Index Block索引的Data BlockKey
    • TypeData BlockType
    • countIndex Entry的数量
  • Index Entry:表示一个索引字段,指向对应的Series Data Block。指向的Data Block由Offset唯一确定,Offset表示该Data Block在文件中的偏移量,Size表示指向的Data Block大小。Min Time和Max Time表示指向的Data Block中时序数据集合的最小时间以及最大时间,用户在根据时间范围查找时可以根据这两个字段进行过滤。

TSM文件总体结构

上文我们分别就Series Data Block以及Series Index Block进行了微观的分析,回过头我们再从宏观的角度将整个TSM文件表示为下图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IikLvCYY-1597660672541)(http://note.youdao.com/yws/res/11375/WEBRESOURCEb64cc1b1668d6c928995cccdab0de1f9)]

TSM引擎工作原理-时序数据读取

基于对TSM文件的了解,在一个文件内部根据Key查找一个某个时间范围的时序数据就会变得很简单,整个过程如下图所示:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6LQ33Lgq-1597660672543)(http://note.youdao.com/yws/res/11379/WEBRESOURCE73c61c4d7b378a199e36ccbbc63da165)]

上图中中间部分为索引层,TSM在启动之后就会将TSM文件的索引部分加载到内存,数据部分因为太大并不会直接加载到内存。用户查询可以分为三步:

  1. 首先根据Key找到对应的Series Index Block,因为Key是有序的,所以可以使用二分查找来具体实现
  2. 找到Series Index Block之后再根据查找的时间范围,使用[MinTime, MaxTime]索引定位到可能的Series Data Block列表
  3. 将满足条件的Series Data Block加载到内存中解压进一步使用二分查找算法查找即可找到
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值