一、OpenTSDB原理
随着互联网、尤其是物联网的发展,我们需要把各种类型的终端实时监测、检查与分析设备所采集、产生的数据记录下来,在有时间的坐标中将这些数据连点成线,往过去看可以做成多纬度报表,揭示其趋势性、规律性、异常性;往未来看可以做大数据分析,机器学习,实现预测和预警。
这些数据的典型特点是:产生频率快(每一个监测点一秒钟内可产生多条数据)、严重依赖于采集时间(每一条数据均要求对应唯一的时间)、测点多信息量大(实时监测系统均有成千上万的监测点,监测点每秒钟都产生数据,每天产生几十GB的数据量)。
基于时间序列数据的特点,关系型数据库无法满足对时间序列数据的有效存储与处理,因此迫切需要一种专门针对时间序列数据来做优化处理的数据库系统。
时序数据库就是存放时序数据的数据库,并且需要支持时序数据的快速写入、持久化、多纬度的聚合查询等基本功能。对比传统数据库仅仅记录了数据的当前值,时序数据库则记录了所有的历史数据。同时时序数据的查询也总是会带上时间作为过滤条件。
时序数据,股票的变化趋势、温度的变化趋势、系统某个指标的变化趋势……其实都是时序数据,就是每个时间点上纪录一条数据。 关于数据的存储,我们最熟悉的就是mysql了,但是想想看,每5分钟存储一个点,一天288个点,一年就10万+,这还是单个维度,往往在实际应用中维度会非常多,比如股票交易所,成千上万支股票,每天所有股票数据就可能超过百万条,如果还得支持历史数据查询,mysql是远远扛不住的,必然要考虑分布式存储,最好的选择就是Hbase了,事实上业内基本上也是这么做的。
Hbase可通过加机器的水平扩展迅速增加读写能力,非常适合存储海量的数据,但是它并不是关系数据库,无法进行类似mysql那种select、join等操作,取而代之的只有非常简单的Get和Scan两种数据查询方式。总之,你可以通过Get获取到hbase里的一行数据,通过Scan来查询其中RowKey在某个范围里的一批数据。如此简单的查询方式虽然让hbase变得简单易用, 但也限制了它的使用场景。针对时序数据,只有get和scan远远满足不了你的需求。
这个时候OpenTSDB就应运而生。 首先它做了数据存储的优化,可以大幅度提升数据查询的效率和减少存储空间的使用。其次它基于hbase做了常用时序数据查询的API,比如数据的聚合、过滤等。另外它也针对数据热度倾斜做了优化。
1、OpenTSDB相关介绍
时间序列数据库:主要用来存储时间序列数据(数据格式里包含timestamp字段的数据),常常用来做监控预警数据的存储。
OpenTSDB是基于HBase存储时间序列数据的一个开源数据库,但只是一个HBase的应用而已。也即是在HBase之上加了一层外壳,用于更好的处理时序数据库,真实的数据存储还是在HBase。最新db-engines.com排行统计。
- 特点:
- 写多于读:95%-99%的操作都是写操作
- 顺序写:实时数据写入,多以追加的方式
- 很少更新:基本上不更新
- 区块删除:删除总是会删除一段时间的数据
- 毫无遗漏的接收并存储大量的时间序列数据。
- 主要用做监控系统;譬如收集大规模集群(包括网络设备、操作系统、应用程序)的监控数据并进行存储,查询。
-
存储
- 无需转换,写的是什么数据存的就是什么数据
- 时序数据以毫秒的精度保存
- 永久保留原始数据
-
扩展性
- 运行在Hadoop 和 HBase之上
- 可扩展到每秒数百万次写入
- 可以通过添加节点扩容
-
读能力
- 直接通过内置的GUI来生成图表
- 还可以通过HTTP API查询数据
- 另外还可以使用开源的前端与其交互
2、OpenTSDB架构原理
- Servers:就是服务器了,上面的C就是指Collector,可以理解为OpenTSDB的agent,通过Collector收集数据,推送数据;
- TSD:TSD是对外通信的无状态的服务器,Collector可以通过TSD简单的RPC协议推送监控数据;另外TSD还提供了一个web UI页面供数据查询;另外也可以通过脚本查询监控数据,对监控数据做报警
- HBase:TSD收到监控数据后,是通过AsyncHbase这个库来将数据写入到HBase;AsyncHbase是完全异步、非阻塞、线程安全的Hbase客户端,使用更少的线程、锁以及内存,可以提供更高的吞吐量,特别对于大量的写操作。
OpenTSDB是一个时间序列数据库,由一个 Time Series Daemon (TSD) 和一系列命令行实用程序组成。与OpenTSDB交互主要通过运行一个或者多个 TSD 来实现。每个 TSD 是独立的。没有master,没有共享状态,可以运行尽可能多的 TSD 来处理工作负载。
每个 TSD 使用开源数据库 HBase 或托管Google Bigtable服务来存储和检索时间序列数据。数据模式针对类似时间序列的快速聚合进行了高度优化,以最大限度的减少存储空间。
TSD 的用户不需要直接访问底层仓库。直接通过telnet协议,HTTP API 或者简单的内置 GUI 与 TSD 进行通信,所有的通信都发生在同一个端口上(TSD 通过查看接收到的前几个字节来计算出客户端的协议)
3、OpenTSDB存储原理
譬如,假设我们采集1个服务器(hostname=qatest)的CPU使用率,发现该服务器在21:00的时候,CPU使用率达到99%
- 1)Metric:即平时我们所说的监控项。譬如上面的CPU使用率
- 2)Tags:就是一些标签,在OpenTSDB里面,Tags由tagk和tagv组成,即tagk=takv。标签是用来描述Metric的,譬如上面为了标记是服务器A的CpuUsage,tags可为hostname=qatest
- 3)Value:一个Value表示一个metric的实际数值,譬如上面的99%
- 4)Timestamp:即时间戳,用来描述Value是什么时候的;譬如上面的21:00
Data Point:即某个Metric在某个时间点的数值。Data Point包括以下部分:Metric、Tags、Value、Timestamp。上面描述的服务器在21:00时候的cpu使用率,就是1个DataPoint,保存到OpenTSDB的,就是无数个DataPoint。
譬如,保存这样的1个DataPoint:
metric:proc.loadavg.1m
timestamp:1234567890
value:0.42
tags:host=web42,pool=static
Hbase去存,可能就是:RowKey=metric|timestamp|value|host=web42|pool=static
,Column=v
,Value=0.42
OpenTSDB使用HBase存储,核心的存储,是有两张表**,tsdb和tsdb-uid**,
tsdb表:保存数据;tsdb-uid表:保存的一些metric,tagk,tagv的映射关系。
(1) tsdb表
1)RowKey的设计
RowKey其实和上面的metric|timestamp|value|host=web42|pool=static类似;
但是区别是,OpenTSDB为了节省存储空间,将每个部分都做了映射。
在OpenTSDB里面有这样的映射,metric–>3字节整数、tagk–>3字节整数、tagv–>3字节整数
上图的映射关系为,proc.loadavg.1m–>052、host–>001、web42–>028、pool–>047、static–>001
若每秒存储一个数据点,每天就有86400个数据点,在hbase里就意味着86400行的数据,不仅浪费存储空间,而且还查起来慢,
OpenTSDB做了数据压缩上的优化,多行一列 转 一行多列,一行多列转一行一列。
数据开始写入时其实OpenTSDB还是一行一个数据点,如果用户开启了数据压缩的选项,OpenTSDB会在一个小时数据写完,或者查询某个小时数据时对其做多行转一行的数据压缩,压缩后那些独立的点数据就会被删除以节省存储空间。
多行一列 转 一行多列
原始数据可能长这样,一个小时总共有3600行的数据。
Opentsdb会将一个小时的数据合并到一个Rowkey里,相应的Rowkey里的timestamp也会归一化到哪个小时的时间戳。如下图。
通过这样转换后一个Rowkey就能查到一个小时的数据,一天24个Rowkey也就够了。在hbase中Qualifier是个两个Bytes的整数(如果是毫秒级数据是4个bytes),value是4-8 bytes的数值。
一行多列转一行一列
在2.2版本,opentsdb进一步对数据存储做了优化,把每个Row里的3600列合并成了一列,存储格式如下。
<offset1><value1><offset2><value2>...<offsetN><valueN>
就是位移量+值拼接在一起,opentsdb在这里并不要求这里的offset有序,查询的时候才会被排序。
2)column的设计
为了方便后期更进一步的节省空间。OpenTSDB将一个小时的数据,保存在一行里面。
所以上面的timestamp1234567890,会先模一下小时,得出1234566000,然后得到的余数为1890,表示的是它是在这个小时里面的第1890秒;
然后将1890作为column name,而0.42即为column value
(2) tsdb-uid表
opentsdb在构建Rowkey的时候并不是直接用原始值的,而是将metric、timesta、tagk、tagv分别用了一个3字节的uid做了替代(3字节意味着最多1600多万uid,大多数情况下应该够用了),可以减少Rowkey的存储空间。
所以这里需要有个表来做uid和真实值之间的转换,这个表就是tsdb-uid表。
tsdb-uid表中有两个列族,分别是uid-name的映射(name famlily),name-uid的映射(uid famliy)。另外还有一行特殊的数据,就是uid已分配情况记录表。
name-uid (name family)
Rowkey: name
Qualifiers: metric, tagk, tagv
value: name实际对应的uid值。
uid-name(id family)
Rowkey: uid
Qualifiers: metric, tagk, tagv
value: uid对应的实际name值
UID 分配行
这是一行非常特殊的数据,Rowkey为0x00,里面保存了metric、tagk、tagv已分配uid的最大值,每次新分配一个uid就会对其中相应的值增加1,这里用了hbase的原子操作,就是为了确保uid不重复。
(3) 数据查询的封装
OpenTSDB对hbase的读做很多的封装,方便实现更复杂切灵活的查询功能,我们来看下读接口的查询参数就能一窥究竟。
OpenTSDB在从底层hbase拿到数据后数据处理流程如下。
Filtering 过滤
Grouping 分组
Downsampling 数据缩放
Interpolation 数据改写
Aggregation 聚合
Rate Conversion 计算斜率
Functions 执行函数
Expressions 表达式运算
(4) 数据热点的解决
用hbase存过数据的人可能会知道,大多数时候数据分布是存在严重倾斜的,可能20%的metric会聚集80%的数据,甚至更严重。因为hbase把数据按照Rowkey增序存储在不同的机器上,所以这种数据切斜很可能会导致hbase集群某些机器读写压力非常大,但别的机器却没什么压力。
为了解决数据热点的问题,OpenTSDB在2.2版本增加了对数据做分桶的能力。其实就是对每行数据的tags做hash,然后把hash值拼接到Rowkey前面,这样就可以使同metric产生的rowkey分散开,减少数据热点发生的可能性。 可以通过以下两个参数开启salting功能。
tsd.storage.salt.width #桶宽度
tsd.storage.salt.buckets #设置最大多少个bucket
注意,不要突发奇想去开关这个功能,这个集群要么从始至终开这个功能要么不开。否则你中途开关,会导致操作前的数据无法查询。 另外还有一点,开启salting会影响查询性能,比如你想扫某个metric下所有数据,这个时候就得遍历所有的bucket。
二、OpenTSDB安装配置
1、安装环境
-
操作系统:CentOS Linux release 7.2.1511 (Core)
-
OpenTSDB版本:2.3.0
-
JDK版本:1.8.1_101
-
Apache HBase版本:1.2.2
2、安装部署
参考官方文档
(1)将opentsdb安装包下载到本地
wget https://github.com/OpenTSDB/opentsdb/releases/download/v2.3.0/opentsdb-2.3.0.rpm
执行以下命令进行安装:
yum localinstall opentsdb-2.3.0.rpm
OpenTSDB主要目录介绍:
- /etc/opentsdb —— 配置文件目录
- /usr/share/opentsdb —— 应用程序目录
- /usr/share/opentsdb/bin —— "tsdb"启动脚本目录
- /usr/share/opentsdb/lib —— Java JAR library
- /usr/share/opentsdb/plugins —— 插件和依赖
- /usr/share/opentsdb/static —— GUI 静态文件
- /usr/share/opentsdb/tools —— 脚本和其他工具
- /var/log/opentsdb —— 日志存放目录
安装包安装后包括一个init脚本 /etc/init.d/opentsdb ,此脚本可以 start,stop 和 restart OpenTSDB。简单地调用 service opentsdb start 启动和 service opentsdb stop 关闭。
注意,在安装之后,tsd 将不是运行状态,所以你能够编辑配置文件。编辑配置文件,然后启动 TSD。
(2)在hbase建表
如果你第一次用你的HBase实例运行OpenTSDB,你需要创建必要的HBase表。使用 /usr/share/opentsdb/tools/create_table.sh 脚本可以轻松建表。执行:
cd /usr/share/opentsdb/tools
env COMPRESSION=SNAPPY HBASE_HOME=/usr/hbase ./create_table.sh
COMPRESSION参数指定压缩方式,可选值是 NONE,LZO,GZIP,或者 SNAPPY 。这个命令将在指定的HBase中创建四张表:tsdb, tsdb-uid, tsdb-tree 和 tsdb-meta。如果你只是评估OpenTSDB,现在就不用关心压缩方式。在生产环境中,你要使用一个最合适的有效压缩库。
(3) 相关配置
编辑 /etc/opentsdb/opentsdb.conf 配置文件:
tsd.storage.hbase.zk_basedir = /hbase
tsd.storage.hbase.zk_quorum = node01:2181,node02:2181,node03:2181
提示:tsd.storage.hbase.zk_basedir 属性值参考 HBase 属性 zookeeper.znode.parent 的值