OpenTSDB介绍

参考:
http://opentsdb.net/docs/build/html/index.html
https://github.com/OpenTSDB/asynchbase
 

前言

OpenTSDB is a distributed, scalable Time Series Database (TSDB) written on top of HBase。即OpenTSDB是一个基于HBase的分布式的,可伸缩的时间序列数据库。其一般存储时间上连续的数据,了解到的比较多的公司是将其用作运维监控系统,其可以从大规模的集群中获取相应的metrics(包括集群中的网络设备、操作系统、应用程序)并进行存储、索引以及服务化,从而使得这些数据更容易让人理解、使用。对于运维工程师而言,OpenTSDB可以获取基础设施和服务的实时状态信息,展示集群的各种软硬件异常、性能变化等。对于开发者而言,OpenTSDB可以展示集群的主要性能瓶颈,经常出现的错误,从而可以着力重点解决重要问题、系统调优等。对于管理者而言,OpenTSDB可以衡量系统的SLA,了解资源消耗情况等。

       同时OpenTSDB还具有很多设计上的优势,接下来我们会对其设计原理做一个整体的介绍。

相关概念

我们以一个监控系统的背景来介绍这些概念。比如我们需要记录的数据是一个集群里面各个服务器磁盘的使用率。

  1. Metric:监控项,这里就是磁盘的使用率。
  2. Tags:就是一些标签,在OpenTSDB里面,Tags由tagk和tagv组成,即tagk=takv。标签是用来描述Metric的,也可以说是用来区分各个Metric,比如一个集群里有多台电脑,我们需要用主机名来区分,这里tagk为hostname,tagv即为各个主机号。Tags可以有多个
  3. Value:一个value就是一个metric对应的实际值,比如磁盘使用率50%。
  4. Timestamp:用以表示这条数据是什么时候的。
  5. DataPoint:包含以上四个部分。

在OpenTSDB里面存储的就是多个DataPoint。

整体储存设计

OpenTSDB它的设计思路主要有两个,一是将一个维度一段时间的数据聚在一起,二是使用定长字典值压缩数据,主要依赖两张HBase表实现,tsdb和tsdb-uid。

表 tsdb包含一个列族“t”,tsdb-uid包含两个列族”id”和“name“,在HBase中列族名字越短,所占用的字节数也就越短,越有利于存储;tsdb是我们存放数据的表,tsdb-uid是 tsdb 的辅助表,用于查找uid对应的指标或者指标对应的uid。

假设我们要存放以下的数据:

metric:proc.loadavg.1m

timestamp:1234567890

value:0.42

扫描二维码关注公众号,回复: 2839829 查看本文章

tags:host=web42,pool=static

  1. 表tsdb:

  • RowKey的设计:

RowKey的设计是metric+timestamp+value+tagk=tagv。但是OpenTSDB并不是简单地将这些数据组合起来,OpenTSDB为了节省存储空间,将每个部分都做了映射。

这里面除了timestamp,每一项都在uid表中有一个映射。默认是每一个值都映射到一个3字节的整数,就是24位,223是8百多万,但是我们可以自己配置字节数,比如我们可以用四个字节,那就是几十亿的数据量。

这里映射关系为:proc.loadavg.1m-->052、host-->001、web42-->028、pool-->047、static-->001。

这样Rowkey的设计还有一个好处,就是各个项的长度是固定的,对于原来的每一个metric,tag key,tag value的长度都是不固定的,这不利于通过字节偏移量来直接定位它们。(否则需要使用特定的分隔符来对各个项进行分割,而且为了避免输入信息中可能存在特定的分隔符导致解析出错,还要对所有输入信息的分割符进行转义处理)

  • Column的设计:

列的设计依赖于timestamp,如果我们的将一行数据表示为一个小时的,那么我们将timestamp除以小时(3600),就可以得到这条数据是哪一个小时,余数作为列名。那么1234567890得到的是1234566000,余数1890。那么1234566000会放在rowKey中,1890会作为列名。表示这条数据是在这个小时里面的第1890秒。

这里的设计是充分利用了HBase列可以动态扩充的特点。我们并不知道这一个小时会有多少条数据,但是同一时间段来的数据余数肯定不一样,我们就可以不断地添加列。

  2. 表tsdb-uid

tsdb-uid这里其实保存的就是一些metric,tagk,tagv的一些映射关系。结构如下图

他有两个列族,其中列族name将uid映射到一个字符串,这里的uid就是我们在tsdb表中用作rowkey的;列族id则是将字符串映射到uid。这两个列族的数据其实是相互对应的,两者存储的值和rowKey是互反的。

这里再说明一下这张表的作用:前面说过这是一张辅助表,他就是存储一些映射关系。但是由于这张表的存在,可以节省空间。我们的metric,tag会在数据中重复出现多次,但是它在tsdb-uid这张表中只会存一次,并且会有一个唯一的uid与之对应。这样在tsdb中再存储这个数据的时候,我们反复存储的就不是这个值而是这个uid,很多情况下这个uid的长度远远小于这个值的长度,这样就在一定程度上节省了很多空间。

同时我们在前面提到的这里的uid默认是3字节整数,223是8百多万,但是这个数据并不是说我们只能存储8百多万条数,而是8百多万种数据(这个数据量是指metric或是tag的种类),前一段提过相同的metric和tag对应的是同一个uid,而223是说可以有这个量的uid存在,而这些uid可以对应多少条数据取决于数据中数据项的重复程度。

优势体现

  • 节省空间:在tsdb-uid表中我们已经解释过我们使用uid来代替原来本应存储的值,这在一定程度节省了空间。
  • 提升查询效率:OpenTSDB采用宽表存储,以下两张图可以理解宽表存储的含义。

就是我们提到的将一个时间段的数据用一行表示,用多列来记录各个时间点的数据。Row的数量大大减少,可以提升查询的效率,主要是以下两点:

      1.HFile中meta block中会存储bloom filter,用来判定特定的rowkey是否在HFile中。随着row数量的减少,bloom filter的体积会显著减小,因为bloom filter entry的生成是以row为单位。

      2.HBase中除了rowkey作为检索条件,还可以利用filter在rowkey,keyvalue的集合上进行过滤。在filter执行的早期阶段进行rowkey的比较,如果发现整个row不符合条件,能迅速跳过大量keyvalue,减少filter比对的次数。

  • 分散数据到不同的region:

OpenTSDB处理的是典型的时间序列化数据,必然面临“热点”问题,一般来说,如果使用时间做rowkey,那么前面就必须加“哈希”字段。但是OpenTSDB并没有加特别的哈希字段,OpenTSDB中时间字段不会放在rowkey的开始位置,其次,rowkey开始位置挑选了自身的一个的“metric"来替代了“哈希”字段。

从OpenTSDB的处理上我们可以总结出一点:在处理时间序列数据时,如果系统中存在“理想的”“天然的”起哈希作用的字段应该优先考虑其作为rowkey的起始组成部分,后接时间字段,但如果找不到这样的字段再设置人工的哈希字段。

  • 使用asynchbase客户端:

HBase的原生java 客户端是完全同步的,当你使用原生API 例如HTableInterface 访问HBase表,HBase响应请求的每一个动作都会短时间地堵塞你的应用进程,这种行为常常不能令人满意,这对于一些流程较长的操作看起来比较不利,一些应用不想在服务器上等待响应,而是希望继续执行路径。

HBase在此还提供了另外一种java客户端 asynchbase,asynchbase是完全异步、非阻塞、线程安全的HBase客户端,使用更少的线程、锁以及内存,可以提供更高的吞吐量,特别对于大量的写操作。OpenTSDB采用的就是asynchbase客户端。

总结

以上是对OpenTSDB做的一个简单的介绍,主要介绍了它整体的存储设计以及它的优势。

猜你喜欢

转载自blog.csdn.net/yulin_Hu/article/details/81805858