下面介绍了InfluxDB对于时序数据的存储/索引的设计。由于InfluxDB的集群版已在0.12版就不再开源,因此如无特殊说明,所介绍对象都是指 InfluxDB 单机版
尽管InfluxDB自发布以来历时三年多,其存储引擎的技术架构已经做过几次重大的改动, 以下将简要介绍一下InfluxDB的存储引擎演进的过程。
版本0.9.0之前
**基于LevelDB的LSMTree方案**
版本0.9.0~0.9.4
**基于BoltDB的mmapCOWB+tree方案**
版本0.9.5~1.2
**基于自研的WAL+TSMFile方案**(TSMFile方案是0.9.6版本正式启用,0.9.5只是提供了原型)
版本1.3~至今
**基于自研的WAL+TSMFile+TSIFile方案**
InfluxDB的存储引擎先后尝试过包括LevelDB, BoltDB在内的多种方案。但是对于InfluxDB的下述诉求终不能完美地支持:
时序数据在降采样后会存在大批量的数据删除
=>*LevelDB的LSMTree删除代价过高*
单机环境存放大量数据时不能占用过多文件句柄
=>*LevelDB会随着时间增长产生大量小文件*
数据存储需要热备份
=>*LevelDB只能冷备*
大数据场景下写吞吐量要跟得上
=>*BoltDB的B+tree写操作吞吐量成瓶颈*
存储需具备良好的压缩性能
=>*BoltDB不支持压缩*
此外,出于技术栈的一致性以及部署的简易性考虑(面向容器部署),InfluxDB团队希望存储引擎 与 其上层的TSDB引擎一样都是用GO编写,因此潜在的RocksDB选项被排除
基于上述痛点,InfluxDB团队决定自己做一个存储引擎的实现。
在解析InfluxDB的存储引擎之前,先回顾一下InfluxDB中的数据模型。
在InfluxDB中,时序数据支持多值模型,它的一条典型的时间点数据如下所示:
图 1
measurement:
指标对象,也即一个数据源对象。每个measurement可以拥有一个或多个指标值,也即下文所述的**field**。在实际运用中,可以把一个现实中被检测的对象(如:“cpu”)定义为一个measurement
tags:
概念等同于大多数时序数据库中的tags,通常通过tags可以唯一标示数据源。每个tag的key和value必须都是字符串。
field:
数据源记录的具体指标值。每一种指标被称作一个“field”,指标值就是“field”对应的“value”
数据的时间戳。在InfluxDB中,理论上时间戳可以精确到**纳秒**(ns)级别
此外,在InfluxDB中,measurement的概念之上还有一个对标传统DBMS的 Database 的概念,逻辑上每个Database下面可以有多个measurement。在单机版的InfluxDB实现中,每个Database实际对应了一个文件系统的 目录。
InfluxDB中的SeriesKey的概念就是通常在时序数据库领域被称为 时间线 的概念, 一个SeriesKey在内存中的表示即为下述字符串(逗号和空格被转义)的 字节数组(github.com/influxdata/influxdb/model#MakeKey())
<blockquote>{measurement名}{tagK1}={tagV1},{tagK2}={tagV2},...
其中,SeriesKey的长度不能超过 65535 字节
InfluxDB的Field值支持以下数据类型:
Datatype | Size in Mem | Value Range |
---|---|---|
Float | 8 bytes | 1.797693134862315708145274237317043567981e+308 ~ 4.940656458412465441765687928682213723651e-324 |
Integer | 8 bytes | -9223372036854775808 ~ 9223372036854775807 |
String | 0~64KB | String with length less than 64KB |
Boolean | 1 byte | true 或 false |
在InfluxDB中,Field的数据类型在以下范围内必须保持不变,否则写数据时会报错 类型冲突。
同一Serieskey + 同一field + 同一shard
在InfluxDB中, 能且只能 对一个Database指定一个 retention Policy (简称:RP)。通过RP可以对指定的Database中保存的时序数据的留存时间(duration)进行设置。而 Shard 的概念就是由duration衍生而来。一旦一个Database的duration确定后, 那么在该Database的时序数据将会在这个duration范围内进一步按时间进行分片从而时数据分成以一个一个的shard为单位进行保存。
shard分片的时间 与 duration之间的关系如下
Duration of RP | Shard Duration |
---|---|
< 2 Hours | 1 Hour |
>= 2 Hours 且 <= 6 Months | 1 Day |
> 6 Months | 7 Days |
新建的Database在未显式指定RC的情况下,默认的RC为 数据的Duration为永久,Shard分片时间为7天
注: 在闭源的集群版Influxdb中,用户可以通过RC规则指定数据在基于时间分片的基础上再按SeriesKey为单位进行进一步分片
时序数据库的存储引擎主要需满足以下三个主要场景的性能需求
大批量的时序数据写入的高性能
直接根据时间线(即Influxdb中的 Serieskey )在指定时间戳范围内扫描数据的高性能
间接通过measurement和部分tag查询指定时间戳范围内所有满足条件的时序数据的高性能
InfluxDB在结合了1.2所述考量的基础上推出了他们的解决方案,即下面要介绍的 WAL + TSMFile + TSIFile的方案
InfluxDB写入时序数据时为了确保数据完整性和可用性,与大部分数据库产品一样,都是会先写WAL,再写入缓存,最后刷盘。对于InfluxDB而言,写入时序数据的主要流程如同下图所示:
图 2
由于InfluxDB对于时序数据的写操作永远只有单纯写入,因此它的Entry不需要区分操作种类,直接记录写入的数据即可
图 4
其特点是在一个TSMFile中将 时序数据(i.e Timestamp + Field value)保存在数据区;将Serieskey 和 Field Name的信息保存在索引区,通过一个基于 Serieskey + Fieldkey构建的形似B+tree的文件内索引快速定位时序数据所在的 数据块
注: 在当前版本中,单个TSMFile的最大长度为2GB,超过时即使是同一个Shard,也会继续新开一个TSMFile保存数据。本文的介绍出于简单化考虑,以下内容不考虑同一个Shard的TSMFile分裂的场景
索引块的构成
上文的索引块的构成,如下所示:*图6*
其中**索引条目**在InfluxDB的源码中被称为`directIndex`。在TSMFile中,索引块是按照Serieskey+Fieldkey**排序**后组织在一起的。明白了TSMFile的索引区的构成,就可以很自然地理解InfluxDB如何高性能地在TSMFile扫描时序数据了:1.根据用户指定的时间线(Serieskey)以及Field名在**索引区**利用二分查找找到指定的Serieskey+FieldKey所处的**索引数据块**2.根据用户指定的时间戳范围在**索引数据块**中查找数据落在哪个(*或哪几个*)**索引条目**3.将找到的**索引条目**对应的**时序数据块**加载到内存中进行进一步的Scan*注:上述的1,2,3只是简单化地介绍了查询机制,实际的实现中还有类似扫描的时间范围跨索引块等一系列复杂场景*<br>
时序数据的存储
在图 2中介绍了时序数据块的结构:即同一个 Serieskey + Fieldkey 的 所有时间戳 - Field值
对被拆分开,分成两个区:Timestamps区和Value区分别进行存储。它的目的是:实际存储时可以分别对时间戳和Field值按不同的压缩算法进行存储以减少时序数据块的大小
采用的压缩算法如下所示:
做查询时,当利用TSMFile的索引找到文件中的时序数据块时,将数据块载入内存并对Timestamp以及Field Value进行解压缩后以便继续后续的查询操作。
Float类: Gorrila's Float Commpression
Integer类型: Delta Encoding + Zigzag Conversion + RLE / Simple8b / None
String类型: Snappy Compression
Boolean类型: Bit packing
Timestamp: Delta-of-delta encoding
Field Value:由于单个数据块的Field Value必然数据类型相同,因此可以集中按数据类型采用不同的压缩算法
有了TSMFile,第3章开头所说的三个主要场景中的场景1和场景2都可以得到很好的解决。但是如果查询时用户并没有按预期按照Serieskey来指定查询条件,而是指定了更加复杂的条件,该如何确保它的查询性能?通常情况下,这个问题的解决方案是依赖倒排索引(Inverted Index)。
InfluxDB的倒排索引依赖于下述两个数据结构
map<SeriesID, SeriesKey>
map<tagkey, map<tagvalue, List<SeriesID>>>
它们在内存中展现如下:
图 7
图 8
但是在实际生产环境中,由于用户的时间线规模会变得很大,因此会造成倒排索引使用的内存过多,所以后来InfluxDB又引入了 TSIFile
TSIFile的整体存储机制与TSMFile相似,也是以 Shard 为单位生成一个TSIFile。
以上就是如何进行时序数据库InfluxDB的存储机制解析,小编相信有部分知识点可能是我们日常工作会见到或用到的。希望你能通过这篇文章学到更多知识。更多详情敬请关注本站行业资讯频道。
本文由 贵州做网站公司 整理发布,部分图文来源于网络,如有侵权,请联系我们删除,谢谢!
抖音(Tiktok)是由北京字节跳动科技有限公司(ByteDance)孵化的音乐创意短视频社交网站。它于2016年9月20日上线,主要面向全年龄段的用户,尤其是...
飞极速为您提供高清在线电影、电视剧大全、动画片,综艺等,飞极速在线更新及时,播放速度快,给您带来最好的观影体验!飞极速在线,免费提供日本新番动漫、最新电影和最新...
《南华早报》(英语:South China Morning Post, SCMP)和星期日出版的《星期日南华早报》(英语:Sunday Morning Post...
征信报告次级抵押贷款也做不了吗?若准备在招行申请个人贷款,“征信记录” 会作为审核的重要选项之一。最终审核是.否能够通过,是结合您申请的业务品种、个人偿付能力、信用状况等因素进行综合评定的,需要经办网点审批后才能确定。建议您提供相关申请材料,联系当地网点的个贷部门进一步核实。征信次级是不是永远不能贷款?一般来说,银行会根据借款人的还款能力,将贷款划分为正常、关注、次级、可疑...
央行100亿逆回购意味着市场资金比较充足,货币政策仍处于一个维稳状态。央行逆回购其实就是向市场投放一定的资金,从而保持市场的活跃性,资金流通平稳。央行逆回购是国家实行较宽松的货币政策,不断的增加货币供应量,使其流入市场。央行逆回购是什么央行逆回购指的是中国人民银行向一级交易商买入有价证券,双方再约定好在将来特定日期把这些有价证券再卖还给一级交易商的交易行为。通俗点来说,是央行把资金借给商业银行,商...
上海个人小额贷款办理流程是什么?个人小额贷款,只要符合要求,处理起来是非常快的。如果感兴趣,可以了解一下民间小额贷款。办理银行小额贷款的流程主要包括以下步骤:1.在提供小额贷款的银行网点申请贷款时,借款人必须携带相关资料,如果是商户,还必须携带营业执照。2.在收到贷款人的申请后,银行进行调查。主要检查个人信用状况和收入。3.经过银行的调查和批准,与银行签订了一份贷款合同。4.银行贷款,贷方成功获得...