openTSDB compaction 机制探究

openTSDB 介绍

openTSDB是基于Hbase的分布式的,可伸缩的时间序列数据库,作为时序性数据库,能作为监控系统 ,目前openTSDB支持秒级别的数据查询存储,并且数据会持久化保存在HBase表中,在官方文档,给出以下架构
在这里插入图片描述

1.为什么会需要做compact

这就要先介绍以下,openTSDB的数据在HBase的存储了,这里有个HB阿瑟数据表 tsdb表,这里面保存了 openTSD的数据,一条完整的数据包含一下维度

1)Metric:监控项。如 集群监控指标
2)Tags:Tags由tagk和tagv组成,
3)Value:一个Value表示一个metric的实际数值,比如99
4)Timestamp:时间戳,因为数据是基于时间的,一条数据 对应一个时间戳。
由于openTSD底层依赖于HBase 进行数据的保存,首先是TSDB的rowkey设计,TSDB是采用 :加盐+metric + timestamp + tagk1 + tagv1 + tagk2 + tagv2 + … + tagkn + tagvn,作为HBase TSDB表的rowkey
基本格式如下

在这里插入图片描述
open TSDB 为了减少rowkey的存储,openTSDB 会对每一个tag metric 都进行编码,所以TSDB 会依赖UID表,这个表对应了 每个tag 和编码的相互对应关系

在这里插入图片描述
最终形成了 下面的格式

在这里插入图片描述

2.追踪源码-1

public Deferred<Object> call(final Boolean allowed) throws Exception {
  if (!allowed) {
    return Deferred.fromResult(null);
  }
 
  last_ts = (ms_timestamp ? timestamp : timestamp * 1000);
 
  long base_time = baseTime();
  long incoming_base_time;
  if (ms_timestamp) {
    // drop the ms timestamp to seconds to calculate the base timestamp
    incoming_base_time = ((timestamp / 1000) - ((timestamp / 1000) % Const.MAX_TIMESPAN));
  } else {
    incoming_base_time = (timestamp - (timestamp % Const.MAX_TIMESPAN));
  }
  if (incoming_base_time - base_time >= Const.MAX_TIMESPAN) {
    // Need to start a new row as we've exceeded Const.MAX_TIMESPAN.
    base_time = updateBaseTime((ms_timestamp ? timestamp / 1000 : timestamp));
  }
更新基础时间,添加row到队列中

private long updateBaseTime(final long timestamp) {
  
  final long base_time = timestamp - (timestamp % Const.MAX_TIMESPAN);
  row = Arrays.copyOf(row, row.length);
  Bytes.setInt(row, (int) base_time, Const.SALT_WIDTH() + tsdb.metrics.width());
  RowKey.prefixKeyWithSalt(row); // in case the timestamp will be involved in
                                 // salting later
  tsdb.scheduleForCompaction(row, (int) base_time);
  return base_time;
}

在这里插入图片描述
上面是TSDB的逻辑存储,每一个rowkey,是一个整点的时间戳,后面对应多个kv ,然后 TSDB 会把一个小时整个数据都会读取出来,做压缩。

3.compaction 做了什么

主要步骤: 读取,压缩,写入,删除

1.主要是对多个k v 进行压缩合并,把上述产生的 数据通过压缩把多个kv 合并成为一个k v,这也就是open TSDB compaction 需要做的事情在这里插入图片描述
2. 每个TSDB实例 都会维护一个 ConcurrentSkipListMap 作为数据结构的CompactionQueue ,这里面记录着,添加进HBase 表的所有rowkey,,TSDB 会定时启动线程,去对每一个rowkey 都进行compact 操作CompactionQueue ,这里面记录着,向HBase 添加的所有rowkey

4.compact 代码追踪-2

这里做compact 的时候 有几个关键点:

 

private final int flush_interval;  // 单位是s 多长时间会执行compact 线程

private final int min_flush_threshold;  // rows 最小的压缩行
private final int max_concurrent_flushes;  // rows 同时最大压缩行
private final int flush_speed;  //压缩的速率
final int maxflushes = Math.max(min_flush_threshold,
  size * flush_interval * flush_speed / Const.MAX_TIMESPAN);
final long now = System.currentTimeMillis();
flush(now / 1000 - Const.MAX_TIMESPAN - 1, maxflushes);
if (LOG.isDebugEnabled()) {
  final int newsize = size();
  LOG.debug("flush() took " + (System.currentTimeMillis() - now)
            + "ms, new queue size=" + newsize
            + " (" + (newsize - size) + ')');
}
 



会调用 tsdb.get(row),获取每一行数据的kv 进行判断压缩
private Deferred<ArrayList<Object>> flush(final long cut_off, int maxflushes) {
  assert maxflushes > 0: "maxflushes must be > 0, but I got " + maxflushes;
  // We can't possibly flush more entries than size().
  maxflushes = Math.min(maxflushes, size());
  if (maxflushes == 0) {  // Because size() might be 0.
    return Deferred.fromResult(new ArrayList<Object>(0));
  }
  final ArrayList<Deferred<Object>> ds = new ArrayList<Deferred<Object>>(Math.min(maxflushes, max_concurrent_flushes));
  int nflushes = 0;
  int seed = (int) (System.nanoTime() % 3);
  for (final byte[] row : this.keySet()) {
    if (maxflushes == 0) {
      break;
    }
    if (seed == row.hashCode() % 3) {
      continue;
    }
    final long base_time = Bytes.getUnsignedInt(row,
        Const.SALT_WIDTH() + metric_width);
    if (base_time > cut_off) {
      break;
    } else if (nflushes == max_concurrent_flushes) {
      break;
    }
    if (super.remove(row) == null) {  // We didn't remove anything.
      continue;  // So someone else already took care of this entry.
    }
    nflushes++;
    maxflushes--;
    size.decrementAndGet();
    ds.add(tsdb.get(row).addCallbacks(compactcb, handle_read_error));
  }
 }

获取到具体的rowkey 对应的kv 之后,这里会做判断,如果对应的列是多个 就会进行进行数据的读取和删除等操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值