导读 大数据时代,数据量呈爆炸式增长,如何从海量数据中快速的挖掘出潜在信息成为现阶段数据库领域的重要挑战。在企业级的数据分析场景下,采用OLAP分析引擎+ADM的方式是最为常见的性能解决方案。今天会和大家分享下蚂蚁集团在OLAP场景下面临的问题及针对这些问题现阶段蚂蚁集团所采用的解决方案。
全文目录:
- 为什么需要通过ADM来解决OLAP场景下大表性能问题
- 通过Cube解决OLAP场景下报表性能问题
- 通过采样解决OLAP场景下分析性能问题
- 我们的团队
分享嘉宾|余志鹏 蚂蚁智信(杭州)信息技术有限公司 高级技术专家
编辑整理|橘子
内容校对|李瑶
出品社区|DataFun
01 通过ADM来解决OLAP场景下大表性能问题
1.常见的名词解释
在接下来的正题之前先解释一下这个领域的专有名词。
互联网场景主要分为两种模式:一种是OLTP(OnlineTransaction Processing),一个是OLAP(Online Analytical Processing)。其中,OLTP主要解决在线的事务查询,常见的框架如图中所示的MVC,底层会有LOG及业务的数据库。在离线分析场景下,先会把数据同步至离线,如Spark或Hive等离线引擎。在此之上,进行基础建模,目前比较成熟的建模理论就是维度建模,比如我们经常用到的的星型模型和雪花模型。当数据量特别大时(如蚂蚁所面临的超百亿级数据量)很多OLAP引擎无法支持亚秒级查询,因此,ETL会把DWD向上进一步汇总成DWS,比如根据user_id进行汇总。此外,还可以面向具体业务应用进一步整合成应用层(ADM层),大大减少在分析时查询引擎的数据量和复杂度。这里类似于OLTP场景下的service,越向上通用性会下降,业务越聚焦,业务属性会越来越增强。本篇主要介绍OLAP场景所碰到的问题,我们先从OLAP场景下一个流程开始。
2.常见的流程分析
在数据驱动决策链路中:
- 首先需将数据加到数据仓储中,搭建相应看板,这些看板主要给经营决策者日常看数使用,比如高管、运营人员,通过观测业务数据进行经营决策;
- 当数据出现异常时,需要分析原因,则需要建立分析的假设树,沿着分析思路不断下钻分析,找到最终的洞见。然后根据这个洞见进行决策。
接下来我们主要看一下业务看板的完整流程:
一个完整制作报表的流程需要如下几步:
首先,运营或PD会向业务BI提出需求,业务BI接收到需求后,负责制作后续的看板。业务BI基于需求,需要确认现有数据是否能支持业务需求,如果没有相关数据,则需要跟ETL数据研发团队进行需求沟通。在确认数据后,业务BI进行看板制作、报表发布等工作。那这一流程的一个核心或者主要耗时在ADM研发,如果整个报表的研发耗时为1.5天,那其中ADM的研发耗时就要1天,如果一年要产生1万张报表,则需要1万人日研发ADM。这种方式不仅效率低下,且会带来巨大的研发成本。
报表制作好之后,业务看数的时候,假如某个指标出现异常(当业务出现下跌进行原因查找时),那么我们如何一步一步找到最终的问题原因。首先我们需要提出假设,以上面图表中的案例:“月份贷款余额下降”为例,为了找到贷款余额下跌的原因,我们可以从产品、用户、流量等这些维度提出假设:
① 是否是产品余额下降导致
② 是否是新/老客户影响等,根据前面的维度建立完整的假设树,不断在各维度空间探索从而找到贡献度最大的原因,那么最终要执行这个假设树,从而找到这个原因,具体我们需要做什么呢?
具体实现流程可分为几个流程:
① 定义问题
② 找到对应数据
③ 写SQL
④执行脚本
⑤ 检查
这个过程需要反复进行,直到找到最终问题的原因,从上面这张图中可以发现,要完整的把所有空间探索完,流程非常长,一般是周级别,我们再看一下具体耗时在哪里?
对探索式分析流程的进一步细化可分为三步:
① 度量定义
② 写SQL代码
③ 运行结果
这其中基于分析场景的SQL通常比较复杂,耗时长,也是效率低的关键。
除了前述的效率问题外,随着需求增长,ADM快速增长,相应的资源和存储成本均在快速增长,此外,由于很多业务都会随之着不断变化,而之前的ADM会随着业务的变化而失效,然后这些ADM无法精准判断下游下,导致治理成本越来越高,随着ADM不断增多,也带来了治理成本高的问题。
3. 那么为什么需要ADM,是否有优化方案
前述诸多内容,引发了一个思考:既然ADM会带来这么多的问题,那么为什么通过ADM来解决这些问题。
从流程上来分析,传统ETL中,数据首先从离线数仓到维度建模(解决ER模型分析复杂度高问题),然后进行数据维度聚合,继而在基于现实业务的场景下形成各自ADM。
在上述环节中,ADM核心解决两个问题:① 性能问题;② 复杂度量定义的问题,那么接下来我们就要思考有没有其他方案解决两大问题。今天我分享的主题是有没有其他方案解决性能问题。
基于前述分享,主要有两种应用场景:一个是报表,一个是探索式分析。报表的特点在于度量和维度确定,用户在固定空间内看数,针对这种情况,比较适合用业内常用的的“Cube预聚合”减少查询数据量(本质上是自动化ADM,从而提升查询性能)。探索式分析场景下,度量和维度会随着前面所说的假设树的分支增多,度量数和维度数都会不断增加,那么,使用Cube由于不知道用户会使用哪些组合,则需要提前构建成所有可能的组合,成本上会产生巨大的浪费。由于分析的过程我们主要是做对比分析,对于数据的精准度要求没有报表看数的要求这么高,比较适合“采样的方案”来减少即时分析时的数据量。
02通过Cube解决报表的性能问题
1.Cube的系统执行流程
首先来看下Cube是如何工作的。
一般一个报表配置会包含业务所需的维度、度量,会设定查询的步长(多少天),会有一些固定的筛选项,按照相关报表配置,如果直接翻译成SQL进行引擎查询,由于数据量非常大,常用的MPP引擎或者MR引擎查询速度非常慢。从上面的SQL我们可以发现我们可以把这个数据提前算好,Cube就是解决这个问题。那么我们再看看Cube的构建SQL,这个Cube就是类似于人工ADM,只是Cube是根据特征自动化的预聚合,在具体的查询中,只需要传入动态变化的参数,数据量从10亿级别减少到百万级别,查询性能可以从分钟级别提升到秒级。
接下来,我们看一下基于Cube的系统执行流程,这里主要分为两个阶段:
① 构建侧
② 查询侧
在构建侧,从数据模型出发,通过报表上的配置抽取出维度、度量,形成一个完整的Cube定义,随后对Cube进行剪枝优化(哪些组合是不必要的),形成相应的Cube构建任务,提交至构建引擎,比如如Spark,然后将构建同步至MPP或RDB引擎,提升即席查询的性能。在查询侧,则基于图表特征和Cube进行匹配,匹配出正确的Cube之后,把对明细表查询改写成基于Cube的查询。
2.Cube系统的核心指标
类似评价一辆汽车的好坏我们使用百公里加速、油耗、舒适度等指标,在这里,同样在Cube系统里面我们将Cube的优化问题转化为数学问题,那么Cube的核心指标有以下三个:
- 慢查询场景Cube覆盖率(当前能力能覆盖多少图表)
- Cube命中率(应该做而没有做的图表)
- Cube利用率(当前构建的Cube有多少应用了)。
(1)那么我们如何提升Cube能力覆盖率?
业内常见的开源Cube引擎比如说kylin通常是基于SQL进行Cube定义,这种方式的好处是SQL是一种标准化语言,和业务耦合度低,基于此方式可以开源、通用化,但会带来覆盖度不高,且特征比较难以提取的问题。比如上面图中的案例中的“最近七天”的条件,在SQL中就是某天开始-某天结束的时间范围,但是这个时间范围从SQL视角并不知道其语义是最近7天,这就导致Cube的构建任务的时间窗口并不知道是几天,这个问题还是一个比较简单的问题。更复杂的是SQL中的嵌套语句,更难以识别。
目前我们的方案中采用的是基于报表配置定义Cube,这种方式通用性会比较低,需要与BI场景下的功能进行深度耦合,但Cube覆盖率会有明显提升,可以覆盖更多的场景,解决更多的业务问题。所以在指标的权衡取舍中我们优先考虑的是Cube覆盖率,而非通用性。接下来我们看看Cube是如何提取特征进行构建,以及查询侧如何改写。
基于报表配置定义Cube的流程:
- 报表上线——报表特征提取——Cube定义——构建Cube;
- 报表查询——提取查询特征——Cube路由,找到后进行改写;
(2)那么,如何提升Cube的利用率
(此处图片中有个错误,提升Cube利用率)
Cube利用率较低的原因,主要是因为我们在构建的时候并不知道哪些组合会被利用,这样会导致大量的浪费,那么,我们可以根据用户的使用情况基于用户查询特征及HBO进行剪枝优化。一般来说,用户进行查询时并不会使用所有的组合,我们会记录用户相关查询组合,对Cube进行剪枝优化,大幅缩减构建成本,随着报表的查询不断稳定,那么利用率会越高,然而对于一些长尾查询(比如说半个月查询一次),会面临Cube被回收导致的性能问题。
3.Cube的技术架构
从下往上来看,Cube架构构建的第一步是进行物化发现,包括离线图表发现、在线图表发现,同时组成图表发现的能力;第二步进行物化构建,实现在确定时间范围内可以构建更多的Cube;第三步是物化识别,在查询时进行识别。其他还有包括Cube治理、监控告警等相关辅助能力,上述内容共同构成完成的Cube系统。
03 通过采样解决探索式分析的性能问题
1.探索式分析的理论基础
探索式分析的特点是度量灵活、维度灵活。分析过程往往是找规律,不需要数据的绝对精准,所以我们可以利用这个特性,对原表进行采样,减少表的数据量,从而提升查询性能。
采样的核心理论支持是统计学,基于统计学原理还原真实数据情况。从表中可以看到,目前统计学中的一些原子计算,现在比较常用的是count、avg、sum及count Distinct等,其理论支持是伯努利分布或中心极限定理。
2.采样分析的误差及权重问题
在实践中,上述统计学计算也会存在一些问题。
(1)COUNTD导致的误差问题
随机采样情况下,COUNTD会导致较大误差。从图中示例可以看出,当我对原始表进行50%采样,统计用户数并还原回原始数据计算,得出的结果用户数是8,但实际上,user_id是4。这种情况下,是Count Distinct的本质是先做Distinct再做Count,而随机采样的本质并不是基于Distinct的结果进行采样,导致结果无法还原。
针对这个情况,解决思路是先要把COUNTD转化成COUNT,这样就从一个非统计量转化成一个统计量。我们把原始表映射到一系列的桶上,而这样就可以保证每个桶内部的数据是不重复的,这样对于原表的COUNTD就转化为这样对分桶表的COUNT,这样就由非统计量变成统计量。我们这里的采样比例就转化为取几个分桶的数据,并可以按比例进行还原,即可得到真实数据下的结果。
(2)另外,我们看一下下钻数据如何确保不同维值下数据的精准度
理论上,我们开展分析的误差率基本是要满足95%置信度下的误差率。当样本量不同时,为满足误差率要求,相应的采样比例也应该发生变化。
举例来看,当我们要计算全国的GMV时,对应原始数据量有1000万订单,此时,按照我们1%的采样比例,10万笔订单即可满足误差率要求;当我们想下钻到具体某一个城市的GMV,比如上图中的三沙市,由于城市规模小,订单数小,对应城市的原始数据可能仅为1万笔订单,按照1%的采样,只有100笔订单。按照左下角的公式,需要满足95%置信度下3%的误差率,这个样本显然无法满足要求,而按照公式,需要满足这个条件,采样数据需要达到3000才可以,也就是对三沙市的采样比例需要达到30%。
为了解决前面的问题,显然,我们不能按照统一的采样比例进行采样,那么,我们是否可以针对不同的维值数据量进行分别设置其采样比例呢?答案是肯定的。
以图中为例,第一步:从原始表中计算各城市的采样比例,将原始表中的user_id映射到分桶上。第二步:根据前面不同的维值数据量,设置不同的采样比例,其中上海、北京原始数据比较多,采样比例相对小,占用分桶中的一个格子,合肥相对采样比例多,占用2个格子,而三沙市原始数据少,相关数据全部采用,则占用3个格子,从而形成最终的采样结果表,这样我们就可以兼顾不同的维值下的数据,保证每个维值下的误差率都在我们要求范围之内。第三步:按照不同的采样比例进行还原。值得注意的是,由于每一个维值采用了不同的采样比例,还原的时候会相对比统一的采样比例更复杂,性能上也会低一些。如上图所示,我们算全国的用户数量的时候,需要用到开窗函数,先对不同的维值计算分组,然后对所有的维值结果求SUM。
3.采样的技术架构
在前面讲到了Cube的架构图,内在的结构有些相似性,Cube架构中做的是Cube预聚合,采样架构中则是利用采样的方式减少数据量,这里都会有具体的构建任务。采样计算中最核心的是采样算法,包括此前提到的解决COUNTD较大误差采用的哈希分桶采样及加权采样;另一个是采样样本的管理(和Cube管理类似),比如无效样本回收、基于特征匹配分层维度等多样本的决策管理。在构建完成之后,就是查询测,需要能进行路由,Cube里面是路由到cube表,而在采样计算的环节里面则是路由到采样表,最查询进行改写,对查询的结果进行还原。这样就形成了完成的采样架构。
04 我们的团队
DeepInsight是蚂蚁集团内部的BI工具,通过数据驱动决策,提升公司商业决策力。整体团队强调的是公平、公正、公开;合情、合理、合法。鼓励创新,提出新的假设,然后验证,落地。鼓励成长思维,只有认知的提升才能引领这个领域前进。
也因为前面的团队文化,以及不断的产品&技术创新,DeepInsight在蚂蚁内部的多个活动及评选中获得了非常多的奖项,也得到了非常多用户的认可。
今天的分享就到这里,谢谢大家。
文章来源:“志明与数据”微信公众号