druid的优化杂谈

1、基于DataSource与Segment的数据结构
druid中segment 大小存储的因为其一般由dataSource_beginTime_endTime_version_shardNumber做唯一标识。所以一般我们可以根据产生数据频率设置文件生成的周期跨度
(1)、通过时间粒度划分通过granularitySpec来配置属性的.

"granularitySpec" : {
  "type" : "uniform",
  "segmentGranularity" : "day",
  "queryGranularity" : "none",
  "rollup" : false,
  "intervals" : ["2017-03-09/2017-03-10"]
}

type : 用来指定粒度的类型使用 uniform, arbitrary(尝试创建大小相等的段).
segmentGranularity : 用来确定每个segment包含的时间戳范围(一般我们用于设置具体的segment的时间跨度)
intervals : 用来确定总的要获取的文件时间戳的范围(看是否要限制未作限制说明不用过滤掉不在此范围内的时间)
如上的配置说明了接受 09-10 这一天的数据, 然后按天来划分 segment, 所以总共只有一个 segment.
(2)、通过限制segment的段的大小(推荐的300mb-700mb范围内),数据量在含5-10 百万行记录。我们通过partition的划分做为配置。例如下配置为:

"partitionsSpec" : {
  "type" : "hashed",
  "targetPartitionSize" : 5000000,
  "maxPartitionSize" : 7500000,
  "assumeGrouped" : false,
  "numShards" : -1,
  "partitionDimensions" : [ ]
}

targetPartitionSize : 要在分区中包括的目标行数,应该是以500MB〜1GB为目标的数字。
分区中要包括的最大行数。默认为比targetPartitionSize大50%.

2、缓存配置
配置查询时的broker缓存。当集群机器较少时(官方文档推荐<20台),在broker节点配置缓存,可以适当增加缓存大小,或者从local替换成memcached。(注意:当集群机器较多时,应当只配置historical节点缓存,减轻broker节点压力。)

# Query cache
druid.broker.cache.useCache=true
druid.broker.cache.populateCache=true
druid.cache.type=local
druid.cache.sizeInBytes=2000000000

3、冷热数据分层
具体步骤为:Druid 提供了Historical 的 Tier 分组机制与数据加载 Rule 机制,通过配置能很好的将数据进行冷热分离。 首先将 Historical 群进行分组,默认的分组是"_default_tier",规划少量的 Historical 节点,使用 SATA 盘;把大量的 Historical 节点规划到 “hot” 分组,使用 SSD 盘。然后为每个 DataSource 配置加载 Rule :

rule1: 加载1份最近30天的 Segment 到 “hot” 分组;
rule2: 加载2份最近6个月的 Segment 到 “_default_tier” 分组;
rule3: Drop 掉之前的所有 Segment(注:Drop 只影响 Historical 加载 Segment,Drop 掉的 Segment 在 HDFS 上仍有备份)
(具体实现方式待完善)

{"type":"loadByPeriod","tieredReplicants":{"hot":1}, "period":"P30D"} 
{"type":"loadByPeriod","tieredReplicants":{"_default_tier":2}, "period":"P6M"} 
{"type":"dropForever"}

参考:https://www.jianshu.com/p/0e1b317767a9

4、查询优化:
对于大时间范围的查询,可以拆分为多个小时间范围的查询,并行提交,以充分利用 Druid 多节点并行查询能力。

5、老数据进行roll up (已数据冷热分层后基础)
在我们实时或批量indexing的时候,一般我们配置的按小时的粒度进行roll up,最后存储的就是按小时聚合的数据。
“granularitySpec”: {
“type”: “uniform”,
“segmentGranularity”: “HOUR”,
“queryGranularity”: “HOUR”
}
当数据积累较长时间后,按照小时聚合必然数据量巨大,可以将不常用的或者不太重要的数据,按天存储数据量会大大减小,必然可以提高查询速度。
例如:将40天之后的数据提交batch indexing任务按天roll up。
以7台机器为例,配置5台hot分片的机器,2台default分片的机器。hot分片存储的是以小时为粒度的数据,_default_tier分片存的是按天为粒度的数据。
image

40天之内的热数据根据之前配置的规则,会在hot分片存一份,_default_tier分片存一份
在这里插入图片描述

40天之前的数据只会在_default_tier分片存一份
在这里插入图片描述
查询40天内的数据时,由于hot分片的机器优先级高。只会从hot分片的5台机器读取数据,40天之前的数据只会从default分片读取数据。

5、查询优化个别例子(借鉴快手http://www.mobabel.net/%E8%BD%AC%E5%BF%AB%E6%89%8B%E4%B8%87%E4%BA%BF%E7%BA%A7%E5%AE%9E%E6%97%B6olap%E5%B9%B3%E5%8F%B0%E7%9A%84%E5%BB%BA%E8%AE%BE%E4%B8%8E%E5%AE%9E%E8%B7%B5/)
在大规模数据场景下查询性能的加速,我们也做了很多优化。首先是物化视图,会做两个层面的物化视图,一个是维度层面的物化,一个是时序层面的物化
(1)、是维度层面的物化
假设一个数据源的原始维度有十个列,通过分析查询请求发现,group1 中的三个维度和 group2 中的三个维度分别经常同时出现,剩余的四个维度可能查询频率很低。更加严重的是,没有被查询的维度列里面有一个是高基维,就是 count district 值很大的维度,比如说像 User id 这种。这种情况下会存在很大的查询性能问题,因为高基维度会影响 Druid 的数据预聚合效果,聚合效果差就会导致索引文件 Size 变大,进而导致查询时的读 IO 变大,整体查询性能变差。针对这种 case 的优化,我们会将 group1 和 group2 这种维度分别建一个预聚合索引,然后当收到新的查询请求,系统会先分析请求里要查询维度集合,如果要查询的维度集合是刚才新建的专用的索引维度集合的一个子集,则直接访问刚才新建的索引就可以,不需要去访问原始的聚合索引,查询的性能会有一个比较明显的改善,这就是物化视图的一个设计思路,也是一个典型的用空间换时间的方案。
(2)、时序物化视图:
除了刚才提到的查询场景外,还有一种查询 Case,Druid 也不能很好满足。比如大跨度时间范围的查询,假设一个数据源的聚合力度是分钟级别,但需要查询最近三个月的数据就比较麻烦,因为需要把过去三个月的所有分钟级别的索引文件全部扫描一遍,然后再做一次聚合的计算。
为了解决这个问题,我们在数据源分钟级别的索引上再新建一个小时级别甚至级别的物化索引,这种情况下聚合效果就会更好,索引整体的 size 也会比较小。当收到一个新的查询请求时,如果查询要统计的粒度是天级别或者是更高级别的查询粒度,会把查询请求自动路由到天级别物化索引上,这样查询性能也会有一个比较明显的改善

元数据方面查询的优化。

推荐比较好的文章:https://juejin.im/entry/5b18d62d6fb9a01e5c454311 滴滴在druid 实践中也写到了在druid 在元数据查询上的优化

注意:不适合场景查询:Druid作为一个OLAP数据库。OLAP数据库需要支持类似上卷、切块、切片、下钻等操作,但不适合明细查询。对于类似根据某主键ID定位唯一数据的任务

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值