InfluxDB 的存储机制解析
本文介绍了InfluxDB对于时序数据的存储/索引的设计。由于InfluxDB的集群版已在0.12版就不再开源,因此如无特殊说明,本文的介绍对象都是指 InfluxDB 单机版

  1. InfluxDB 的存储引擎演进

尽管InfluxDB自发布以来历时三年多,其存储引擎的技术架构已经做过几次重大的改动, 以下将简要介绍一下InfluxDB的存储引擎演进的过程。

1.1 演进简史
版本0.9.0之前

基于 LevelDB的LSMTree方案
版本0.9.0~0.9.4

基于BoltDB的mmap COW B+tree方案
版本0.9.5~1.2

基于自研的 WAL + TSMFile 方案(TSMFile方案是0.9.6版本正式启用,0.9.5只是提供了原型)
版本1.3~至今

基于自研的 WAL + TSMFile + TSIFile 方案
1.2 演进的考量
InfluxDB的存储引擎先后尝试过包括LevelDB, BoltDB在内的多种方案。但是对于InfluxDB的下述诉求终不能完美地支持:

时序数据在降采样后会存在大批量的数据删除

=> LevelDB的LSMTree删除代价过高
单机环境存放大量数据时不能占用过多文件句柄

=> LevelDB会随着时间增长产生大量小文件
数据存储需要热备份

=> LevelDB只能冷备
大数据场景下写吞吐量要跟得上

=> BoltDB的B+tree写操作吞吐量成瓶颈
存储需具备良好的压缩性能

=> BoltDB不支持压缩
此外,出于技术栈的一致性以及部署的简易性考虑(面向容器部署),InfluxDB团队希望存储引擎 与 其上层的TSDB引擎一样都是用GO编写,因此潜在的RocksDB选项被排除

基于上述痛点,InfluxDB团队决定自己做一个存储引擎的实现。

2 InfluxDB的数据模型
在解析InfluxDB的存储引擎之前,先回顾一下InfluxDB中的数据模型。

在InfluxDB中,时序数据支持多值模型,它的一条典型的时间点数据如下所示:

图 1

measurement:

指标对象,也即一个数据源对象。每个measurement可以拥有一个或多个指标值,也即下文所述的field。在实际运用中,可以把一个现实中被检测的对象(如:“cpu”)定义为一个measurement
tags:

概念等同于大多数时序数据库中的tags, 通常通过tags可以唯一标示数据源。每个tag的key和value必须都是字符串。
field:

数据源记录的具体指标值。每一种指标被称作一个“field”,指标值就是 “field”对应的“value”
timestamp:

数据的时间戳。在InfluxDB中,理论上时间戳可以精确到 纳秒(ns)级别
此外,在InfluxDB中,measurement的概念之上还有一个对标传统DBMS的 Database 的概念,逻辑上每个Database下面可以有多个measurement。在单机版的InfluxDB实现中,每个Database实际对应了一个文件系统的 目录。

2.1 Serieskey的概念
InfluxDB中的SeriesKey的概念就是通常在时序数据库领域被称为 时间线 的概念, 一个SeriesKey在内存中的表示即为下述字符串(逗号和空格被转义)的 字节数组(github.com/influxdata/influxdb/model#MakeKey())

{measurement名}{tagK1}={tagV1},{tagK2}={tagV2},...

其中,SeriesKey的长度不能超过 65535 字节

2.2 支持的Field类型
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

2.3 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为单位进行进一步分片

  1. InfluxDB的存储引擎分析

时序数据库的存储引擎主要需满足以下三个主要场景的性能需求

大批量的时序数据写入的高性能
直接根据时间线(即Influxdb中的 Serieskey )在指定时间戳范围内扫描数据的高性能
间接通过measurement和部分tag查询指定时间戳范围内所有满足条件的时序数据的高性能
InfluxDB在结合了1.2所述考量的基础上推出了他们的解决方案,即下面要介绍的 WAL + TSMFile + TSIFile的方案

3.1 WAL解析
InfluxDB写入时序数据时为了确保数据完整性和可用性,与大部分数据库产品一样,都是会先写WAL,再写入缓存,最后刷盘。对于InfluxDB而言,写入时序数据的主要流程如同下图所示:

图 2

InfluxDB对于时间线数据和时序数据本身分开,分别写入不同的WAL中,其结构如下所示:

索引数据的WAL
由于InfluxDB支持对Measurement,TagKey,TagValue的删除操作,当然随着时序数据的不断写入,自然也包括 增加新的时间线,因此索引数据的WAL会区分当前所做的操作具体是什么,它的WAL的结构如下图所示

图 3

时序数据的WAL
由于InfluxDB对于时序数据的写操作永远只有单纯写入,因此它的Entry不需要区分操作种类,直接记录写入的数据即可

图 4

3.2 TSMFile解析
TSMFile是InfluxDB对于时序数据的存储方案。在文件系统层面,每一个TSMFile对应了一个 Shard。

TSMFile的存储结构如下图所示:

图 5

其特点是在一个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只是简单化地介绍了查询机制,实际的实现中还有类似扫描的时间范围跨索引块等一系列复杂场景

时序数据的存储

在图 2中介绍了时序数据块的结构:即同一个 Serieskey + Fieldkey 的 所有时间戳 - Field值对被拆分开,分成两个区:Timestamps区和Value区分别进行存储。它的目的是:实际存储时可以分别对时间戳和Field值按不同的压缩算法进行存储以减少时序数据块的大小

采用的压缩算法如下所示:

Timestamp: Delta-of-delta encoding
Field Value:由于单个数据块的Field Value必然数据类型相同,因此可以集中按数据类型采用不同的压缩算法

Float类: Gorrila's Float Commpression
Integer类型: Delta Encoding + Zigzag Conversion + RLE / Simple8b / None
String类型: Snappy Compression
Boolean类型: Bit packing
做查询时,当利用TSMFile的索引找到文件中的时序数据块时,将数据块载入内存并对Timestamp以及Field Value进行解压缩后以便继续后续的查询操作。

3.3 TSIFile解析
有了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。具体的存储格式就在此不赘述了。

  1. 总结

以上就是对InfluxDB的存储机制的粗浅解析,由于目前所见的只有单机版的InfluxDB,所以尚不知道集群版的InfluxDB在存储方面有哪些不同。但是,即便是这单机版的存储机制,也对我们设计时序数据库有着重要的参考意义。

时序数据库连载系列: 时序数据库一哥InfluxDB之存储机制解析相关推荐

  1. 时序数据库连载系列: 时序数据库一哥InfluxDB之存储机制解析 1

    2019独角兽企业重金招聘Python工程师标准>>> InfluxDB 的存储机制解析 本文介绍了InfluxDB对于时序数据的存储/索引的设计.由于InfluxDB的集群版已在0 ...

  2. 时序数据库连载系列:指标届的独角兽Prometheus

    简介 Prometheus是SoundCloud公司开发的一站式监控告警平台,依赖少,功能齐全. 于2016年加入CNCF,广泛用于 Kubernetes集群的监控系统中,2018.8月成为继K8S之 ...

  3. 数据库改名系列(数据库名,逻辑名,物理文件名)

    汇总篇:http://www.cnblogs.com/dunitian/p/4822808.html#tsql 某系统设计的不是很合理,库很多,图形化操作分离都得搞半天,各种改名也就更浪费时间了,于是 ...

  4. 临床公共数据库挖掘系列1---seer数据库注册

    对于很多没有临床数据和不会做实验的小伙伴,使用国际公共数据库进行发表论文也是一个很好的选择,简单来说就是用别人的数据来发表自己的论文.seer数据库是美国的癌症数据库,最初是用于社会保险,今年来在医学 ...

  5. 回滚机制_【巨杉数据库SequoiaDB】巨杉 Tech | 并发性与锁机制解析与实践

    01 概述 数据库是一个多用户使用的共享资源.当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况.若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性.加锁 ...

  6. 【巨杉数据库SequoiaDB】巨杉 Tech | 并发性与锁机制解析与实践

    01 概述 数据库是一个多用户使用的共享资源.当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况.若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性.加锁 ...

  7. InfluxDB 开源分布式时序、事件和指标数据库

    from:https://segmentfault.com/a/1190000000444617 InfluxDB 开源分布式时序.事件和指标数据库 InfluxDB 是一个开源分布式时序.事件和指标 ...

  8. 时序数据库技术体系 – InfluxDB TSM存储引擎之数据写入

    之前两篇文章笔者分别从TSM File文件存储格式.倒排索引文件存储格式这两个方面对InfluxDB最基础.最底层也最核心的存储模块进行了介绍,接下来笔者会再用两篇文章在存储文件的基础上分别介绍Inf ...

  9. 时序数据库技术体系 – InfluxDB TSM存储引擎之数据读取

    任何一个数据库系统内核关注的重点无非:数据在内存中如何存储.在文件中如何存储.索引结构如何存储.数据写入流程以及数据读取流程.关于InfluxDB存储内核,笔者在之前的文章中已经比较全面的介绍了数据的 ...

最新文章

  1. 配置IIS服务器提供APP文件下载
  2. wkwebview html5页面,iOS使用WKWebView加载HTML5不显示屏幕宽度的问题解决
  3. POJ1226 Substrings(二分+后缀数组)
  4. 如何使用命令行拿到SAP Kyma的Lambda Function明细
  5. Axure实现多用户注册验证
  6. Qt4_写TCP客户/服务器应用程序
  7. python必背入门代码-Python零基础入门学习笔记(一)
  8. 车间调度建模系列1|复杂车间调度问题特点
  9. FRM-92120: Registry.dat
  10. cad打开a3样板图形_cad a3图框下载-cada3标准图框模板 dwg版 - 河东下载站
  11. 微信小程序Scope参数错误或没有Scope权限的处理方法
  12. Python 安装pyqt—tools失败,记录
  13. 关于C语言中“x++”和“++x”的问题
  14. linux连接到sqlserver命令行,Linux 下连接sqlserver (上)
  15. 网易免费企业邮箱Foxmail设置方法
  16. 58同城python_Python实战计划爬虫作业第一周作业:爬58同城
  17. 2021-05-31 - Laravel - 搭建开发环境 - 学习/实践
  18. 大势所趋,RIA已成为主流应用程序!
  19. 小程序时间轴和地区列表的实现,js+css实现时间轴效果
  20. Android 多国语言转换 Excel 和 Excel 转换为 string

热门文章

  1. Mybatis原理分析一 从JDBC到Mybaits
  2. Firefox 50优化Electrolysis
  3. Linux虚拟机创建后如何进行登录(Windows Azure)
  4. 烂泥:php5.6源码安装及php-fpm配置与nginx集成
  5. BackTack4 指南
  6. showModalDialog和showModelessDialog使用心得
  7. 用中值排序基数法实现树状结构 (转)
  8. 嵌入式Linux内存压力测试
  9. vmware无法打开ubuntu解决办法
  10. 你还在这样学习Python吗?真的不可以