0.时序数据库

时间序列(Time Series):是一组按照时间发生先后顺序进行排列的数据点序列,通常一组时间序列的时间间隔为一恒定值(如1秒,5分钟,1小时等)。

时间序列数据可被简称为时序数据。实时监控系统所收集的监控指标数据,通常就是时序数据 。时序数据具有如下特点:

  • 每一个时间序列通常为某一固定类型的数值
  • 数据按一定的时间间隔持续产生,每条数据拥有自己的时间戳信息
  • 通常只会不断的写入新的数据,几乎不会有更新、删除的场景
  • 在读取上,也往往倾向于读取最近写入的数据。

OpenTSDB是其中一种时序数据库实现,是一种基于Hbase、分布式、可伸缩的时间序列数据库。

1.OpenTSDB基本概念

  • metric:指标名,这个就是我们监控的指标,比如 sys.cpu.user;
  • timestamp:时间戳,监控数据产生的时间;
  • value:监控值,Long 或者 Double 类型的数据,这个是监控指标在某个时间的具体值;
  • tag:标签,包括标签名字(tagk)和标签值(tagv),比如 tagk1=tagv1,主要用于描述数据属性,每条时序数据必须包含一组和多组的标签数据。目前 OpenTSDB 最多支持8组标签。

2.数据样例:

sys.cpu.user host=webserver01
sys.cpu.user host=webserver01,cpu=
sys.cpu.user host=webserver01,cpu=
sys.cpu.user host=webserver01,cpu=
sys.cpu.user host=webserver01,cpu=
............
sys.cpu.user host=webserver01,cpu=

其中,每一行表示时间序列中的一个DataPoint,每部分对应如下:

每一个Data Point,都关联一个metrics名称,但可能关联多组<tagKey,tagValue>信息。而关于时间序列,事实上就是具有相同的metrics名称以及相同的<tagKey,tagValue>组信息的Data Points的集合。

3.存储模型

OpenTSDB是基于HBase进行数据存储,在HBase中存放tsdb、tsdb-meta、tsdb-tree、tsdb-uid四张表,主要用到的是tsdb、tsdb-uid两个。

1)tsdb-uid

为了统一各个值的长度以及节省空间,OpenTSDB中为每一个metrics名、tagKey以及tagValue都定义了一个唯一的数字类型的标识码(Unique Identifier, UID),这些UID信息被保存在OpenTSDB的元数据表tsdb-uid中。同时,为了从UID索引到metrics(或tagKey、tagValue),同时也要从metrics(或tagKey、tagValue)索引到UID,OpenTSDB同时保存了这两种映射关系数据

列族Column Family:

在元数据表中,把这两种数据分别保存到两个名为"id""name"的列族(Column Family)中,Column Family描述信息如下所示:

{NAME => 'id', BLOOMFILTER => 'ROW', COMPRESSION => 'SNAPPY'}
{NAME =>'name',BLOOMFILTER => 'ROW', COMPRESSION => 'SNAPPY', MIN_VERSIONS => '', BLOCKCACHE => 'true', BLOCKSIZE => '', REPLICATION_SCOPE => ''}

OpenTSDB分配UID时遵循如下规则:

  • metrics、tagKey和tagValue的UID分别独立分配
  • 每个metrics名称(或tagKey/tagValue)的UID值都是唯一。不存在不同的metrics(或tagKey/tagValue)使用相同的UID,也不存在同一个metrics(或tagKey/tagValue)使用多个不同的UID
  • UID值使用三个字节进行存储,其范围是0x000000到0xFFFFFF。

关于metrics名为"cpu.hum",tagKey值为"host",tagValue值分别为"189.120.205.26"、"189.120.205.27"的UID信息定义如下:

说明:

  • RowKey为"0"的行中,分别保存了metrics、tagKey和tagValue的当前UID的最大值。当为新的metrics、tagKey和tagValue分配了新的UID后,会更新对应的最大值
  • RowKey为"1"的行中,RowKey为UID,Qualifier(列名)为"id:metrics"的值"metrics",Qualifier为"id:tagk"的值为tagKey,Qualifier为id:tagv的值为tagValue
  • RowKey为"2"的行中,RowKey为UID,Qualifier为"id:tagv"的值为tagValue,暂不存在UID为"2"的metrics和tagKey
  • RowKey为"189.120.205.26"的行中,Qualifer为"name:tagv"的值为UID。表示当"189.120.205.26"为tagValue时,其UID为1
  • RowKey为"189.120.205.27"的行中,Qualifer为"name:tagv"的值为UID。表示当"189.120.205.26"为tagValue时,其UID为2
  • RowKey为"cpu.hum"的行中,Qualifer为"name:metrics"的值为UID。表示当cpu.hum为metrics时,其UID为1
  • RowKey为"host"的行中,Qualifer为"name:tagk"的值为UID。表示当host为tagValue时,其UID为1

由于HBase的存储数据类型是Bytes,所以UID在存储时会被转换为3个字节长度的Bytes数组进行存储。

TUID:

对每一个Data Point,metrics、timestamp、tagKey和tagValue都是必要的构成元素。除timestamp外,metrics、tagKey和tagValue的UID就可组成一个TSUID,每一个TSUID关联一个时间序列,如下所示:

<metrics_UID><tagKey1_UID><tagValue1_UID>[...<tagKeyN_UID><tagValueN_UID>]

在上面的例子中就涉及两个TSUID,分别是:

2)tsdb

tsdb为存放OpenTSDB中所有数据记录的表,下面具体介绍tsdb的结构设计。

① RowKey设计

tsdb的HBase RowKey中包含主要组成部分为:盐值(Salt)、metrics名称、时间戳、tagKey、tagValue等部分。

在tsdb-uid中提到,为了统一各个值的长度以及节省空间,对metrics名称、tagKey和tagValue分配了UID信息。所以,在HBase RowKey中实际写入的是metrics UID、tagKey UID和tagValue UID(存放在tsdb-uid中)。

HBase RowKey的数据模型如下图所示:

  • SALT:建议开启SALT功能,可以有效提高性能。SALT数据的长度是变长的:如果SALT的值值少于256,那么只用一个字节表示即可;如果需要设置更大的SALT值,也会相应地占用更多的空间。
  • Metric ID:metrics名经过编码后,每个Metric ID的长度为三个字节。
  • Timestamp:这里整点小时级别的时间戳
  • tagKey UID & tagValue UID:tagKey和tagValue经过编码后,每个tagKey UID和tagValue UID的长度都为三个字节。tagKey UID和tagValue UID必须成对出现,最少必须存在1对,最多存在8对。

② Qualifier设计

Qualifier用于保存一个或多个DataPoint中的时间戳、数据类型、数据长度等信息。

由于时间戳中的小时级别的信息已经保存在RowKey中了,所以Qualifier只需要保存一个小时中具体某秒或某毫秒的信息即可,这样可以减少数据占用的空间。

一个小时中的某一秒(少于3600)最多需要2个字节即可表示,而某一毫秒(少于3600000)最多需要4个字节才可以表示。为了节省空间,OpenTSDB没有使用统一的长度,而是对特定的类型采用特性的编码方法。Qualifer的数据模型主要分为如下三种情况:秒、毫秒、秒和毫秒混合。

秒类型

当OpenTSDB接收到一个新的DataPoint的时候,如果请求中的时间戳是秒,那么就会插入一个如下模型的数据。

判断请求中的时间戳为秒或毫秒的方法是基于时间戳数值的大小,如果时间戳的值的超过无符号整数的最大值(即4个字节的长度),那么该时间戳是毫秒,否则为秒。

  • Value长度:Value的实际长度是Qualifier的最后3个bit的值加1,即(qualifier & 0x07) + 1。表示该时间戳对应的值的字节数。所以,值的字节数的范围是1到8个字节。
  • Value类型:Value的类型由Qualifier的倒数第4个bit表示,即(qualifier & 0x08)。如果值为1,表示Value的类型为float;如果值为0,表示Value的类型为long。
  • 时间戳:时间戳的值由Qualifier的第1到第12个bit表示,即(qualifier & 0xFFF0) >>>4。由于秒级的时间戳最大值不会大于3600,所以qualifer的第1个bit肯定不会是1。

毫秒类型

当OpenTSDB接收到一个新的DataPoint的时候,如果请求中的时间戳是毫秒,那么就会插入一个如下模型的数据。

  • Value长度:与秒类型相同。
  • Value类型:与秒类型相同。
  • 时间戳: 时间戳的值由Qualifier的第5到第26个bit表示,即(qualifier & 0x0FFFFFC0) >>>6。
  • 标志位:标志位由Qualifier的前4个bit表示。当该Qualifier表示毫秒级数据时,必须全为1,即(qualifier[0] & 0xF0) == 0xF0。
  • 第27到28个bit未使用。

混合类型

当同一小时的数据发生合并后,就会形成混合类型的Qualifier。

合并的方法很简单,就是按照时间戳顺序进行排序后,从小到大依次拼接秒类型和毫秒类型的Qualifier即可。

  • 秒类型和毫秒类型的数量没有限制,并且可以任意组合。
  • 不存在相同时间戳的数据,包括秒和毫秒的表示方式。

遍历混合类型中的所有DataPoint的方法是:

  • 从左到右,先判断前4个bit是否为0xF
  • 如果是,则当前DataPoint是毫秒型的,读取4个字节形成一个毫秒型的DataPoint
  • 如果否,则当前DataPoint是秒型的,读取2个字节形成一个秒型的DataPoint
  • 以此迭代即可遍历所有的DataPoint

 ③ Value设计

HBase Value部分用于保存一个或多个DataPoint的具体某个时间戳对应的值
由于在Qualifier中已经保存了DataPoint Value的类型和DataPoint Value的长度,所以无论是秒级还是毫秒级的值,都可以用相同的表示方法,而混合类型就是多个DataPoint Value的拼接。
HBase Value按照长度可以分为如下几种类型:
单字节:当DataPoint Value为long型,且大于等于-128(Byte.MIN_VALUE),且少于或等于127(Byte.MAX_VALUE)的时候,使用1个字节存储。
两字节:当DataPoint Value为long型,且大于等于-32768(Short.MIN_VALUE),且少于或等于32767(Short.MAX_VALUE)的时候,使用2个字节存储。
四字节:当DataPoint Value为long型,且大于等于0x80000000(Integer.MIN_VALUE),且少于或等于0x7FFFFFFF(Integer.MAX_VALUE)的时候,使用4个字节存储。
八字节:当DataPoint Value为long型,且不是上面三种类型的时候,使用8个字节存储。当DataPoint Value为float型的时候,使用8个字节表示。
多字节:
按照时间戳的顺序,把多个Value拼接起来的数据模型如下:

每个格子表示一个DataPoint Value的值,这个DataPoint Value的长度可能是1或2或4或8个字节。

DataPoint Value的顺序与Qualifier中时间戳的顺序一一对应。
混合标志:如果最后1个字节为0x01,表示存在秒级类型和毫秒级类型混合的情况。

  • 指标名字:这个就是我们监控的指标,比如 sys.cpu.user;

  • 时间戳:监控数据产生的时间;

  • 值:Long 或者 Double 类型的数据,这个是监控指标在某个时间的具体值;

  • 标签:包括标签名字(tagk)和标签值(tagv),比如 tagk1=tagv1,主要用于描述数据属性,每条时序数据必须包含一组和多组的标签数据。目前 OpenTSDB 最多支持8组标签。

参考:

OpenTSDB原理系列-元数据模型

OpenTSDB原理系列-TSDB数据表设计

OpenTSDB的数据模型

OpenTSDB在HBase中的底层数据结构设计的更多相关文章

  1. 使用bulkload向hbase中批量写入数据

    1.数据样式 写入之前,需要整理以下数据的格式,之后将数据保存到hdfs中,本例使用的样式如下(用tab分开): row1 N row2 M row3 B row4 V row5 N row6 M r ...

  2. 用Spark查询HBase中的表数据

    java代码如下: package db.query; import org.apache.commons.logging.Log; import org.apache.commons.logging ...

  3. hbase中double类型数据做累加

    public static Result incr(String tableFullName, String rowKey, String family, String qualifier, long ...

  4. Redis 底层数据结构设计

    10万+QPS 真的只是因为单线程和基于内存?_Howinfun的博客-CSDN博客_qps面试题 https://blog.csdn.net/Howinfun/article/details/105 ...

  5. 使用Hive或Impala执行SQL语句,对存储在HBase中的数据操作

    CSSDesk body { background-color: #2574b0; } /*! zybuluo */ article,aside,details,figcaption,figure,f ...

  6. talend 将hbase中数据导入到mysql中

    首先,解决talend连接hbase的问题: 公司使用的机器是HDP2.2的机器,上面配置好Hbase服务,在集群的/etc/hbase/conf/hbase-site.xml下,有如下配置: < ...

  7. HBase中的备份和故障恢复方法

    本文将对Apache HBase可用的数据备份机制和大量数据的故障恢复/容灾机制做简要介绍. 随着HBase在重要的商业系统中应用的大量添加,很多企业须要通过对它们的HBase集群建立健壮的备份和故障 ...

  8. hadoop生态系统学习之路(八)hbase与hive的数据同步以及hive与impala的数据同步

    在之前的博文中提到,hive的表数据是能够同步到impala中去的. 一般impala是提供实时查询操作的,像比較耗时的入库操作我们能够使用hive.然后再将数据同步到impala中.另外,我们也能够 ...

  9. 将HBase中的表加载到hive中

    两种方式加载hbase中的表到hive中,一是hive创建外部表关联hbase表数据,二是hive创建普通表将hbase的数据加载到本地 1. 创建外部表 hbase中已经有了一个test表,内容如下 ...

随机推荐

  1. VLC播放器:快捷键

     造冰箱的大熊猫@cnblogs 2019/2/27 VLC播放器(VLC Media Player)快捷键汇总(在Ubuntu 16.04环境下测试) - 音量大/小:CTRL+上/下 - 静音开/ ...

  2. go之基本数据类型

    一.整形 Go语言里支持有符号和无符号两种整型.这里的符号就是正负号. 1.分类: 有符号的整型:int , int8 , int16 , int32 , int64 无符号的整型:uint,uint ...

  3. HAOI2010软件安装

    首先tarjan缩点应该能看出来,然后我用topsort跑了个DAG上的一维dp,结果WA的很惨. 其实用DAG应该也能做,但是DAG强调整体顺序,而对一些局部问题,例如两个儿子怎么分配,是否给当前节 ...

  4. leetcode题目5.最长回文子串(中等)

    题目描述: 给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为 1000. 示例 1: 输入: "babad"输出: "bab"注意: ...

  5. SRS之RTMP连接处理线程conn:接收客户端推流

    由 SRS之RTMP的TCP线程 分析可知,SRS 接受客户端的连接后创建了一个线程:conn,用于处理与客户端的 RTMP 连接. 本文的分析是基于该配置文件的: listen 1935; max_ ...

  6. 【黑马JavaSE】1.1JavaSE、环境变量、CMD使用、常量、变量、数据类型转换(自动/强制)、ASCII码表、Unicode万国码表

    文章目录 SUN公司,詹姆斯.劳瑟琳,Java祖师爷 Java语言开发环境搭建 把Java添加到环境变量的方法 命令行CMD里一些报的错误 命令控制行常用操作的代码展示 Notepad++.注释.标识 ...

  7. vue中如何刷新页面

    vue中刷新页面的方法 1. 不能使用 this.$router.go(0) 或者 window.reload() 不起作用还特别恶心 这个才是有效果的刷新页面,只要照图敲,就能有效果 我们在 app ...

  8. 如何查看 SELinux状态及关闭SELinux

    查看SELinux状态: 1./usr/sbin/sestatus -v      ##如果SELinux status参数为enabled即为开启状态 SELinux status:         ...

  9. selenium expected_conditions 源码学习记录

    #expected_conditions模块收集了一系列的场景判断方法 #源码地址 # https://seleniumhq.github.io/selenium/docs/api/py/_modul ...

  10. LC 851. Loud and Rich

    In a group of N people (labelled 0, 1, 2, ..., N-1), each person has different amounts of money, and ...