1 基础介绍
1.1 特点
支持流式数据的摄入以及现场聚合
内存化 字典 位图 编码
index (哪些部分聚合,如何内存化、如何建立索引)
水平扩展???
实时分析: 历史数据以segment的形式组织。
轻聚合的数据存储在哪? Hbase还是hdfs???
聚合是实时聚合???
1.2 基本概念
1.2.1 数据格式
时间列、维度列、指标列
1.2.2 数据摄入
实时:kafka
批处理:HDFS
1.2.3 查询
原生用Json查询,也有很多插件来支持sql查询。
1.3 其他
1.3.1 时序数据库:
openTSDB InfluxDB
note:时序数据库
一般是各种硬件设备的各种性能指标,
这种场景的特点是:
写入的数据一般都非常大,相对于写,读取显得不大。
这种一般关注于某种时间粒度的聚合,因此没有必要保存原始的数据。
druid granularity 查询聚合粒度,这种查询聚合粒度的查询结果会被缓存下来吗???
原始数据的那个粒度称之为摄入粒度
1.3.2 竞品
Druid pinot Kylin
和预计算比如kylin的区别就在于kylin完全是预计算,没有现场计算,Druid是轻粒度预计算,有着大量的现场聚合
2 实践
json查询
不存储明细如何实现去重?
不支持join(必须全部做成一张宽表),如何通过lookup和维表join
3 基础架构及原理分析
3.1 设计特点
一般的数据平台在数据摄入和快速查询 往往是难以两全,但是Druid基于独特的dataSource和segment结构,很好的解决了这个问题。
列式存储
分布式
share-nothing
高级索引
3.2 基础架构
note:
查询的时候,从实时节点上以何种形式读取数据,从历史节点读取的时候应该包括批量摄入和segment吧???
为何能够快速摄入??
查询的时候再次将实时和历史的数据再次聚合,这种再次聚合怎么完成去重计数???
3.3 架构思想
3.3.1 基本思想
LSM-tree
3.3.2 数据结构
"granularitySpec" : { #预聚合相关的配置 "segmentGranularity" : "HOUR", "queryGranularity" : "HOUR" }
预聚合粒度是要小于等于查询粒度的,
预聚合: group time_function(time) , dim1,dim2 (查询的时候再次现场聚合)
上面的样例数据我们可以称之为原始数据,为我们直接采集到的数据,每天这样的数据有千亿甚至万亿。基于这些原始数据,如果我们需要分析点击量,成本是非常高的,因为我们尽管我们可以通过维度筛选出一部分数据,但是数据量还是很巨大,需要扫描这些数据来聚合,如此便会直接导致查询时长加长。为了避免这种情况,Druid采用了预聚合的设计,在数据接入的时候,就开始根据定义的维度,对数据进行聚合。Druid的预聚合分为两个级别,第一级是时间粒度,第二级是维度。
时间粒度
例子中模型的配置有segmentGranularity 和queryGranularity两个关键的参数,可以理解为一个是段的粒度,一个是查询的最小粒度。首先,Druid会根据timestamp和segmentGranularity来决定数据所属的段;然后,再根据timestamp和queryGranularity来决定存储在Druid的__time。
维度
Druid的预聚合过程也是其索引的过程,通常Druid会在内存中使用ConcurrentSkipListMap存储数据,以TimeAndDims(时间和维度值信息)作为key,根据配置的metricsSpec对数据进行聚合,聚合的结果作为value。为了避免OOM,最后会以bitmapIndex的数据格式周期性的落地到磁盘存储。
于是,样例数据最后存储的格式大概为:
Segment sampleData_2011-01-01T01:00:00:00Z_2011-01-01T02:00:00:00Z_v1_0
__time | publisher | advertiser | rows | click_sum |
---|---|---|---|---|
2011-01-01T01:00:00Z | ultratrimfast.com | google.com | 1 | 0 |
2011-01-01T01:00:00Z | bieberfever.com | google.com | 3 | 1 |
Segment sampleData_2011-01-01T02:00:00:00Z_2011-01-01T03:00:00:00Z_v1_0
__time | publisher | advertiser | rows | click_sum |
---|---|---|---|---|
2011-01-01T02:00:00Z | ultratrimfast.com | google.com | 2 | 1 |
segmentGranularity为小时,所以对应的段都是小时级别。queryGranularity为小时,聚合的结果对应的__time也是整点,会将每小时的数据全部聚合到其所属小时的开始时间。 另外说明,倒数第二例为总共的行数,最后一列为点击数。sampleData_2011-01-01T02:00:00:00Z_2011-01-01T03:00:00:00Z_v1_0中的v1通常为Task启动时获取的TaskLock的version,可以理解为Task启动的时间。
计数:
支持count/count distinct,支持基数计数。(非精确计数??)
4 源码分析
5 参考资料
http://www.sohu.com/a/109761742_470008
http://gitbook.cn/books/590150dd45025e57603548a3/index.html
http://garyhuang.name/2017/07/16/druid-architecture/
https://blog.csdn.net/hellobabygogo3/article/details/79782810