作者:teachzhang 腾讯PCG工程师
|导语 大数据多维分析是业务中非常常见的分析场景,目前也有许多落地方案,但是在遇到上百亿数据、维度个数不限、秒级返回结果这样的场景时,实现的时候还是遇到了一些挑战。本文介绍了一种参考kylin的预聚合模式实现的存储方案,支持对上百亿数据以及数百个维度的多维分析,并且能在秒级返回查询结果。该方案可以运用于多维指标拆解分析,异动归因分析业务场景。希望给其他有类似分析场景的同学提供一种参考方案,对本内容感兴趣的同学,欢迎一起交流学习。
1. 背景
周报场景:微视的分析师每周一需要对上周的业务情况进行分析,整理成周报向领导进行汇报。以前的流程是在灯塔上通过执行大量复杂的sql查询需要的数据,然后下载数据,整理成许多多维分析树。查询的数据以周为单位,需要查询4周的数据,数据量达几百亿,因此每次查询都需要很长的时间(小时级),并且经常碰到查询超时的情况。当分析模型变动时,又得需要改动sql重新查询。总结就是,查询流程长,人工成本非常大,整个团队的分析师周一一大半时间都fork在周报整理上。
即席分析:当业务指标大幅变动时,需要快速找出变动原因,例如当DAU下跌时,分析师需要从多个维度钻取,找出具体的下跌原因。
除此之外,希望在微信小程序查看多维分析报表,从数据中发掘出更多的价值。
因此急需建设一个多维分析平台,解决目前的业务痛点。
2. 产品介绍
最终我们开发了一个归因分析平台,产品演示如下:
特殊说明:1.展示数据经过脱敏处理;2.为了演示直接使用了已运行好的报表。
功能特色:
归因分析:
以上是分析师创建的归因报表(注:数据为假数据),用于分析拉活对内软下各渠道的影响。
3. 技术难点
要实现这样一个多维分析系统,有以下难点需要解决:
4. 实现思路
4.1 分析树拆解
首先我们来看一下一棵多维分析树是如果查询数据的。上面是一棵多维分析树,m1代表指标,例如DAU、总时长等,D1代表维度,例如城市、首启方式等。对于这棵树,转化成sql去查询数据,一次sql无法实现,只能多次查询才能取得结果,分为以下组合查询:
(D0)
(D1), (D2) (D1, D3), (D1, D4) (D1, D4, D5), (D1, D4, D6)
例如(D1, D3)转化成sql如下
select D1, D3, m1 from table group by D1, D3;
D0代表对全部聚合查询。对于一颗具有n个维度,m个指标的分析树,查询sql的次数为m*(n+1)次。
4.2 存储引擎调研
接下来需要选择一个合适的大数据分析引擎,目前常用的有ES、Spark、Kylin、Clickhouse、灯塔、Hermes,我们分别对这些引擎进行了调研,进行了对比:
4.3 预聚合
通过对现有分析引擎的调研,发现它们都无法满足我们的业务场景。从查询时间要求出发,只有Kylin这种预聚合的引擎才能满足,但Kylin维度爆炸问题无法解决。以40个维度,最多5层维度组合为例,组合方式有C(40,5)=658008种,在上亿数据量的情况下Kylin无法聚合出结果。
通过对需求进一步分析,发现虽然维度非常多,但是分析师在使用中根本不会用到这么多维度组合,对于一个包含10个维度的报表,用到的维度组合为10,并且业务的分析逻辑基本上有迹可循,最终的维度组合最多只有几千。但是Kylin不支持指定维度组合的方式构建cube。因此我们决定参考Kylin的原理自己实现预聚合。
最终实现方案:将报表拆解为多个维度组合的cube,按天预聚合去查询每个cube的数据,将结果缓存起来。用户查询报表时,直接从缓存中取数。当新数据产出后,只需要增量缓存最新一天数据即可。
底层存储的选择上,只有Hermes和clickhouse比较适合,但是由于clickhouse现在资源紧张,并且业务方希望尽快上线,因此最终选择了Hermes作为查询存储引擎。
5. 实现方案
5.1 整体架构
整体架构分为四层
汇总层:根据前端传入的查询时间,按照本期、同比周期、环比周期、基期分别去聚合层查询分析树,然后将4颗树的数据汇总到一颗树上,计算出指标的同比、环比、同比等指标。
聚合层:解析多维分析树,拆分为多个cube,按照cube到聚合层查询数据,根据聚合指标的计算逻辑计算出指标绝对值,构造出一颗多维分析树。
预聚合层:维护所有分析树中用到的cube集合,自动调度cube任务,解析成sql语句,从Hermes查询聚合数据,最终缓存到ES。
源数据层:采用Hermes存储底层明细数据,利用Hermes的sql能力查询聚合数据;采用ES存储聚合数据,最终报表的查询直接从ES中查询缓存数据,做到秒级响应。
接下来重点介绍预聚合层的实现原理。
5.2 预聚合层
5.2.1 kylin的存储结构
因为本架构是参考Kylin实现的,所以首先介绍一下Kylin的存储结构。
Apach Kylin是一个开源分布式数仓,提供超大规模的多维分析能力,这里就不详细介绍了,网上有很多文章,这里重点介绍Kylin Cube的实现方式。Cube也就是多维立方体,提前将所有维度的可能的组合提前聚合分析好,以Cube为单位存储起来。
这里以查询DAU场景为例,假如有城市(city)、渠道(channel)、消费层次(consume_level)三个维度,那么所有维度的组合有2^3=8种。
一维度(1D)的组合有:(city)、(channel)、(consume_level)
二维度(2D)的组合有:(city, channel)、(city, consume_level)、(channel, consume_level)
三维度(3D)的组合有:(city, channel, consume_level)
另外还有(0D),总共8种。
假设有以下数据:
城市 | 消费层次 | 渠道 | qimei |
---|---|---|---|
北京 | 低 | c1 | 10 |
北京 | 低 | c2 | 20 |
北京 | 中 | c2 | 30 |
北京 | 中 | c4 | 40 |
上海 | 高 | c1 | 50 |
上海 | 高 | c3 | 60 |
现在计算DAU=count(distinct qimei),按照上面的方式计算所以维度组合
为了压缩存储,需要对维度和维度值进行编码,生成维度字典。
维度编码:
维度值编码:
最终对所以cube编码如下:
其中code和itemKey中的0代表全部。
5.2.2 预聚合层架构
首先给出cube和cube任务的定义。维度编码+指标代表一个cube,例如(101, m1);cube再加上日期代表一个cube任务,例如(20210101, 101, m1)。
目前预聚合层会缓存30天的数据,一个分析报表创建好之后,需要缓存近30天的数据,当所有数据都缓存好之后,该报表才可用。第二天新的数据产出后,预聚合层自动缓存最新的数据,然后报表的时间范围就更新到最新。即用户创建好报表后,以后无需操作,就能查询最近一个月的数据。
创建一个报表的流程如下:
5.3 其他功能
缓存数据多版本:对于同一cube的数据,可以存在多个版本。这是因为当一个报表的数据缓存好之后,如果此时某几天数据出问题了需要重跑,那么需要将所有数据重跑好了之后,再一次全部切换,否则会让用户看到中间态的数据。
动态添加指标和维度:可以根据现有的维度和指标配置出新的维度指标,无需重跑源表数据。
支持留存维度和指标:支持不同留存时间的维度和指标,比如次留、3日留存、7日留存等等。
6.未来优化
1.优化底层存储。目前支持的数据分析时间范围为一个月,未来可能会增加到3个月或者半年,相应的缓存时间就会变长,Hermes的存储成本也会变大,未来准备支持多个数据底层数据源,比如灯塔、presto、clickhouse等,加速缓存。
2.添加各种归因算法。未来准备在归因分析树上应用一些归因算法,比如JS散度等,智能的找出指标的影响因素。
3.添加报表全局过滤功能。在报表上添加过滤条件,限定整棵树的分析范围。
4.支持维度间的层级关系。比如支持城市、区域维度之间的层级关系。
近期热文
让我知道你在看