逝者如斯夫,不舍昼夜。 —— 孔子
时间如流水,一去不复返。自古不乏对时间流逝的感慨,而现代已经有不少技术记录流逝的过去。咱们能够拍照,能够录像,固然还能够用时序数据库!数据库
时序数据库是专门存放随着时间推移而不断变化的数据。近些年,随着IoT等概念的流行,时序数据库成为数据库一个相对独立的领域逐渐受到重视,普遍应用于物联网、监控系统、金融、医疗和零售等多种场景。并发
那么云上的用户如何构建一个存储海量数据的时序数据库呢?笔者这里推荐使用 云HBase + OpenTSDB 方案。云HBase是使用阿里多年优化过的HBase内核版本,本文不做过多介绍,详情请看产品主页。测试
OpenTSDB是一款基于HBase构建的时序数据库,它的数据存储彻底交给HBase,自己没有任何数据存储。全部节点是对等的,因此部署起来实际上是很是方便的。由于基于HBase,因此自己就具有了横向扩展,存储海量数据的能力。常见的部署模式有2种,一种分离部署,一种混合部署。优化
独立部署,即与多个业务共享一个HBase。适合时序业务较小,或者用不满HBase资源。ui
混合部署,即TSDB进程和RS在一个VM内。适合时序业务较重,须要独享HBase。spa
上述2种模式,云HBase产品都能提供支持,云HBase购买页面现已增长时序引擎购买入口。设计
一条时间线由 Metirc + 多个tag 惟一肯定,时间线上会有源源不断的数据点(Data Point)写入,数据点由时间戳和值组成。OpenTSDB支持秒级(10位整数),毫秒级别(13位整数)两种时间精度。3d
举个例子,好比咱们监控一个手环收集的心跳信息,那么咱们能够这样定义:code
Metric: "band.heartbeat" Tags: "id" # 只定义一个tag,就是手环的ID
那么咱们经过 band.heartbeat
+ id=1
就能查询到编为1的手环收集到的心跳信息。blog
这个设计有几个特色:
salt:打散同一metric不一样时间线的热点
metric, tagK, tagV:实际存储的是字符串对应的UID(在tsdb-uid表中)
timestamp:每小时数据存在一行,记录的是每小时整点秒级时间戳
它们长度默认是3个字节,即最多只能分配 2^24=16777216
个UID。能够经过这些参数调整:
tsd.storage.uid.width.metric # metric UID长度,默认3 tsd.storage.uid.width.tagk # tagK UID长度,默认3 tsd.storage.uid.width.tagv # tagV UID长度 默认3 # 这3者的UID分配分别是独立的空间
注意:
集群已经写过数据后就没法修改,因此最好是一开始就肯定好,建议4个字节。由于使用压缩技术后,RowKey多占的几个字节能够忽略,下文会提到。
salt这个东西最好根据本身HBase集群规模去配置,它有2个配置:
tsd.storage.salt.width # 默认1,1基本够了,不用调整 tsd.storage.salt.buckets # 打散到几个bucket去,默认20
查询的时候会并发 tsd.storage.salt.buckets
个Scanner到HBase上,因此若是这个配置太大,对查询影响比较大,容易打爆HBase。这里实际上是一个权衡,写入热点和查询压力。默认20其实我我的以为有点多,配置3~8就差很少了,固然实际效果还和metric设计有关,若是在一个metric里设计了不少时间线,那就得配置不少bucket。在一个metric中设计过多时间线,会影响OpenTSDB的查询效率,因此不建议这么作。
这个参数也是设置了就不能改的,因此也是要一开始规划好。
这是列名(HBase中称为qualifier)的格式,能够看到毫米级须要多出2个字节。因此若是你的采集间隔不须要精确到毫秒级别,那请必定使用秒级(10位整数)。Value只能存储整数和浮点,因此有一个bit存储Float flag。
这里你们必定会有疑问,直接经过qualifier长度是4仍是2不就能判断是秒级精度的数据点,仍是毫秒了么?为什么还须要MS flag这样一个标记信息?阅读下面的“压缩”部分,就能知道为何。
OpenTSDB有个很常见而且很麻烦的问题,就是整点时候对HBase对流量冲击。下面2张图是咱们一个测试集群只作写入对效果:
能够看到会有一个数倍流量的爆发,要持续好久才能消化。这意味着咱们须要更高规格去抗这个峰值。首先咱们要明白OpenTSDB为啥要作压缩?在压缩些什么东西?
前面提到过OpenTSDB一行一小时的特色,那么一行里会有不少KV。表面上看起来好像没什么问题,可是实际上对比逻辑视图和物理视图你会发现一些问题。
很明显,每一个KV都记录了rowX,那rowX就是一个空间浪费。这个空间不只影响成本,还影响查询效率(毕竟数据多了)。压缩作的事情就是把多个小KV合成1个大KV,减小这部分浪费。因此压缩的时候会涉及到对HBase的“读-写-删”,这就是整点HBase IO流量的来源。
那么咱们有没有办法,既作压缩,同时又消除这部分HBase IO呢?
固然有!咱们能够把压缩的逻辑放到HBase内部去。由于HBase自己就须要对HFile作合并工做,这时候HBase自己就会读写数据文件,这部分对HDFS的IO不会少,而咱们经过hook在HBase读出数据后,替换掉要写入的数据(即压缩好的数据)。
实现上面这个功能,固然须要必定内核开发量。好消息是经过云HBase购买页面购买的时序引擎,已经自带了上述功能。不论是分离部署模式,仍是混合部署模式。
这个功能的好处显而易见,消除峰值节省成本,提高集群稳定性。这样咱们对一个现有的HBase集群空闲资源需求就不是那么高了,彻底能够复用了。下面是使用此功能后,一样只作写入的测试集群的流量状况:
本文做者:郭泽晖
本文为云栖社区原创内容,未经容许不得转载。