时序数据库技术体系-时序数据存储模型设计

时序数据库技术体系-时序数据存储模型设计

存储架构  2017-11-19

时序数据库技术体系中一个非常重要的技术点是时序数据模型设计,不同的时序系统有不同的设计模式,不同的设计模式对时序数据的读写性能、数据压缩效率等各个方面都有不同程度的影响。这篇文章笔者将会分别针对OpenTSDB、Druid、InfluxDB以及Beringei这四个时序系统中的时序数据模型设计进行介绍。

在详细介绍时序数据模型之前,还是有必要简单回顾一下时序数据的几个基本概念,如下图所示:

上图是一个典型的时序数据示意图,由图中可以看出,时序数据由两个维度坐标来表示,横坐标表示时间轴,随着时间的不断流逝,数据也会源源不断地吐出来;和横坐标不同,纵坐标由两种元素构成,分别是数据源和metric,数据源由一系列的标签(tag,也称为维度)唯一表示,图中数据源是一个广告数据源,这个数据源由publisher、advertiser、gender以及country四个维度值唯一表示,metric表示待收集的数据源指标。一个数据源通常会采集很多指标(metric),上图中广告数据源就采集了impressions、clicks以及revenue这三种指标,分别表示广告浏览量、广告点击率以及广告收入。

看到这里,相信大家对时序数据已经有了一个初步的了解,可以简单的概括为:一个时序数据点(point)由datasource(tags)+metric+timestamp这三部分唯一确定。然而,这只是逻辑上的概念理解,那具体的时序数据库到底是如何将这样一系列时序数据点进行存储的呢?下文笔者针对OpenTSDB、Druid、InfluxDB以及Beringei四种系统进行介绍。

OpenTSDB(HBase)时序数据存储模型

OpenTSDB基于HBase存储时序数据,在HBase层面设计RowKey规则为: metric+timestamp+datasource(tags) 。HBase是一个KV数据库,一个时序数据(point)如果以KV的形式表示,那么其中的V必然是point的具体数值,而K就自然而然是唯一确定point数值的datasource+metric+timestamp。 这种规律不仅适用于HBase,还适用于其他KV数据库,比如Kudu。

既然HBase中K是由datasource、metric以及timestamp三者构成,现在我们可以简单认为rowkey就为这三者的组合,那问题来了:这三者的组合顺序是怎么样的呢?

首先来看哪个应该排在首位。因为HBase中一张表的数据组织方式是按照rowkey的字典序顺序排列的,为了将同一种指标的所有数据集中放在一起,HBase将将metric放在了rowkey的最前面。假如将timestamp放在最前面,同一时刻的数据必然会写入同一个数据分片,无法起到散列的效果;而如果将datasource(即tags)放在最前面的话,这里有个更大的问题,就是datasource本身由多个标签组成,如果用户指定其中部分标签查找,而且不是前缀标签的话,在HBase里面将会变成大范围的扫描过滤查询,查询效率非常之低。举个上面的例子,如果将datasource放在最前面,那rowkey就可以表示为publisher=ultrarimfast.com&advertiser:google.com&gender:Male&country:USA_impressions_20110101000000,此时用户想查找20110101000000这个时间点所有发布在USA的所有广告的浏览量,即只根据country=USA这样一个维度信息查找指定时间点的某个指标,而且这个维度不是前缀维度,就会扫描大量的记录进行过滤。

确定了metric放在最前面之后,再来看看接下来应该将datasource放在中间呢还是应该将timestamp放在中间?将metric放在前面已经可以解决请求均匀分布(散列)的要求,因此HBase将timestamp放在中间,将datasource放在最后。试想,如果将datasource放在中间,也会遇到上文中说到的后缀维度查找的问题。

因此,OpenTSDB中rowkey的设计为:metric+timestamp+datasource,好了,那HBase就可以只设置一个columnfamily和一个column。那问题来了,OpenTSDB的这种设计有什么问题?在了解设计问题之前需要简单看看HBase在文件中存储KV的方式,即一系列时序数据在文件、内存中的存储方式,如下图所示:

上图是HBase中一个存储KeyValue(KV)数据的数据块结构,一个数据块由多个KeyValue数据组成,在我们的事例中KeyValue就是一个时序数据点(point)。其中Value结构很简单,就是一个数值。而Key就比较复杂了,由rowkey+columnfamily+column+timestamp+keytype组成,其中rowkey等于metric+timestamp+datasource。

问题一:存在很多无用的字段。 一个KeyValue中只有rowkey是有用的,其他字段诸如columnfamily、column、timestamp以及keytype从理论上来讲都没有任何实际意义,但在HBase的存储体系里都必须存在,因而耗费了很大的存储成本。

问题二:数据源和采集指标冗余。 KeyValue中rowkey等于metric+timestamp+datasource,试想同一个数据源的同一个采集指标,随着时间的流逝不断吐出采集数据,这些数据理论上共用同一个数据源(datasource)和采集指标(metric),但在HBase的这套存储体系下,共用是无法体现的,因此存在大量的数据冗余,主要是数据源冗余以及采集指标冗余。

问题三:无法有效的压缩。 HBase提供了块级别的压缩算法-snappy、gzip等,这些通用压缩算法并没有针对时序数据进行设置,压缩效率比较低。HBase同样提供了一些编码算法,比如FastDiff等等,可以起到一定的压缩效果,但是效果并不佳。效果不佳的主要原因是HBase没有数据类型的概念,没有schema的概念,不能针对特定数据类型进行特定编码,只能选择通用的编码,效果可想而知。

问题四:不能完全保证多维查询能力。 HBase本身没有schema,目前没有实现倒排索引机制,所有查询必须指定metric、timestamp以及完整的tags或者前缀tags进行查询,对于后缀维度查询也勉为其难。

虽说有这样那样的问题,但是OpenTSDB还是针对存储模型做了两个方面的优化:

优化一:timestamp并不是想象中细粒度到秒级或毫秒级,而是精确到小时级别,然后将小时中每一秒设置到列上。 这样一行就会有3600列,每一列表示一小时的一秒。这样设置据说可以有效的取出一小时整的数据。

优化二:所有metrics以及所有标签信息(tags)都使用了全局编码将标签值编码成更短的bit,减少rowkey的存储数据量。 上文分析HBase这种存储方式的弊端是说道会存在大量的数据源(tags)冗余以及指标(metric)冗余,有冗余是吧,那我就搞个编码,将string编码成bit,尽最大努力减少冗余。虽说这样的全局编码可以有效降低数据的存储量,但是因为全局编码字典需要存储在内存中,因此在很多时候(海量标签值),字典所需内存都会非常之大。

上述两个优化可以参考OpenTSDB这张经典的示意图:

Druid时序数据存储模型设计

和HBase和Kudu这类KV数据库不同,Druid是另一种玩法。Druid是一个不折不扣的列式存储系统,没有HBase的主键。上述时序数据在Druid中表示是下面这个样子的:

Druid是一个列式数据库,所以每一列都会独立存储,比如Timestamp列会存储在一起形成一个文件,publish列会存储在一起形成一个文件,以此类推。细心的童鞋就会说了,这样存储,依然会有数据源(tags)大量冗余的问题。针对冗余这个问题,Druid和HBase的处理方式一样,都是采用编码字典对标签值进行编码,将string类型的标签值编码成int值。但和HBase不一样的是,Druid编码是局部编码,Druid和HBase都采用LSM结构,数据先写入内存再flush到数据文件,Druid编码是文件级别的,局部编码可以有效减小对内存的巨大压力。除此之外,Druid的这种列式存储模式还有如下好处:

  1. 数据存储压缩率高。每列独立存储,可以针对每列进行压缩,而且可以为每列设置对应的压缩策略,比如时间列、int、fload、double、string都可以分别进行压缩,压缩效果更好。
  2. 支持多维查找。Druid为datasource的每个列分别设置了Bitmap索引,利用Bitmap索引可以有效实现多维查找,比如用户想查找20110101T00:00:00这个时间点所有发布在USA的所有广告的浏览量,可以根据country=USA在Bitmap索引中找到要找的行号,再根据行号定位待查的metrics。

然而,这样的存储模型也有一些问题:

  1. 数据依然存在冗余。 和OpenTSDB一样,tags存在大量的冗余。
  2. 指定数据源的范围查找并没有OpenTSDB高效。 这是因为Druid会将数据源拆开成多个标签,每个标签都走Bitmap索引,再最后使用与操作找到满足条件的行号,这个过程需要一定的开销。而OpenTSDB中直接可以根据数据源拼成rowkey,查找走B+树索引,效率必然会更高。

InfluxDB时序数据存储模型设计

相比OpenTSDB以及Druid,可能很多童鞋对InfluxDB并不特别熟悉,然而在时序数据库排行榜单上InfluxDB却是遥遥领先。InfluxDB是一款专业的时序数据库,只存储时序数据,因此在数据模型的存储上可以针对时序数据做非常多的优化工作。

为了保证写入的高效,InfluxDB也采用LSM结构,数据先写入内存,当内存容量达到一定阈值之后flush到文件。InfluxDB在时序数据模型设计方面提出了一个非常重要的概念:seriesKey,seriesKey实际上就是datasource(tags)+metric,时序数据写入内存之后按照seriesKey进行组织:

内存中实际上就是一个Map:<serieskey, list>,Map中一个SeriesKey对应一个List,List中存储时间线数据。数据进来之后根据datasource(tags)+metric拼成SeriesKey,再将Timestamp|Value组合值写入时间线数据List中。内存中的数据flush的文件后,同样会将同一个SeriesKey中的时间线数据写入同一个Block块内,即一个Block块内的数据都属于同一个数据源下的一个metric。

这种设计我们认为是将时间序列数据按照时间线挑了出来。先来看看这样设计的好处:

好处一:同一数据源的tags不再冗余存储。一个Block内的数据都共用一个SeriesKey,只需要将这个SeriesKey写入这个Block的Trailer部分就可以。 大大降低了时序数据的存储量。

好处二:时间序列和value可以在同一个Block内分开独立存储,独立存储就可以对时间列以及数值列分别进行压缩。InfluxDB对时间列的存储借鉴了Beringei的压缩方式,使用delta-delta压缩方式极大的提高了压缩效率。而对Value的压缩可以针对不同的数据类型采用相同的压缩效率。

好处三:对于给定数据源以及时间范围的数据查找,可以非常高效的进行查找。这一点和OpenTSDB一样。

细心的同学可能会问了,将datasource(tags)和metric拼成SeriesKey,不是也不能实现多维查找。确实是这样,不过InfluxDB内部实现了倒排索引机制,即实现了tag到SeriesKey的映射关系,如果用户想根据某个tag查找的话,首先根据tag在倒排索引中找到对应的SeriesKey,再根据SeriesKey定位具体的时间线数据。 InfluxDB的这种存储引擎称为TSM,全称为Timestamp-Structure Merge Tree,基本原理类似于LSM。后期笔者将会对InfluxDB的数据写入、文件格式、倒排索引以及数据读取进行专题介绍。

Beringei时序数据存储模型设计

Beringei是今年Facebook开源的一个时序数据库系统。InfluxDB时序数据模型设计很好地将时间序列按照数据源以及metric挑选了出来,解决了维度列值冗余存储,时间列不能有效压缩的问题。但InfluxDB没有很好的解决写入缓存压缩的问题:InfluxDB在写入内存的时候并没有压缩,而是在数据写入文件的时候进行对应压缩。我们知道时序数据最大的特点之一是最近写入的数据最热,将最近写入的数据全部放在内存可以极大提升读取效率。Beringei很好的解决了这个问题,流式压缩意味着数据写入内存之后就进行压缩,这样会使得内存中可以缓存更多的时序数据,这样对于最近数据的查询会有很大的帮助。

Beringei的时序数据模型设计与InfluxDB基本一致,也是提出类似于SeriesKey的概念,将时间线挑了出来。但和InfluxDB有两个比较大的区别:

  1. 文件组织形式不同。Beringei的文件存储形式按照时间窗口组织,比如最近5分钟的数据全部写入同一个文件,这个文件分为很多block,每个block中的所有时序数据共用一个SeriesKey。Beringei文件没有索引,InfluxDB有索引。
  2. Beringei目前没有倒排索引机制,因此对于多维查询并不高效。

后续笔者也会针对Beringei的数据写入、流式压缩、文件格式等进行介绍。在笔者看来,如果将Beringei和InfluxDB有效结合起来,就能够将时序数据高效存储在内存,另外数据按照维度进行组织,可以非常高效的提高数据在文件的存储效率以及查询效率,最后结合InfluxDB的倒排索引功能可以有效提高多维查询能力。

本文是时序数据库技术体系的第一篇文章,笔者主要结合OpenTSDB、Druid、InfluxDB以及Beringei这四种时序数据库分别对时序数据这种数据形式的存储模型进行了介绍。每种数据库都有自己的一套存储方式,而每种存储方式都有各自的一些优势以及缺陷,正是这些优劣式直接决定了相应时序数据库的压缩性能、读写性能。

有态度的HBase

责编内容by:有态度的HBase (源链)。感谢您的支持!

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
一、物联网的概览1.1物联网的起源1.2物联网的概念1.3物联网的应用1.4物联网技术要素1.5物联网与云计算的关系1.6物联网与大数据的关系二、软件架构演进史2.1单体架构2.2分布式应用2.3微服务架构2.4Serverless架构三、物联网云平台开发环境搭建3.1开发需要的软件与技术环境概览3.2Java环境-JDK安装3.3数据库-MySQL安装3.4高速缓存技术-redis安装3.5时序数据库-influxdb安装3.6IDE开发工具-idea 安装3.7原型图设计工具-axure安装3.8前端开发工具-vscode安装3.9容器部署-docker安装3.10消息队列-kafka安装3.11mqtt broker安装四、可视化管理工具的安装4.1navicat安装与使用4.2redis 可视化工具安装与使用4.3mqtt可视化工具安装与使用4.4kafka可视化工具安装与使用4.5代码管理工具安装git与使用五、后台开发基础知识介绍5.1数据库使用5.2Redis连接5.3Mqtt接入5.4Influxdb接入5.5Kafka接入5.6负载均衡nginx搭建5.7租户概念5.8Iass,pass,sass之间的联系六、微服务架构介绍6.1微服务核心组件介绍6.2微服务网关gateway6.3注册中心6.4配置中心6.5负载均衡6.6服务调用6.7熔断机制七、物联网平台需求分析7.1物联网云平台的背景7.2物联网云平台脑图设计7.3物联网云平台需求分析7.4物联网云平台开发计划设计八、物联网平台架构设计8.1平台服务拆分8.2物联网平台架构图设计8.3平台技术栈的选择8.4设备认证的设计8.5服务网关的设计8.6后台服务的设计 九、物联网云平台原型设计9.1登录注册页面设计9.2首页设计9.3产品页面设计9.4设备页面设计9.5数据中心页面设计十、数据库设计10.1关系数据库设计10.1.1用户表10.1.2角色表10.1.3权限表10.1.4用户角色表10.1.5角色权限表10.1.6产品表10.1.7设备表10.1.8操作记录表10.2时序数据库设计十一、物联网云平台接口文档设计11.1物联网云平台通信方式介绍11.2HTTP接口设计11.2.1.登录接口设计11.2.2注册接口设计11.2.3产品列表设计11.2.4产品添加设计11.2.5产品编辑接口11.2.6产品删除设计11.2.7添加设备接口11.2.8编辑设备接口11.2.9删除设备接口11.2.10添加租户接口11.2.11删除租户接口11.2.12编辑租户接口11.3mqtt主题十二、物联网云平台后台代码开发12.1.认证服务代码开发12.2产品管理代码开发12.3设备管理代码开发12.4数据分析代码开发12.5首页代码开发十三、物联网平台接口测试13.1什么是接口13.2接口测试流程13.3常见后台测试用例13.4使用postman测试接口 十四、物联网云平台前端设计14.1物联网云平台前端技术栈14.2vue环境搭建14.3element基础组件学习14.4vue admin element框架13.5vue与后台接口对接与联调 十五、物联网设备客户端开发15.1flutter介绍15.2flutter环境搭建15.3利用flutter编写第一个Android程序15.4flutter写一个程序接入物联网云平台  十六、部署与实施16.1使用idea发布docker环境16.2微服务程序部署方式介绍16.2.1使用jar包部署微服务程序16.2.2docker 部署微服务程序16.3dockerfile编写16.5负载均衡Nginx搭建与配置微服务程序 十七、物联网实例-设计一款远程电子锁17.1材料准备17.2技术原理17.3产品测试
Prometheus时序数据库提供了强大的Promql查询语言来满足我们的查询需求。在查询数据之前,我们需要先插入数据到Prometheus中。在之前的博客中,详细介绍了Prometheus数据的插入过程\[1\]。而在查询数据时,我们可以使用Promql来进行查询。Promql是一种灵活的查询语言,可以根据我们的需求进行千变万化的查询\[2\]。 在进行查询时,Prometheus会根据指定的时间窗口来过滤数据,默认的时间窗口是5分钟,可以通过启动参数来进行设置\[3\]。这样可以确保我们只获取到指定时间范围内的数据,而不会包含过去或未来的数据。 总结来说,Prometheus时序数据库通过Promql查询语言来满足我们的查询需求,并通过时间窗口来过滤数据,确保我们获取到的数据符合我们的要求。 #### 引用[.reference_title] - *1* [Prometheus时序数据库-数据的查询](https://blog.csdn.net/weixin_55416758/article/details/115350199)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [Prometheus时序数据库-报警的计算 及 Prometheus时序数据库-数据的查询](https://blog.csdn.net/m0_67322837/article/details/125004715)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值