Tsm存储引擎

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014473112/article/details/82971285

参考:
http://hbasefly.com/2018/01/13/timeseries-database-4/
http://blog.fatedier.com/2016/08/05/detailed-in-influxdb-tsm-storage-engine-one/


influxdb使用的存储引擎是自己实现的TSM Tree算法,类似于LSM Tree,LSM Tree原理参见这篇文章http://blog.fatedier.com/2016/06/15/learn-lsm-tree/

influxdb继承了LSM Tree的顺序写入的特点,所以写入性能很好(在LSM结构中,特点就是在内存中先把大量的数据顺序写,然后持久化到磁盘,这样可以极大地提升数据写入性能,但是牺牲了部分读的性能(这里我的理解是,如果是顺序读取,比如key值连续的数据读取,性能还是高的,但是如果是随机读取,那么每次都要遍历sstable文件查找,这样就会很慢,所以这种特性适用于时序数据库,因为时序数据库每次读取数据都是读取固定series的指定时间范围的连续数据,所以读取相对来说比较快速)),但是对于读的性能,LSM Tree是比较弱势的,TSM Tree也做了自己的一些优化。

组件

TSM存储引擎主要由几个部分组成:cache、wal、tsm file、compactor
在这里插入图片描述

1、shard

具体的说,shard并不是一个实际存在的组件,它只是一个逻辑概念,正如上图看到的,一个shard,包含cache、WAL、TSM File、Compactor。influxdb中,不同的时间戳范围对应一个shard,这个时间戳的设置可以在rp里面设置(shard Group duration,也就是这个shard组的时间戳范围),设计shard的目的是为了通过时间快速定位要查询的数据资源,另外,在rp中设置数据过期时间(duration)可以设置数据过期时间,这样如果数据过期了,可以批量删除指定时间段的shard的数据,更加高效

2、cache

cache存在于内存中,相当于是LSM Tree中的memtable,是一个简单的map结构,key为seriesKey + 分隔符 + filedName,目前代码中的分隔符为#!~#,时序数据写入内存之后按照key组织如下,seriesKey + filedName作为key,List<Timestamp|value>作为value,形成一个map,按照具体结构如下:
在这里插入图片描述
每次写入数据时,数据同时写入数据到cache和wal中,当cache大小达到一定阈值(默认情况下是25MB),会将当前cache进行一次快照,清空当前cache,同时创建一个新的wal文件,删除之前的wal文件,快照中的数据会被写入到tsm文件中

可以看到,其实wal文件和cache内容都是一样的,wal的作用是在influxdb崩溃时cache数据丢失,可以从wal中恢复,每次influxdb启动时,cache都会被重新构造

cache存在于内存中,一是为了加快数据写入(内存写入比磁盘快),二是可以快速进行数据排序(内存排序时间快)

其实cache设计有一个问题,当快照文件被写入tsm文件的时候,当前cache由于写入数据量过大,又达到了阈值,又要创建一个快照,而前一个快照又没有完全写入tsm,InfluxDB 的做法是让后续的写入操作失败,用户需要自己处理,等待恢复后继续写入数据。

3、WAL

WAL文件作用上面也说了,这里就不赘述。wal单个文件达到一定大小后会进行分片,创建一个新的wal文件用于写入。
下面讲讲它的写入速度问题,由于数据是顺序写入wal文件中,所以写入性能其实是很高的,但是有一种情况:数据没有按照时间顺序排列,那么influxdb会把数据路由到不同的shard,这样就会影响到写入性能了
##4、tsm文件
tsm文件在data目录下,最大大小一般是2GB,具体结构件后面解析
##5、Compactor
Compactor组件运行在后台,主要是对tsm文件进行操作,包括两方面:一个是当cache文件达到阈值,进行快照,把快照写入tsm文件;另一方面就是对tsm文件进行合并,减少文件数量,它会每隔1秒检查是否又可以压缩合并的数据

目录和文件结构

目录结构:
influxdb数据目录一般在/var/lib/influxdb下面,在这个目录下有三个目录:wal、data、meta,meta用于存储数据库的元数据,在这个目录下只有一个meta.db文件。wal和data目录下面针对的是每一个数据库有一个目录,接下来就是rp目录,然后就是shard id目录了:
在这里插入图片描述

Wal文件

wal 文件中的一条数据,对应的是一个 key(measument + tags + fieldName) 下的所有 value 数据,按照时间排序。文件每一条数据的数据结构如下:
在这里插入图片描述

  • Type (1 byte): 表示这个条目中 value 的类型。
  • Key Len (2 bytes): 指定下面一个字段 key 的长度。
  • Key (N bytes): 这里的 key 为 measument + tags + fieldName。
  • Count (4 bytes): 后面紧跟着的是同一个 key 下数据的个数。
  • Time (8 bytes): 单个 value 的时间戳。
  • Value (N bytes): value 的具体内容,其中 float64, int64, boolean 都是固定的字节数存储比较简单,通过 Type 字段知道这里 value 的字节数。string 类型比较特殊,对于 string 来说,N bytes 的 Value 部分,前面 4 字节用于存储 string 的长度,剩下的部分才是 string 的实际内容。

TSM文件

一个tsm文件的主要结构如下:
在这里插入图片描述
在这里插入图片描述
主要分为四个部分:header、blocks、index、footer,下面具体介绍每一个结构

(1) header
在这里插入图片描述

  • MagicNumber(4 bytes):用于区分是哪一个存储引擎,目前使用的是tsm1引擎 MagicNumber为0x16D116D1
  • Version(1 byte):目前是tsm1引擎,此值固定为1

(2)Blocks
在这里插入图片描述
block是influxDb的最小操作对象,每一个block只会存储同一种key的数据,当然同一种key的数据可能分布到连续几个block里面。每一个Block分为CRC32和Data两部分,CRC32用于校验data内容是否有问题,data的结构如下:
在这里插入图片描述

  • type表示该seriesKey对应的时间序列的数据类型,数值数据类型通常为int、long、float以及double等,不同的数据类型对应不同的编码方式
  • length:表示timestamps或者values的个数(时序数据的时间值以及指标值在一个block内部是按照列式存储的:所有的时间值存储在一起,所有的指标值存储在一起。使用列式存储可以极大提高系统的压缩效率
  • Timestamps:时间值存储在一起形成的数据集,通常来说,时间序列中时间值的间隔都是比较固定的,比如每隔一秒钟采集一次的时间值间隔都是1s,这种具有固定间隔值的时间序列压缩非常高效,TSM采用了Facebook开源的Geringei系统中对时序时间的压缩算法:delta-delta编码。
  • Values:指标值存储在一起形成的数据集,同一种Key对应的指标值数据类型都是相同的,由Type字段表征,相同类型的数据值可以很好的压缩,而且时序数据的特点决定了这些相邻时间序列的数据值基本都相差不大,因此也可以非常高效的压缩。需要注意的是,不同数据类型对应不同的编码算法。

(3)Index
Index里面存放的是Blocks中Data的索引,其结构如下:
在这里插入图片描述
IndexEntry表示
每一个索引条目对应的是一个key下所有block的索引,因为一个key对应的数据可能分布在不同的block,所以一个index条目中可能有多个IndexEntry

(4)footer
在这里插入图片描述
tsm file 的最后8字节的内容存放了 Index 部分的起始位置在 tsm file 中的偏移量,方便将索引信息加载到内存中。

(4)间接索引
间接索引不是当前文件下的结构,它是存在于内存中为了快速定位到key在Index中的位置创建的,它是一个数,存储的值为每一个key在Index表中的位置,当指定一个要查询的key时,可以通过二分查找,定位到当前key在Index表中的位置,再根据要查询的数据的时间进行定位,就可以找到对应的block(其实这里具体是怎么查的不是很清楚,首先在offsets数组里面存的到底是什么,key如何在这个数组里面进行二分查找,我不是很懂

另外还有一个疑问:
在内存中,数据先是以block形式存在,那么如果刚开始一次性同时写入不同的series的数据,内存一下子要维护多个block,会不会造成内存超标

猜你喜欢

转载自blog.csdn.net/u014473112/article/details/82971285
TSM