一、背景介绍
此次航天局为了让天宫一号与神舟九号载人交会顺利对接成功,采用了新一代数值天气预报系统为神九保驾护航。新一代数值天气预报系统是中国国内技术最先进、分辨率最高、预报时效最长的数值天气预报系统。新系统在火箭燃料加注、飞船发射和返回、载人交会对接等关键节点发挥重要作用。 同样,作为后台系统或网站的运维,我们同样需要类似的监控或预报系统快速发现各种不稳定现象和解决性能问题以达到SLA(服务等级协议)的标准。
你有没有厌倦那个拥有10年以上寿命的监控系统?它常常会出现这样的问题:1)中心化数据存储进而导致单点故障。2)有限的存储空间。3)数据会因为时间问题而变得不准确。4)不易于定制图形。5)不能扩展采集数据点到100亿级别。6)不能扩展metrics到K级别。7)不支持秒级别的数据。
这里介绍一淘使用的一个开源监控系统OpenTSDB,它可以解决上面的问题,它用hbase存储所有的时序(无须采样)来构建一个分布式、可伸缩的时间序列数据库。它支持秒级数据采集所有metrics,支持永久存储,可以做容量规划,并很容易的接入到现有的报警系统里。OpenTSDB可以从大规模的集群(包括集群中的网络设备、操作系统、应用程序)中获取相应的metrics并进行存储、索引以及服务,从而使得这些数据更容易让人理解,如web化,图形化等。
对于运维工程师而言,OpenTSDB可以获取基础设施和服务的实时状态信息,展示集群的各种软硬件错误,性能变化以及性能瓶颈。对于管理者而言,OpenTSDB可以衡量系统的SLA,理解复杂系统间的相互作用,展示资源消耗情况。集群的整体作业情况,可以用以辅助预算和集群资源协调。对于开发者而言,OpenTSDB可以展示集群的主要性能瓶颈,经常出现的错误,从而可以着力重点解决重要问题。
二、架构Overview
openTSDB(见图1) 【1】 使用hbase作为存储中心,它无须采样,可以完整的收集和存储上亿的数据点,支持秒级别的数据监控,得益于hbase的分布式列式存储,hbase可以灵活的支持metrics的增加,可以支持上万机器和上亿数据点的采集。在openTSDB中,TSD是hbase对外通信的daemon程序,没有master/slave之分,也没有共享状态,因此利用这点和hbase集群的特点就可以消除单点。用户可以通过telnet或者http协议直接访问TSD接口,也可以通过rpc访问TSD。每一个需要获取metrics的Servers都需要设置一个Collector用来收集时间序列数据。这个Collector就是你收集数据的脚本。
图1、openTSDB的数据流图
如果想快速地展示mysql中在一段时间内执行delete子句的数量,慢查询的数量,创建的临时文件数量以及99%的延迟数量等等。OpenTSDB则可以非常容易存储和处理百万级别以上的数据点,并能实时动态的生成对应的图,如图2 【1】 。
图2、OpenTSDB用例图
三、在hbase中存储时间序列
OpenTSDB使用async hbase 【2】 ,这是个完全异步、非阻塞、线程安全、HBase api,使用更少的线程、锁以及内存可以提供更高的吞吐量,特别对于大量的写操作。图3为读写流程 【1】 。
图3、读写路径
在hbase中,表结构的设计对性能具有很大的影响,其中tsdb-uid表和tsdb表见表一和表二 【1】 。
表1、tsdb-uid
表2、tsdb
四、一淘的实例
在我们的搜索引擎中,随着业务的发展和扩张,使得流量快速增长以及业务逻辑变得越来越复杂。进而使得引擎随时都会出现各种瓶颈,因此提前知道引擎的变化状态显得尤为重要,如全量和增量的增长趋势图,见图4。
图4、OpenTSDB用例图
在OpenTSDB,一个数据点可以表示为:1)一个指标名称。2)UNIX时间戳。3)一个值(64位整数或双精度浮点值)。4)标识这个数据点的一组标记tags(键-值对)。
下面四个数据点来源于图4,都是采集的metrics为index.full_count,代表引擎索引doc数;标记tags为来自哪个domain(代表机房),area和app代表应用,cluster代表索引表,partition代表列。Metrics和tags加起来就是一个时间序列。图3为一系列下面的数据点绘画而成(数据经过了处理,不代表真实数据)。
index.full_count 1341069600 156866750 domain=domain_E area=1 app=jqb cluster=epid partition=partition_16384_32767
index.full_count 1341069600 155819640 domain=domain_E area=1 app=jqb cluster=epid partition=partition_32768_49151
index.full_size 1341069000 18561 domain=domain_D area=1 app=jqb cluster=b2c partition=partition_0_16383
index.full_size 1341069000 18554 domain=domain_D area=1 app=jqb cluster=b2c partition=partition_16384_32767
index.full_count 1341069200 11421051 domain=domain_G area=1 app=jqb cluster=b2c partition=partition_16384_32767
那如何收集这些数据呢,Etao在tcollector 【3】 开源收集器的基础上,做第二次开发,见图5。tcollector可以完成:1)可以任意添加你的收集脚本程序,并收集所有数据。2)完成发送数据到TSD的所有连接管理。3)初始化一些状态,执行一些公共的部分,比如定时管理执行1min文件夹下面的脚本。4)删除重复的数据。5)支持很多种数据交换协议,提供良好的扩展性。
图5、etao-tcollector
将etao-tcollector部署在所有机器上(可采用集中运维脚本进行远程部署,并可通过该系统远程控制收集器的启停)。etao-tcollector会将带时间和metrics的时间序列数据发送到tsd,之后的处理见第三节的图3,最后我们在Opentsdb提供的web UI上通过指定查询条件进行查询获取相应的图形用来对应用进行监控。
该etao-tcollector在一淘引擎中用来收集索引相关信息,引擎服务状态如延迟,日志等。
六、小结
openTSDB采用hbase作为时序数据的存储中心,具有高扩展性,metrics添加相当灵活,且对数据可以无损的存储。可以很灵活的支持数据分析,图形显示以及一系列定制化操作,非常方便运维人员做运维监控。
参考文献:
[1] http://opentsdb.net/overview.html
[2] https://github.com/stumbleupon/asynchbase
[3] https://github.com/stumbleupon/tcollector
文章来源:http://www.searchtb.com/2012/07/opentsdb-monitoring-system.html
OpenTSDB 用HBase存储所有的时序(无须采样)来构建一个 分布式、可伸缩的时间序列数据库 。它支持秒级数据采集所有metrics,支持永久存储,可以做容量规划,并很容易的接入到现有的报警系统里。OpenTSDB可以从大规模的集群(包括集群中的网络设备、操作系统、应用程序)中获取相应的metrics并进行存储、索引以及服务,从而使得这些数据更容易让人理解,如web化、图形化等。
对于运维工程师而言,OpenTSDB可以获取基础设施和服务的实时状态信息,展示集群的各种软硬件错误,性能变化以及性能瓶颈。对于管理者而言,OpenTSDB可以衡量系统的SLA,理解复杂系统间的相互作用,展示资源消耗情况。集群的整体作业情况,可以用以辅助预算和集群资源协调。对于开发者而言,OpenTSDB可以展示集群的主要性能瓶颈,经常出现的错误,从而可以着力重点解决重要问题。
OpenTSDB使用LGPLv2.1+开源协议,目前版本为2.X。
OpenTSDB依赖jdk和 Gnuplot ,Gnuplot需要提前安装,版本要求为最小4.2,最大4.4,执行以下命令安装即可:
yum install gnuplot autoconf
apt-get install gnuplot
OpenTSDB是用java编写的,但是项目构建不是用的java的方式而是使用的C、C++程序员构建项目的方式。运行时依赖:
可选的编译时依赖:
可选的单元测试依赖:
首先安装必要依赖:
yum install gnuplot automake autoconf git -y
下载源代码,可以指定最新版本或者手动checkout
git clone git://github.com/OpenTSDB/opentsdb.git cd opentsdb ./build.sh
COMPRESSION
和 HBASE_HOME
,前者设置是否启用压缩,或者设置hbase home目录。如果使用压缩,则还需要安装lzosrc/create_table.sh
tsdtmp=${TMPDIR-'/tmp'}/tsd # For best performance, make sure mkdir -p "$tsdtmp" # your temporary directory uses tmpfs ./build/tsdb tsd --port=4242 --staticroot=build/staticroot --cachedir="$tsdtmp" --auto-metric
如果你使用的是hbase集群,则你还需要设置 --zkquorum
, --cachedir
对应的目录会产生一些临时文件,你可以设置cron定时任务进行删除。添加 --auto-metric
,则当新的数据被搜集时自动创建指标。
你可以将这些参数编写到配置文件中,然后通过 --config
指定该文件所在路径。
从源代码安装gnuplot、autoconf、opentsdb以及tcollector,可以参考: OpenTSDB & tcollector 安装部署(Installation and Deployment)
OpenTSDB的配置参数可以在命令行指定,也可以在配置文件中指定。配置文件使用的是java的properties文件,文件中key为小写,支持逗号连接字符串但是不能有空格。所有的OpenTSDB属性都以tsdb开头,例如:
# List of Zookeeper hosts that manage the HBase cluster
tsd.storage.hbase.zk_quorum = 192.168.1.100
配置参数优先级:
命令行参数 > 配置文件 > 默认值
你可以在命令行中通过 --config
指定配置文件所在路径,如果没有指定,OpenTSDB会从以下路径寻找配置文件:
如果一个合法的配置文件没有找到并且一些必须参数没有设置,TSD进程将不会启动。
配置文件中可配置的属性请参考: Properties
在深入理解OpenTSDB之前,需要了解一些基本概念。
在OpenTSDB中拥有高基数的指标在查询过程中返回的值要多于低基数的指标,这样花费的时间也就越多。
Compaction 。在OpenTSDB中,会将多列合并到一列之中以减少磁盘占用空间,这和hbase中的Compaction不一样。这个过程会在TSD写数据或者查询过程中不定期的发生。
Data Point 。每一个指标可以被记录为某一个时间点的一个数值。Data Point包括以下部分:
Metric 。一个可测量的单位的标称。 metric
不包括一个数值或一个时间,其仅仅是一个标签,包含数值和时间的叫 datapoints
,metric是用逗号连接的不允许有空格,例如:
Tags 。一个metric应该描述什么东西被测量,在OpenTSDB中,其不应该定义的太简单。通常,更好的做法是用Tags来描述具有相同维度的metric。Tags由tagk和tagv组成,前者表示一个分组,后者表示一个特定的项。
Time Series 。一个metric的带有多个tag的data point集合。
Timestamp 。一个绝对时间,用来描述一个数值或者一个给定的metric是在什么时候定义的。
Value 。一个Value表示一个metric的实际数值。
UID 。在OpenTSDB中,每一个metric、tagk或者tagv在创建的时候被分配一个唯一标识叫做UID,他们组合在一起可以创建一个序列的UID或者 TSUID
。在OpenTSDB的存储中,对于每一个metric、tagk或者tagv都存在从0开始的计数器,每来一个新的metric、tagk或者tagv,对应的计数器就会加1。当data point写到TSD时,UID是自动分配的。你也可以手动分配UID,前提是 auto metric
被设置为true。默认地,UID被编码为3Bytes,每一种UID类型最多可以有16,777,215个UID。你也可以修改源代码改为4Bytes。UID的展示有几种方式,最常见的方式是通过http api访问时,3 bytes的UID被编码为16进制的字符串。例如,UID为1的写为二进制的形式为 ,最为一个无符号的byte数组,其可以表示为 [0,0,1]
,编码为16进制字符串为 ,其中每一位左边都被补上0,如果其不足两位。故,UID为255的会显示为 [0,0,255]
和 0000FF
。
关于为什么使用UID而不使用hashes,可以参考: why-uids
TSUID 。当一个data point被写到OpenTSDB时,其row key格式为:
,不考虑时间戳的话,将其余部分都转换为UID,然后拼在一起,就可以组成为TSUID。
Metadata 。主要用于记录data point的一些附加的信息,方便搜索和跟踪,分为UIDMeta和TSMeta。
每一个UID都有一个metadata记录保存在 tsdb-uid
表中,每一个UID包括一些不可变的字段,如 uid
、 type
、 name
和 created
字段表示什么时候被创建,还可以有一些额外字段,如 description
、 notes
、 displayName
和一些 custom
key/value对,详细信息,可以查看 /api/uid/uidmeta
同样,每一个TSUID可以对应一个TSMeta,记录在 tsdb-uid
中,其包括的字段有tsuid
、 metric
、 tags
、 lastReceived
和 created
,可选的字段有 description
, notes
,详细信息,可以查看 /api/uid/tsmeta
开启Metadata有以下几个参数:
tsd.core.meta.enable_realtime_uid
tsd.core.meta.enable_tsuid_tracking
tsd.core.meta.enable_tsuid_incrementing
tsd.core.meta.enable_realtime_ts
metadata的另外一个形式是 Annotations
,详细说明,请参考 annotations
Tree
OpenTSDB使用HBase作为后端存储,在安装OpenTSDB之前,需要先启动一个hbase节点或者集群,然后再执行建表语句 src/create_table.sh
创建hbase表。建表语句如下:
create '$UID_TABLE', {NAME => 'id', COMPRESSION => '$COMPRESSION', BLOOMFILTER => '$BLOOMFILTER'}, {NAME => 'name', COMPRESSION => '$COMPRESSION', BLOOMFILTER => '$BLOOMFILTER'} create '$TSDB_TABLE', {NAME => 't', VERSIONS => 1, COMPRESSION => '$COMPRESSION', BLOOMFILTER => '$BLOOMFILTER'} create '$TREE_TABLE', {NAME => 't', VERSIONS => 1, COMPRESSION => '$COMPRESSION', BLOOMFILTER => '$BLOOMFILTER'} create '$META_TABLE', {NAME => 'name', COMPRESSION => '$COMPRESSION', BLOOMFILTER => '$BLOOMFILTER'}
从上面可以看出一共创建了4张表,并且可以设置是否压缩、是否启用布隆过滤、保存版本号等等,如果追求hbase读写性能,还可以预建分区。
在OpenTSDB中,所有数据存储在一张叫做 tsdb
的表中,这是为了充分利用hbase有序和region分布式的特点。所有的值都保存在列族 t
中。
rowkey为
,UID默认编码为3 Bytes,而时间戳会编码为4 Bytes
OpenTSDB的tsdb启动之后,会监控指定的socket端口(默认为4242),接收到监控数据,包括指标、时间戳、数据、tag标签,tag标签包括tag名称ID和tag值ID。例如:
myservice.latency.avg 1292148123 42 reqtype=foo host=web42
对于指标myservice.latency.avg的ID为:[0, 0, -69],reqtype标签名称的ID为:[0, 0, 1], foo标签值的ID为:[0, 1, 11], 标签名称的ID为:[0, 0, 2] web42标签值的ID为:[0, -7, 42],他们组成rowkey:
[0, 0, -69, 77, 4, -99, 32, 0, 0, 1, 0, 1, 11, 0, 0, 2, 0, -7, 42] `-------' `------------' `-----' `------' `-----' `-------' metric ID base timestamp name ID value ID name ID value ID `---------------' `---------------' first tag second tag
row表示格式为: 每个数字对应1 byte
NOTE :可以看到,对于metric + tags相同的数据都会连续存放,且metic相同的数据也会连续存放,这样对于scan以及做aggregation都非常有帮助
column qualifier 占用2 bytes或者4 bytes,占用2 bytes时表示以秒为单位的偏移,格式为:
占用4 bytes时表示以毫秒为单位的偏移,格式为:
F
举例:
对于时间戳为1292148123的数据点来说,其转换为以小时为单位的基准时间(去掉小时后的秒)为129214800,偏移为123,转换为二进制为 ,因为该值为整数且长度为8位(对应为2byte,故最后3bit为 ),故其对应的列族名为: ,将其转换为十六进制为 07B4
value 使用8bytes存储,既可以存储long,也可以存储double。
总结一下, tsdb
表结构如下:
一个单独的较小的表叫做 tsdb-uid
用来存储UID映射,包括正向的和反向的。存在两列族,一列族叫做 name
用来将一个UID映射到一个字符串,另一个列族叫做 id
,用来将字符串映射到UID。列族的每一行都至少有以下三列中的一个:
metrics
将metric的名称映射到UIDtagk
将tag名称映射到UIDtagv
将tag的值映射到UID如果配置了metadata,则 name
列族还可以包括额外的metatata列。
Row Key - 将会是一个分配到UID的字符串,例如,对于一个指标可能有一个值为 sys.cpu.user
或者对于一个标签其值可能为
Column Qualifiers - 上面三种列类型中一种。
Column Value - 一个无符号的整数,默认被编码为3个byte,其值为UID。
例如以下几行数据是从 tsdb-uid
表中查询出来的数据,第一个列为row key,第二列为”列族:列名”,第三列为值,对应为UID
proc.stat.cpu id:metrics \x00\x00\x01 host id:tagk \x00\x00\x01 cdh1 id:tagv \x00\x00\x01
Row Key - 为UID
Column Qualifiers - 上面三种列类型中一种或者为 metrics_meta
、 tagk_meta
、 tagv_meta
Column Value - 与UID对应的字符串,对于一个 *_meta
列,其值将会是一个UTF-8编码的JSON格式字符串。不要在OpenTSDB外部去修改该值,其中的字段顺序会影响CAS
调用。
例如,以下几行数据是从 tsdb-uid
表中查询出来的数据,第一个列为row key,第二列为”列族:列名”,第三列为值,对应为UID
\x00\x00\x01 name:metrics proc.stat.cpu \x00\x00\x01 name:tagk host \x00\x00\x01 name:tagv cdh1 \x00\x00\x01 name:tagk_meta {"uid":"000001","type":"TAGK","name":"host","description":"","notes":"","created":1395213193,"custom":null,"displayName":""} \x00\x00\x01 name:tagv_meta {"uid":"000001","type":"TAGV","name":"cdh1","description":"","notes":"","created":1395213193,"custom":null,"displayName":""} \x00\x00\x01 name:metric_meta {"uid":"000001","type":"METRIC","name":"metrics proc.stat.cpu","description":"","notes":"","created":1395213193,"custom":null,"displayName":""}
总结一下, tsdb-uid
表结构如下:
上图对应的一个datapoint如下:
proc.stat.cpu 1292148123 80 host=cdh1
从上图可以看出 tsdb-uid
的表结构以及数据存储方式,对于一个data point来说,其被保存到opentsdb之前,会对 metrics
、 tagk
、 tagv
、 metric_meta
、 tagk_meta
、 tagv_meta
生成一个UID(如上图中的 ),然后将其插入hbase表中,rowkey为UID,同时会存储多行记录,分别保存 metrics
、 tagk
、 tagv
、 metric_meta
、 tagk_meta
、 tagv_meta
到UID的映射。
这个表是OpenTSDB中不同时间序列的一个索引,可以用来存储一些额外的信息。这个表名称叫做 tsdb-meta
,该表只有一个列族 name
,两个列,分别为 ts_meta
、 ts_ctr
,该表中数据如下:
\x00\x00\x01\x00\x00\x01\x00\x00\x01 name:ts_ctr \x00\x00\x00\x00\x00\x00\x00p \x00\x00\x01\x00\x00\x01\x00\x00\x01 name:ts_meta {"tsuid":"000001000001000001","displayName":"","description":"","notes":"","created":1395213196,"custom":null,"units":"","dataType":"","retention":0,"max":"NaN","min":"NaN"} \x00\x00\x02\x00\x00\x01\x00\x00\x01 name:ts_ctr \x00\x00\x00\x00\x00\x00\x00p \x00\x00\x02\x00\x00\x01\x00\x00\x01 name:ts_meta {"tsuid":"000002000001000001","displayName":"","description":"","notes":"","created":1395213196,"custom":null,"units":"","dataType":"","retention":0,"max":"NaN","min":"NaN"}
Row Key 和 tsdb
表一样,其中不包含时间戳,
TSMeta Column 和UIDMeta相似,其为UTF-8编码的JSON格式字符串
ts_ctr Column 计数器,用来记录一个时间序列中存储的数据个数,其列名为 ts_ctr
,为8位有符号的整数。
索引表,用于展示树状结构的,类似于文件系统,以方便其他系统使用,例如: Graphite
tsdb支持以下参数:
[root@cdh1 build]# ./tsdb
usage: tsdb <command> [args]
Valid commands: fsck, import, mkmetric, query, tsd, scan, uid
通过以下命令创建指标:
./tsdb mkmetric mysql.bytes_received mysql.bytes_sent
执行上述命令的结果如下:
metrics mysql.bytes_received: [0, 0, -93] metrics mysql.bytes_sent: [0, 0, -92]
KairosDB是一个快速可靠的分布式时间序列数据库,主要用于Cassandra当然也可以适用与HBase。KairosDB是在OpenTSDB基础上重写的,他不仅可以在HBase上存储数据还支持Cassandra。
KairosDB主页: https://code.google.com/p/kairosdb/
转自:http://blog.javachen.com/2014/01/22/all-things-opentsdb/#
文章标题: 本文地址: 除非注明,博客文章均为"运维生存时间"原创,转载请标明本文地址 运维圈子期待您的加入(Q群:39514058
文章来源:http://www.ttlsa.com/opentsdb/opentsdb-comments/