百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT技术 > 正文

27.2k star,开源时序数据库里全球排名第一,InfluxDB何以做到?

wptr33 2025-05-21 16:55 16 浏览

一 什么是时序数据库

时序数据库,全称时间序列数据库(Time Series Database,TSDB),用于存储大量基于时间的数据,时序数据(Time Series Data)指的是一系列基于时间的数据,例如 CPU 利用率,北京的房价变化趋势,某一地区的温度变化等。

时序数据库支持时序数据的快速写入、持久化,多维度查询、聚合等操作,同时可以记录所有的历史数据,查询时将时间作为数据的过滤条件。

二 初识InfluxDB

InfluxDB 是时序数据库中应用比较广泛的一种,在 DB-Engines TSDB rank 中位居首位,可见 InfluxDB 在互联网的受欢迎程度是非常高的。

三 InfluxDB 的存储引擎演进

  • 版本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 方案**

InfluxDB的存储引擎先后尝试过包括LevelDB, BoltDB在内的多种方案。但是对于InfluxDB的下述诉求终不能完美地支持:

  • 时序数据在降采样后会存在大批量的数据删除 => *LevelDB的LSMTree删除代价过高*
  • 单机环境存放大量数据时不能占用过多文件句柄 => *LevelDB会随着时间增长产生大量小文件*
  • 数据存储需要热备份 => *LevelDB只能冷备*
  • 大数据场景下写吞吐量要跟得上 => *BoltDB的B+tree写操作吞吐量成瓶颈*
  • 存储需具备良好的压缩性能 => *BoltDB不支持压缩*

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

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

四 InfluxDB的使用场景

时序数据的使用场景广泛,包括 DevOps 监控,应用程序指标,IoT 传感器数据,实时动态数据分析等场景。

InfluxDB是一种时序数据库,时序数据库常用于监控场景,比如运维和IOT(物联网)领域,此类数据库旨在存储时序数据和实时计算。

如:将服务器上的CPU的使用情况每隔5秒向InfluxDB中写入一条数据,在图形界面中写一个查询过去每10分钟CPU的平均使用情况,再将该查询开发一个定时任务,每10秒钟执行一次并配置一条规则:查询执行结果 > xxx,就立即触发告警。

上述就是一个监控指标的场景,在IOT领域中也有大量的指标需要监控,比如:机械设备的传感器频率、农田湿度温度等等。

时序数据库相对关系型数据库而言,时序数据库专注的是写入性能,时序数据库不关心事务、不关注更新操作(只写不改)。通常指标数据都是关心最近某段时间的数据,之后的数据基本不会再用。时序数据库的设计特点是冷热差别明显,对最近的数据时序数据库会优先加载到内存中。

五 InfluxDB的组件

时序数据库一般用于在监控场景,大体上,数据的应用可以分四部分:数据采集、存储、查询&聚合及告警

对应InfluxDB 1.x开始也推出了TICK生态全套的解决方案:

  • T:Telegraf 数据采集组件
  • I:InfluxDB 数据存储组件
  • C:Chronograf 用户UI数据管理功能
  • K:Kapacitor 后台处理报警信息

在InfluxDB 2.x后已经把C、K合并到了I中了,这是两个版本在生态上的差别,在2.x上易用性也随之提高了一个等级:我们只需要安装InfluxDB就得到一个管理UI界面并且附带了定时任务和告警功能。

T是一个单独的插件,专注于收集各种外部中间件的数据写入到InfluxDB中,这个需要单独研究该插件的使用。

安装下载地址:
https://portal.influxdata.com/downloads/

下面是在web界面中新增Telegraf的配置文件,它已经给支持了非常多的中间件产品,就按照它的示例去给Telegraf机器上设置环境变量和启动即可使用。

时序数据库与我们熟悉的关系型数据库有所不同,首先需要了解一下 InfluxDB 中字段的含义,如下图所示:

六 InfluxDB的特点

● 数据写入:
①.高并发高吞吐,可持续的数据写入。
②.写多读少,时序数据 95% 以上都是写操作,例如在监控系统数据的时候,监控数据特别多,但是通常只会关注几个关键指标。
③.数据实时写入,不支持数据更新,但是可以人为更新修改。

● 数据分析与查询:
①.数据查询是按照时间段读取,例如 1 小时,1 分钟,给出具体时间范围。
②.最近的数据读取率高,越旧的数据读取率越低。
③.多种精度查询和多种维度分析。

● 数据存储:
①.存储数据规模大的数据,监控数据的数据大多数情况下都是 TB 或者 PB 级。
②.数据存放具有时效性,InfluxDB 提供了保存策略,可以认为是数据的保质期,超过周期范围,就可以认为数据失效,需要回收。节约存储成本,清理低价值的数据。

七 InfluxDB数据结构

Telegraf的内部数据结构叫做InfluxDB行协议。如下图所示:

Telegraf本身是InfluxData公司专门为InfluxDB开发的数据采集器。上面这种数据格式是InfluxDB数据库使用的,只要数据符合上面这种格式,就能通过InfluxDB的API将数据导入数据库。所以,自家的插件当然支持自家的生态了,InfluxDB。

与 CSV 相似,在 InfluxDB 行协议中,一条数据和另一条数据之间使用换行符分隔, 所以一行就是一条数据。另外,在时序数据库领域,一行数据一行数据由下面 4 种元素构成。

  • measurement(测量名称)
  • Tag Set(标签集)
  • Field Set(字段集)
  • Timestamp(时间戳)

协议中的数据类型及其格式

  • Float(浮点数):IEEE-754标准的64位浮点数。这是默认的数据类型。
  • Integer(整数):有符号64位整数。需要在数字的尾部加上一个小写数字 i 。
  • UInteger(无符号整数):无符号64位整数。需要在数字的尾部加上一个小写数字 u 。
  • String(字符串):普通文本字符串,长度不能超过64KB
  • Boolean(布尔值):true或者false
  • Unix Timestamp(Unix 时间戳):myMeasurementName fieldKey="fieldValue"1556813561098000000
  • 注释:以井号 # 开头的一行会被当做注释。

基本数据结构

points的数据结构介绍

八 InfluxDB存储原理

InfluxDB 的存储结构树是时间结构合并树(Time-Structured Merge Tree,TSM),它是由日志结构化合并树(Log-Structured Merge Tree,LSM),根据实际需求变化而来的。
①.LSM 树
LSM 树包含三部分:Memtable,Immutable 和 SSTable。MemTable 是内存中的数据结构,用于保存最近产生的数据,并按照 Key 有序地组织数据。内存并不是可靠存储,若断电就会丢失数据,因此通常会使用预写式日志 (Write-ahead logging,WAL) 的方式来保证数据的可靠性。

②.TSM 存储引擎
TSM 存储引擎主要包括四部分:Cache,WAL,TSM File,Compactor。下图中 shard 与 TSM 引擎主要部分放在一起,但其实 shard 在是 TSM 存储引擎之上的一个概念。在 InfluxDB 中按照数据产生的时间范围,会创建不同的 shard 分组,每个 shard 都有本身的 cache、wal、tsm file 以及 compactor。

InfluxDB文件目录结构

九 InfluxDB的写入

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

InfluxDB提供了多种接口协议供外部应用写入,比如可以使用collected采集数据上传,可以使用opentsdb作为输入,也可以使用http协议以及udp协议批量写入数据。批量数据进入到InfluxDB之后总体会经过三个步骤的处理,如下图所示:

  1. 批量时序数据shard路由:InfluxDB首先会将这些数据根据shard的不同分成不同的分组,每个分组的时序数据会发送到对应的shard。每个shard相当于HBase中region的概念,是InfluxDB中处理用户读写请求的单机引擎。
  2. 倒排索引引擎构建倒排索引:InfluxDB中shard由两个LSM引擎构成 – 倒排索引引擎和TSM引擎。时序数据首先会经过倒排索引引擎构建倒排索引,倒排索引用来实现InfluxDB的多维查询。
  3. TSM引擎持久化时序数据:倒排索引构建成功之后时序数据会进入TSM Engine处理。TMS Engine处理流程和通用LSM Engine基本一样,先将写入请求追加写入WAL日志,再写入cache,一旦满足特定条件会将cache中的时序数据执行flush操作落盘形成TSM File。

十 InfluxDB的读取

InfluxDB支持类SQL查询,称为InfluxQL。InfluxQL支持基本的DDL操作和DML操作语句,详见InfluxQL_Spec,比如Select语句:

select_stmt = "SELECT" fields from_clause [ into_clause ] [ where_clause ]               
[ group_by_clause ] [ order_by_clause ] [ limit_clause ]              
[ offset_clause ] [ slimit_clause ] [ soffset_clause ] .

读取流程大体如下:

整个读取流程从宏观上分为四个部分:

1. Query:InfluxQL允许用户使用类SQL语句执行查询分析聚合,InfluxQL语法详见:
https://docs.influxdata.com/influxdb/v1.0/query_language/spec/

2. QueryParser:InfluxQL进入系统之后,系统首先会对InfluxQL执行切词并解析为抽象语法树(AST),抽象树中标示出了数据源、查询条件、查询列以及聚合函数等等,分别对应上图中Source、Condition以及Aggration。

3. BuildIterators:InfluxQL语句转换为Query实体对象之后,就进入读取流程中最重要最核心的一个环节 – 构建Iterator体系。构建Iterator体系是一个非常复杂的逻辑过程,其中细节非常繁复,笔者尽可能化繁为简,将其中的主线抽出来。为了方便理解,笔者将Iterator体系分为三个子体系:顶层Iterator子体系、中间层Iterator子体系以及底层Iterator子体系。

4. Emitter.Emit:Iterator体系构建完成之后就完成了查询聚合前的准备工作,接下来就开始干活了。干活逻辑简单来讲是遍历所有FieldIterator,对每个FieldIterator执行一次Next函数,就会返回每个查询列的结果值,组装到一起就是一行数据。FieldIterator执行Next()函数会传递到最底层的TagsetIterator,TagsetIterator执行Next函数实际返回真实的时序数据。

TSDB存储引擎(实际上就是一个Shard)根据用户的查询请求执行原始数据的查询就是上文中提到的底层Iterator子体系的构建。查询过程分为两个部分:倒排索引查询过滤以及TSM数据层查询,前者通过Query中的where条件结合倒排索引过滤掉不满足条件的SeriesKey;后者根据留下的SeriesKey以及where条件中时间段信息(TimeRange)在TSMFile中以及内存中查出最终满足条件的数值列。TSDB存储引擎会将查询到的所有满足条件的原始数值列返回给上层,上层根据聚合函数对原始数据进行聚合并将聚合结果返回给用户。整个过程如下图所示:

上图需要从底部向上浏览,整个流程可以整理为如下:

1. 根据where condition以及所有倒排索引文件查处所有满足条件的SeriesKey

2. 将满足条件的SeriesKey根据GroupBy维度列进行分组,不同分组后续的所有操作都可以独立并发执行,因此可以多线程处理

3. 针对某个分组的SeriesKey集合以及待查询列,根据指定查询时间段(TimeRange)在所有TSMFile中根据B+树索引构建查询iterator

4. 将满足条件的原始数据返回给上层进行聚合运算,并将聚合运算的结果返回给用户

实际执行的过程可能比较抽象,为了更好的理解,笔者在下半部分举了一个示例。没有理解上面的逻辑没关系,可以先看下面的示例,看完之后再看上面的理论逻辑相信会更加容易理解。

十一 InfluxDB的删除

一般LSM引擎处理删除通常都采用Tag标记的方式,即删除操作和写入操作流程基本一致,只是数据上会多一个Tag标记 – deleted,表示该值已经被deleted。这种处理方案可以最小化删除代价,但万物有得必有失,减小了写入代价必然会增加读取代价,Tag标签方案在读取的时候需要对标记有deleted的数值进行特殊处理,这个代价还是很大的。HBase中删除操作就是采用Tag标记方案。

InfluxDB比较奇葩,对于删除操作处理的比较异类,通常InfluxDB不会删除一条记录,而是会删除某段时间内或者某个维度下的所有记录,甚至一张表的所有记录,这和通常的数据库有所不同。比如:

DROP SERIES FROM h2o_feet WHERE location = ‘santa_monica'
DELETE FROM "cpu" DELETE FROM "cpu" WHERE time < '2000-01-01T00:00:00Z' DELETE WHERE time < '2000-01-01T00:00:00Z'

InfluxDB中一个shard有两个LSM引擎,一个是倒排索引引擎(存储维度列到SeriesKey的映射关系,方便多维查找),一个是TSM Engine,用来存储实际的时序数据。如果是删除一条记录,通常只需要TSM Engine执行删除就可以,倒排索引引擎是不需要执行删除的。而如果是Drop Measurement这样的操作,那么两个LSM引擎都需要执行相应的删除。问题是,这两个引擎的删除策略完全不同,TSM Engine采用了一种同步删除策略,Inverted Index Engine采用了标记删除策略。如下图所示:

1. TSM Engine同步删除策略,整个删除流程可以分为如下四步:

(1)删除所有TSM File中满足条件的series,系统会遍历当前shard中所有TSM File,检查该File中是否存在满足删除条件的File,如果有会执行如下两个操作:

  • TSM File Index相关处理:在内存中删除满足条件的Index Entry,通常删除会带有Time Range以及Key Range,而且TSM File Index会在引擎启动之后加载到内存。因此删除操作会将满足条件的Index Entry从内存中删除。
  • 生成tombstoner文件:tombstoner文件会记录当前TSM File中所有被删除的时序数据,时序数据用[key, min, max]三个字段表示,其中key即SeriesKey+FieldKey,[min, max]表示要删除的时间段。如下图所示:

(2)删除Cache中满足条件的series

(3)在WAL中生成一条删除series的记录并持久化到硬盘

2. Inverted Index Engine 标记Tag删除策略,标记Tag删除非常简单,和一次写入流程基本相同:

(1)在WAL中生成一条flag为deleted的LogEntry并持久化到硬盘

(2)将要删除的维度信息写入Cache,需要标记deleted(设置type=deleted)

(3)当WAL大小超过阈值之后标记为deleted的维度信息会随Cache Flush到倒排索引文件

(4)和HBase一样,Inverted Index Engine中索引信息真正被删除发生在compact阶段

十二 参考资料

[1] InfluxDB文件结构解析:
https://blog.csdn.net/u012794915/article/details/100061367

[2] InfluxDB入门操作:
https://blog.csdn.net/qq_44766883/article/details/131511821

[3] InfluxDB 的存储机制解析:
https://zhuanlan.zhihu.com/p/604131607

[4] InfluxDB TSM存储引擎之数据读取:
http://hbasefly.com/2018/05/02/timeseries-database-7/

[5] InfluxDB TSM存储引擎之数据写入:
http://hbasefly.com/2018/03/27/timeseries-database-6/

[6] InfluxDB源码:
https://github.com/influxdata/influxdb

[7] InfluxDB 2.x概述和数据存储原理:
https://www.caodegao.com/archives/influxdb2x-gai-shu-he-shu-ju-yuan-li

[8] influxdb集成:
https://www.influxdata.com/products/integrations/

相关推荐

redis的八种使用场景

前言:redis是我们工作开发中,经常要打交道的,下面对redis的使用场景做总结介绍也是对redis举报的功能做梳理。缓存Redis最常见的用途是作为缓存,用于加速应用程序的响应速度。...

基于Redis的3种分布式ID生成策略

在分布式系统设计中,全局唯一ID是一个基础而关键的组件。随着业务规模扩大和系统架构向微服务演进,传统的单机自增ID已无法满足需求。高并发、高可用的分布式ID生成方案成为构建可靠分布式系统的必要条件。R...

基于OpenWrt系统路由器的模式切换与网页设计

摘要:目前商用WiFi路由器已应用到多个领域,商家通过给用户提供一个稳定免费WiFi热点达到吸引客户、提升服务的目标。传统路由器自带的Luci界面提供了工厂模式的Web界面,用户可通过该界面配置路...

这篇文章教你看明白 nginx-ingress 控制器

主机nginx一般nginx做主机反向代理(网关)有以下配置...

如何用redis实现注册中心

一句话总结使用Redis实现注册中心:服务注册...

爱可可老师24小时热门分享(2020.5.10)

No1.看自己以前写的代码是种什么体验?No2.DooM-chip!国外网友SylvainLefebvre自制的无CPU、无操作码、无指令计数器...No3.我认为CS学位可以更好,如...

Apportable:拯救程序员,IOS一秒变安卓

摘要:还在为了跨平台使用cocos2d-x吗,拯救objc程序员的奇葩来了,ApportableSDK:FreeAndroidsupportforcocos2d-iPhone。App...

JAVA实现超买超卖方案汇总,那个最适合你,一篇文章彻底讲透

以下是几种Java实现超买超卖问题的核心解决方案及代码示例,针对高并发场景下的库存扣减问题:方案一:Redis原子操作+Lua脚本(推荐)//使用Redis+Lua保证原子性publicbo...

3月26日更新 快速施法自动施法可独立设置

2016年3月26日DOTA2有一个79.6MB的更新主要是针对自动施法和快速施法的调整本来内容不多不少朋友都有自动施法和快速施法的困扰英文更新日志一些视觉BUG修复就不翻译了主要翻译自动施...

Redis 是如何提供服务的

在刚刚接触Redis的时候,最想要知道的是一个’setnameJhon’命令到达Redis服务器的时候,它是如何返回’OK’的?里面命令处理的流程如何,具体细节怎么样?你一定有问过自己...

lua _G、_VERSION使用

到这里我们已经把lua基础库中的函数介绍完了,除了函数外基础库中还有两个常量,一个是_G,另一个是_VERSION。_G是基础库本身,指向自己,这个变量很有意思,可以无限引用自己,最后得到的还是自己,...

China&#39;s top diplomat to chair third China-Pacific Island countries foreign ministers&#39; meeting

BEIJING,May21(Xinhua)--ChineseForeignMinisterWangYi,alsoamemberofthePoliticalBureau...

移动工作交流工具Lua推出Insights数据分析产品

Lua是一个适用于各种职业人士的移动交流平台,它在今天推出了一项叫做Insights的全新功能。Insights是一个数据平台,客户可以在上面实时看到员工之间的交流情况,并分析这些情况对公司发展的影响...

Redis 7新武器:用Redis Stack实现向量搜索的极限压测

当传统关系型数据库还在为向量相似度搜索的性能挣扎时,Redis7的RedisStack...

Nginx/OpenResty详解,Nginx Lua编程,重定向与内部子请求

重定向与内部子请求Nginx的rewrite指令不仅可以在Nginx内部的server、location之间进行跳转,还可以进行外部链接的重定向。通过ngx_lua模块的Lua函数除了能实现Nginx...