openTSDB源码详解之rowKey生成
openTSDB源码详解之rowKey生成
openTSDB的一个非常好的设计就是其rowKey的生成。下面详细介绍一下。
1.相关处理类
openTSDB往hbase中写入数据的处理过程,我之前就已经分析过,主要涉及的类有:
-
addPointInternal(...)
这里主要讲解的是,如何一个row key是如何生成的。
2.具体步骤
2.1 row_size的确定
2.1.2 SALT_WIDTH
首先对于一个rowKey,肯定是有大小的,但是这个rowKey的大小该怎么确定呢?因为这个rowKey是需要写入到HBase中的,也就是需要通过网络的传输才能到达HBase端,所以不可能无限长,即需要精确到一个具体的长度。
openTSDB中的rowKey的大小用变量row_size表示。其具体的生成规则如下图所示:其中的
SALT_WIDTH()
函数返回的是SALT WIDTH,它是一个static修饰的int型变量,初始值为0,如下图所示:
2.1.2 metric_width
,tag_name_width
,tag_value_width
metric_width
代表的就是metric
的长度。在openTSDB系统中,默认的长度是3。该值来自tsdb.metrics.width()
函数的返回值。
width()
方法如下:
而id_width的值设置过程如下:
调用构造函数UniqueId(...)
的过程如下:
最终可以看到这些值默认为3
针对笔者传输的数据,可以推导出最后生成的row_size的大小就是row_size = 0 + 3 + 4 + 3*1 + 3*1 = 13
,经过debug验证,也可以看到的确就是13。
2.2 字节数组row
2.3 pos
变量
问题1:使用pos
变量的原因是,控制对字节数组row的复制控制【每将一个值复制到row[]之后,就需要动态改变row[]的起始位置,这个位置就是pos定义的】
因为我没有开启 加盐处理功能,所以这里的pos的初始值就是0。
2.4 为字节数组row
赋值
上述copyInRowKey(…)的功能就是将metric对应的
uid
值放入到row
中。而其中的 getOrCreateId()
方法则是获取metric对应的uid
值。该方法主要调用的其它方法如下:
-
getIdAsync()
方法 -
从缓存中获取uid
-
Deferred 类的构造方法
-
copyInRowKey()
方法
注意上面一张图中row和下面一张图的row的变化。这个变化就体现了将metric的id放到了rowKey中。
2.3 pos
值的变化
因为已经处理了metric,所以需要将其pos自增一下。
同时,因为暂时不着急处理timestamp,所以再次将pos自增处理。
2.4 tag pair
的处理
最后,需要在row中放入 tag pair,方式是采用for循环处理。
主要调用方法如下:
-
resolveOrCreateAll()
-
resolveAllInternal()
方法
2.5 row
的大致部分
经过上述几个步骤的处理,则会生成一个row值:
2.6 rowKey
的完善
上述的步骤只是生成了一个rowKey的框架,但是还没有完全生成一个rowKey,因为还有最后一个步骤。接着会进入WriteCB
这个回调类,如下:
注意这里的offset的取值:metrics.width() + Const.SALT_WIDTH()
这个是用于将当前value所在小时的时间戳放入到row中。所以需要偏移metrics.width() + Const.SALT_WIDTH()
这样的长度。这里使用base_time = 1542096000举例,在未执行Bytes.setInt()方法之前,row的值如下图示:
使用Bytes
类的setInt()
方法修改row的值。setInt()
主要的是>>>
运算,这个运算符的意思是指:右移指定的位数,左边的空白位置0。得到的row值如下:
可能有人会问,为什么使用的是Bytes.setInt()
这个方法?要知道,openTSDB只是根据timestamp(实质是 base_time
,这个base_time
我在后面会补充介绍)去生成rowKey的一部分,所以这一部分是什么样的逻辑不重要了,重要的是这个逻辑需要保持相同的base_time
映射到固定的byte[]
值。而openTSDB在rowKey
的生成过程中采取的方法就是使用>>>
去处理(timestamp)base_time
,从而保证rowKey
在base_time
相同时,其base_time
对应的rowKey
部分也相同。
到这里,一个完整的rowKey就生成了。
3.其它
3.1 base_time
字段的生成
这个base_time
代表的值就是当前value传递过来所在的timestamp。例如:对于一个timestamp=1542088140,处理过程就是取该timestamp所在小时 0分0秒的timestamp值。这也能解释为什么opentsdb中的存储按照每小时进行行存储,而不是每个时间戳一行。
这个Const.MAX_TIMESPAN
定义如下:
/** Max time delta (in seconds) we can store in a column qualifier. */
public static final short MAX_TIMESPAN = 3600;
代表的是一个小时的秒跨度。对其MAX_TIMESPAN
取余之后,该余数就是秒数,再减去这个秒数就得到hh:00:00的值。
上面的值处理之后,得到的base_time值变为了1542085200。如下示: