当我们有数十亿计的监控数据需要高效地存储和检索时,关系型数据就无法支撑了. 这时需要从时间序列数据库中寻找解决方案. OpenTSDB 因写入速度快,支持水平扩展这些特点成为最知名的一种时间序列数据库, 但在生产环境下应用时,用户几乎一定会遇到下面几个坑,

食之无味的 Compaction 机制 #

OpenTSDB 将同一个时间序列一个小时的的多条记录存储在 HBase 一行当中, 用列名进行区分,逻辑上的结构是这样的

1
rowkey [c1:v1, c2:v2, c3:v3, …:…]

但 HBase 的物理存储结构却是这样的

1
2
3
4
rowkey [c1:v1]
rowkey [c2:v2]
rowkey [c3:v4]
... ...

假设某个时间序列一分钟产生一条数据,按上面这种存储方式在 1 个小时内 rowkey 被重复了 60 次,显然这对 TSDB 的读性能是有害的. 为了解决这个问题,OpenTSDB 引入了 Compaction 机制,即将一个小时内的多条记录合并成一条记录

1
rowkey [c1c2c3...:v1v2v3...]

这确实是一个好想法. 可为实现这一点, OpenTSDB 就要多做很多工作了. 第一步:将数据正常写入 HBase, 同时记录下 rowkey. 第二步:每当到整点时,根据 rowkey 读取所有上一个小时写入 HBase 的数据,在内存中完成合并. 第三步:删除原来的数据. 第四步:将合并后的数据写入 HBase.

Compaction 机制是想在写入性能与读取性能之间做个平衡, 现实情况不尽如意. 根据生产环境下收集到的数据来看,这些额外的工作使得 OpenTSDB 总体写入性能下降了三分之二. 更麻烦的是如果某时间段入库量突增,该机制会后让 OpenTSDB 整点之后压力成倍放大。甚至进入 “死亡螺旋” 状态

OpenTSDB 2.2 引入了 Appends 机制, 试图通过 HBase 的 AtomicAppend 操作, 一步完成写入与合并动作。遗憾的是 HBase 的 AtomicAppend 操作性能十分低下。不具有实际应用价值.

所以在生产环境下最好关闭 OpenTSDB Compaction 机制,转而通过缓存与分段查询提高其读性能。

捉襟见肘的合法字符集 #

假设我们有 PV 这个指标,想存到 OpenTSDB 中去, 对不起, 这是办不到的. OpenTSDB 只支持 a-z, A-Z, 0-9,-, _, ., / 这些字符作为 metric 和 tags 合法字符.

1
2
3
4
5
{
"metric": "pv",
"tags": {"url": "http://www.example.com/about"},
"value": 5793
}

始终缺席的 rollup 机制 #

数据既然写到数据库里了,终究还是要查询的,要不就成了 WOM 了, 呃,但

效率优先, 准确其次的计算顺序 #

OpenTSDB 的内部计算顺序为