百度时序数据库——存储的省钱之道

作者简介:任杰    百度高级研发工程师

负责百度智能运维产品(Noah)的分布式时序数据存储设计研发工作,在大规模分布式存储、NoSQL数据库方面有大量实践经验。

干货概览

百度Noah平台的TSDB,是百度最大规模的时序数据库,它为Noah监控系统提供时序数据存储与查询服务,每天承接多达数万亿次的数据点写入请求,以及数十亿次的查询请求。作为监控系统的后端服务,在如此大规模的写入情况下,保证快速的查询响应非常重要,这对系统提出了巨大挑战。通过对用户日常查询行为进行分析,用户的查询需求与数据的时间轴有强关联,用户更加关心最近产生的数据。因此Noah的TSDB在架构上,利用百度BDRP(百度的Redis平台)构建缓存层,缓存最近几小时的数据,极大提升查询性能,有效降低查询平响。

同样Facebook为了提高其ODS TSDB读写性能,设计了基于内存的Gorilla时序数据库,用作ODS的write-through cache方案缓存数据。可以看出在缓存这层,我们都采用基于内存的方式做数据缓存。采用内存最大的优势是其数据读写速度远快于磁盘速度,然而缺点是需要占用较大的内存空间资源。为了有效节约内存空间,Gorilla设计了时序数据压缩算法对时序数据进行实时压缩。在Gorilla论文[1]中表明,利用其压缩算法,在Facebook的生产环境下平均压缩数据10倍。

我们在对缓存层数据存储设计的时候,结合Noah TSDB的具体情况,借鉴了Gorilla数据压缩算法对数据进行压缩,存储空间资源占用降低了70%,有效降低资源成本。因此本文简单和大家分享一下该压缩算法的基本原理,没准儿也能节约下不少钱呢。

基础介绍

典型的时序数据,是由Key-Value组成的二元组, Key中可能包含如Cluster、Tag、Metric、Timestamp等信息。为了便于理解,这里将时序数据简单理解为Key是时间戳(Timestamp),Value是在该时间戳时的具体数据值。

假设这是某CPU在不同时间的利用率:

以这份数据为例,在后续介绍中我们一边介绍算法,一边采用Gorilla的压缩方法对这个测试数据进行压缩,观察该算法压缩效果。

压缩思想

1基本原则

Gorilla压缩算法,其核心思想建立在时序数据场景下,相邻的时序数据相似度很大这一特点之上。基于这个基本的原则,尽量只保留数据差异的部分,去除相同的部分,来达到压缩数据的目的。

2数据结构

Gorilla将数据组织成一个个数据块(Block),一个Block保存连续一段时间且经过压缩的时序数据。每次查询的时候会直接读取目标数据所属的Block,对Block解压后返回查询结果。Facebook经验表明,如果一个Block的时间跨度超过2小时,由于解压Block所消耗的资源增加,其压缩收益会逐渐降低,因此将单个Block的时间跨度设置为2小时。

每个Block的Header保存其起始时间戳(Timebase),例如如果某时序数据产生时间点是2019/2/24 14:30,则以2小时为单位向上取整,该数据所属的Block的Timebase为2019/2/24 14:00,时间戳为1550944800如下图所示。然后以KV的形式依次保存属于该Block的时序数据。

接下来分别介绍对Key和Value的压缩方法。

时间戳压缩

时序数据的产生,大部分都有固定的产生时间间隔,如间隔10s、15s、60s等。即使由于各种因素造成时序数据产生有一定延迟或者提前,但是大部分数据的时间戳间隔都是在非常接近的范围内。因此对时间戳压缩的思想就是不需要存储完整的时间戳,只存储时间戳差值的差值(delta of delta)。具体以本文测试数据的时间戳Key为例介绍时间戳压缩算法。

  • 压缩前

每个秒级的时间戳用Long型存储(8Bytes),本文测试数据中的3条数据时间戳共需要占用3*8*8 = 192(Bits)。T均为Unix 时间戳。

  • Gorilla压缩

对于每个Block:

  1. Block的头部Header存储本Block的起始时间戳,不做任何压缩。
  2. 第一个时间戳存储与的差值(Delta),占用14(Bits)。
  3. 对于本Block后面的时间戳:
    1. 计算差值的差值:
    2. 存在Block中时间戳数据由 [标识位+D值] 组成,根据D的不同范围确定标识位的取值和保存D值所需占用的空间。如下表所示:

具体对于本例而言,采用上述对时间戳的压缩方式后结果如下所示:

利用上述的压缩编码方式对本文的测试数据编码后,其所属的Block内数据如下所示:

其中只填写了T的部分,V的部分由下文进行补充。经过压缩测试数据,总共占用64+14+9+1=88(Bits),压缩率为88/192=45.8%。

由于本例的测试数据较少,Header空间占比较大,导致压缩收益与实际环境中收益有一定差距。在实际环境中,Header所占有的空间相对于整个Block来说比例较小,压缩收益会更大。根据Facebook线上数据统计,如下图所示,96%的时间戳都被压缩到1个Bit来存储,因此在生产环境将会带来不错的压缩收益(结合数据分布再回过头看编码方式,是不是有点Huffman编码的感觉)。

数据值压缩

对时间戳Key压缩后,接下来对Value进行压缩。与Key类似,通过对历史数据进行分析,发现大部分相邻时间的时序数据的Value值比较接近(可以理解为突增/突降的现象比较少)。而如果Value的值比较接近,则在浮点二进制表示的情况下,相邻数据的Value会有很多相同的位。整数型数据的相同位会更多。相同位比较多,意味着如果进行XOR运算的话会有很多位都为0。

为了便于说明,这里首先定义一个XOR运算后的结果由三部分组成:

  • Leading Zeros(LZ): XOR后第一个非零位前面零的个数
  • Trailing Zeros(TZ): XOR后最后一个非零位后面零的个数
  • Meaningful Bits(MB): 中间有效位的个数

上图是Gorilla论文里给的示例,可以理解该数据为一系列相邻时序数据的Value。可以看出对相邻数据进行XOR运算后,MB、LZ和TZ非常相似。基于此,其压缩方式参考之前其他工作[2,3]已经提出的数据压缩方法,将当前值与前序值取XOR(异或)运算,保存XOR运算结果。具体方式如下:

  • 压缩前

每个浮点类型数据Double型存储占用8Bytes,本文测试数据中的3条数据Value共需要占用3*8*8 = 192(Bits)。

  • Gorilla压缩

在同一个Block内,Value的压缩规则如下:

  1. 第一个Value的值不压缩。
  2. 对于本数据块后面的Value值:
    1. XOR运算结果:
    2. 对结果进行如下处理:

基于上述压缩编码规则,对本文测试数据的Value进行压缩后结果如下所示,压缩后总共占用64+1+1+14 = 80(Bits),压缩率为80/256=31.2%。

此时该Block内的数据如下所示:

以上就是对于Value值的压缩方法。与Key的压缩一样,在线上环境数据量较多的情况下压缩效果会更好。根据Facebook线上数据统计,59.06%的value值都被压缩到1个位来存储。

总  结

总的来说,利用上述的压缩方式,我们的测试数据由384Bits(Key+Value)变为168Bits,压缩率达到43%,具有不错的压缩效率。当然由于数据量的原因,在实际生产环境下压缩收益会更大。百度Noah的TSDB在应用上述压缩算法的实践中,基于我们的实际情况进行了一定的改造(后续序列文章会另行介绍),存储空间的资源占用减少超过70%,表明这个算法能真实有效对时序数据进行压缩。

另外一点,我们发现在做压缩的时候Gorilla对Key和Value分开进行了压缩处理。将Key和Value分开压缩的好处在于,可以根据Key、Value不同的数据类型、数据特点,选用更适合自己的压缩算法,从而提高压缩效率。在时序场景下,KV分别处理虽然不是一个新的思想,但是可以将该思想应用在多个地方。比如本文提到的Gorilla是将该思想应用在压缩方面,FAST2016年的WiscKey[4]利用KV分离思想优化LSM的IO放大问题。有兴趣的读者可以针对KV分离方法探索一下。

由于本人水平有限,若理解不到位或者大家有任何想法,欢迎指出交流。

参考文献

1. Pelkonen T , Franklin S , Teller J , et al. Gorilla: A Fast, Scalable, In-Memory Time Series Database[J]. Proceedings of the Vldb Endowment, 2015, 8(12):1816-1827.

2. P. Lindstrom and M. Isenburg. Fast and Efficient Compression of Floating-Point Data. Visualization and Computer Graphics, IEEE Transactions on, 12(5):1245–1250, 2006.

3. P. Ratanaworabhan, J. Ke, and M. Burtscher. Fast Lossless Compression of Scientific Floating-Point Data. In DCC, pages 133–142. IEEE Computer Society, 2006.

4. Lu L , Pillai T S , Gopalakrishnan H , et al. WiscKey: Separating Keys from Values in SSD-Conscious Storage[J]. ACM Transactions on Storage, 2017, 13(1):1-28.

Image placeholder
hejeff
未设置
  45人点赞

没有讨论,发表一下自己的看法吧

推荐文章
时序数据库的秘密 —— 快速检索

Elasticsearch是通过Lucene的倒排索引技术实现比关系型数据库更快的过滤。特别是它对多条件的过滤支持非常好,比如年龄在18和30之间,性别为女性这样的组合查询。倒排索引很多地方都有介绍,

基于时序数据库做监控,这里有超流行的开源方案

在微服务架构下,我们对服务进行了拆分,所以用户的每次请求不再是由某一个服务独立完成了,而是变成了多个服务一起配合完成。这种情况下,一旦请求出现异常,我们必须得知道是在哪个服务环节出了故障,就需要对每一

分布式时序数据库QTSDB的设计与实现

现有的开源时序数据库influxdb只支持单机运行,在面临大量数据写入时,会出现查询慢,机器负载高,单机容量的限制。为了解决这一问题,360基础架构团队在单机influxdb的基础上,开发了集群版——

NAS与对象存储:谁是非结构化数据存储的最佳选择?

非结构化数据是增长最快的数据类型之一。随着企业日积月累地生成、收集和存储越来越多的数据,必然会带来一个问题:什么是存储非结构化数据的最佳方式?直白来说,非结构化数据就是不遵循传统数据库格式的数据,其结

如何解决云中容器数据存储的移动性挑战?

如今,在云计算领域,越来越多的IT组织正在构建混合云和多云环境以支撑其业务运行。从容器的角度来看,我们知道,容器应用程序从一开始就内置了非常可观的可移动性、灵活性和效率。但是对于容器数据来说,它的移动

海量数据时代,磁带存储的“涅槃重生”

   磁带作为大规模非结构化数据的战略性/低成本存储手段,已然经历了一次复兴。由于磁带在快速恢复网站和反勒索软件方面具有较高的价值,所以备份仍然是它的一个主要用例。不过,磁带的未来增长机会更在于一些新

基于内存和文件存储的 queue worker, 不用 Redis 适合单进程使用没有外部依赖

因为最近要做一个简单的并发任务系统,在github上面找了一圈并没有简单可依赖的库,所以自己写了一个。欢迎大家Review贡献代码。项目地址https://github.com/iflamed/mfw

引领存储新时代——新华三Primera关键业务智能存储

技术的变革,让我们步入数字智能时代。由数据、AI驱动的智能化产业转型正在如火如荼地进行中,金融、工业、医疗、娱乐……智能改变着一切。在IT对于企业已经如此重要的今天,智能也正改变着支撑企业业务运行的底

云端的生存之道,第 2 单元:将 Spring Boot 应用程序连接到云托管的数据库

前提条件 本系列教程的第1部分,因为本教程直接以第1部分中的课程内容和完成的操作为基础。 一个IBMCloud帐户 云原生数据持久性 IBMCloud提供了许多可持久存储数据的选项。在本教程中,我

巨杉TechDay回顾 | 与携程、巨杉、知乎大牛一起探寻DT时代数据库架构之道

数据,已成众多企业的核心资产。如今企业越来越懂得数据的重要性,也愈发清楚数据将为公司带来的巨大价值。在物联网、AI等技术的普及下,数据井喷仍在持续进行,如何更好地管理和使用这些“无穷无尽”的数据,则成

云原生存储和云存储有什么区别?

作者| 李鹏(壮怀)阿里云智能事业群高级技术专家导读:新的企业负载/智能工作负载容器化、迁云、存储方面遇到的性能、弹性、高可用、加密、隔离、可观测性以及生命周期等方面的问题,不但需要存储产品层次的改进

Spring Boot 高效数据聚合之道

项目地址和示例代码:https://github.com/lvyahui8/spring-boot-data-aggregator 背景 接口开发是后端开发中最常见的场景,可能是RESTFul接口,也

往数据库添加数据4个步骤——增

1.前端回传数据,ajax或者直接表单提交,提交到资源路由admin/xxxpost2.后端接收数据,铜鼓参数回传$input=$request->all();或者except(token);3.表单

localForage——轻松实现 Web 离线存储

课程推荐:web全栈开发就业班--拿到offer再缴学费--融职教育 localStorage能够让你实现基本的数据存储,但它的速度慢,而且不能处理二进制数据。IndexedDB和WebSQL是异步的

PHP 整洁之道

yangweijie/clean-code-php clean-code-php TableofContents 介绍 变量 函数 介绍 本文由yangweijie翻译自clenphpcode,团

云端的生存之道,第 1 单元:将 Spring Boot 部署到 Kubernetes

初始化Kubernetes集群 第一步是初始化IBMCloud上的Kubernetes集群。IBMCloud可能需要几分钟时间来启动新的Kubernetes集群;因此,通过先执行初始化操作,可以在后台

GitHub 被墙后的生存之道

背景 从今天开始,陆陆续续看到很多小伙伴说Github登录不上去了,我当然也不例外,但对于我这样的重度Github使用者,这是无法接受的。 前提 首先SS是肯定可以解决我们的访问问题的,但是这里我不会

PHP 代码简洁之道 ( PHP Clean Code)

介绍 RobertC.Martin's的软件工程师准则CleanCode同样适用于PHP。它并不是一个编码风格指南,它指导我们用PHP写出具有可读性,可复用性且可分解的代码。 并非所有的准则都必须严格

架构修炼之道 | 一个传统网关系统有几种 “死” 法

本文节选自《架构修炼之道》,作者京东王新栋。图| meghan-holmes-779221-unsplash这里说的传统,是按照网关技术演进的阶段划分的,从同步到半同步,再到全异步,我们将同步和半同步

来SACC2019共论“数字转型 架构演进”之道

2019已经过半,第十一届中国系统架构师大会SACC2019的脚步也越来越近了,十年来中国系统架构师大会SACC一直紧跟系统架构关键技术热点,成为架构师、CTO、CIO以及各研发人员学习交流的前沿阵地

技术苍穹与平台沃土:华为构筑产业数字化的太极之道

产业数字化正在今天经历快速变化。自华为企业BG发布数字平台之后的7个月里,产业智能已经达成了广泛的行业共识、驱动传统经济向数字经济快速过渡被提升为国家战略,大量技术、人才、资金涌入产业数字化浪潮当中。

虚拟网络的“监管”之道 企业上云两手都要硬

现阶段,企业级业务进入需求爆发期,混合云网络成为新的趋势。企业开始关注和尝试使用微服务架构,其网络当中可以有几百至上千个微服务,各种微服务之间关系紧密。真正复杂的部分不在于资源池网络,而是更多地在于企

MySQL 数据库操作:创建和查看数据库

数据库是数据的集合。MySQL允许我们高效地存储和检索数据库中的数据。在MySQL中,我们可以使用CREATEDATABASE语句创建数据库。但是,如果数据库已经存在,则会引发错误。为了避免该错误,我

MySQL 数据库操作:删除数据库

使用MySQL的DROPDATABASE命令可以很容易的删除一个数据库。数据库删除的同时,所属的数据表将一起被删除。如果删除的数据库不存在,则会引发错误。为了避免错误的发生,可以在DROPDATABA

平安科技数据库总经理汪洋:开源数据库在平安的应用实践

本文转自| 平安科技数据库产品团队2019年5月9日,平安科技数据库产品及存储产品部总经理在第十届数据库技术大会DTCC上分享了《开源数据库在平安的应用实践》,本文根据演讲内容整理,围绕以下几个方面进