听说过时序数据库吗?( 六 )


对于聚合查询,其处理是分两阶段完成的:

  • Shard本地的Lucene Index并行计算出局部的聚合结果;
  • 收到所有的Shard的局部聚合结果,聚合出最终的聚合结果 。
这种两阶段聚合的架构使得每个shard不用把原数据返回,而只用返回数据量小得多的聚合结果 。相比Opentsdb这样的数据库设计更合理 。Opentsdb其聚合只在最终节点处完成,所有的分片数据要汇聚到一个地方进行计算,这样带来大量的网络带宽消耗 。所以Influxdb等更新的时间序列数据库选择把分布式计算模块和存储引擎进行同机部署,以减少网络带宽的影响 。
除此之外Elasticsearch还有另外一个减少聚合过程中网络传输量的优化,那就是Hyperloglog算法 。在计算unique visitor(uv)这样的场景下,经常需要按用户id去重之后统计人数 。最简单的实现是用一个hashset保存这些用户id 。但是用set保存所有的用户id做去重需要消耗大量的内存,同时分布式聚合的时候也要消耗大量的网络带宽 。Hyperloglog算法以一定的误差做为代价,可以用很小的数据量保存这个set,从而减少网络传输消耗 。
为什么时间序列需要更复杂的聚合?
关系型数据库支持一些很复杂的聚合查询逻辑,比如:
  • Join两张表;
  • Group by之后用Having再对聚合结果进行过滤;
  • 用子查询对聚合结果进行二次聚合 。
在使用时间序列数据库的时候,我们经常会怀念这些SQL的查询能力 。在时间序列里有一个特别常见的需求就是降频和降维 。举例如下:
12:05:05 湖南 8112:05:07 江西 3012:05:11 湖南 8012:05:12 江西 3212:05:16 湖南 8012:05:16 江西 30按1分钟频率进行max的降频操作得出的结果是:
12:05 湖南 8112:05 江西 32这种按max进行降频的最常见的场景是采样点的归一化 。不同的采集器采样的时间点是不同的,为了避免漏点也会加大采样率 。这样就可能导致一分钟内采样多次,而且采样点的时间都不对齐 。在查询的时候按max进行降频可以得出一个统一时间点的数据 。
按sum进行降维的结果是:
12:05 113经常我们需要舍弃掉某些维度进行一个加和的统计 。这个统计需要在时间点对齐之后再进行计算 。这就导致一个查询需要做两次,上面的例子里:
  • 先按1分钟,用max做降频;
  • 再去掉省份维度,用sum做降维 。
如果仅仅能做一次聚合,要么用sum做聚合,要么用max做聚合 。无法满足业务逻辑的需求 。为了避免在一个查询里做两次聚合,大部分的时间序列数据库都要求数据在入库的时候已经是整点整分的 。这就要求数据不能直接从采集点直接入库,而要经过一个实时计算管道进行处理 。如果能够在查询的时候同时完成降频和降维,那就可以带来一些使用上的便利 。
这个功能看似简单,其实非常难以实现 。很多所谓的支持大数据的数据库都只支持简单的一次聚合操作 。Elasticsearch 将要发布的 2.0 版本的最重量级的新特性是Pipeline Aggregation,它支持数据在聚合之后再做聚合 。类似SQL的子查询和Having等功能都将被支持 。




推荐阅读