ETL是构建数据仓库的重要一环。通过该过程用户将所需数据提取出来,并按照已定义的模型导入数据仓库。由于ETL是建立数据仓库的必经过程,它的效率将影响整个数据仓库的构建,因此它的有效调优具有很高的重要性。在实际应用中我们通常建议把ETL业务的调优分为若干思路,从而保证调优充分有序进行,避免遗漏,最大化提升ETL的执行效率。
我们将分上下两篇文章介绍ETL业务的调优手段。本文将首先介绍以下三个:检查资源是否有效配置;收集数据特征,确定分区分桶;以及Task运行情况收集和监控。并对每个步骤中的调优原则和注意事项进行讲解,提出相应的解决办法和思路。然后通过案例分析帮助读者加深理解。
检查资源是否有效配置
关于资源,一般原则是根据需求场景,尽量最大化资源的有效配置。POC可考虑采取最大化的配置方式。实施项目中标准可适当保守,确保系统的稳定性。
假如这个集群主要用作批处理,一般建议Inceptor使用50%左右的CPU资源,另外单个executor不要超过16 core。如果硬件配置比较不错,如服务器有40个以上CPU core,建议采用多executor的方式来部署,譬如采用2 executor 每个10 core的方式,会比1 executor每个20 core的效果更好。
如果集群同时部署了其他服务,请保证其他的服务的资源前提下,给Inceptor部署尽量多的计算资源。计算资源的提高一般都会带来接近线性的分析性能提升。
收集数据特征,确定分区分桶
请注意,合理的DDL设计是批处理项目的一个非常关键的过程,需要综合分析业务和数据特点来确定。我们建议开发人员投入足够多的时间和经历来设计DDL,并充分论证设计的有效性。
1) 分区
-
分区字段选择
一般原则为根据系统的业务类型来分则分区字段。通常来讲事实表是数据都包含时间属性,而报表业务也多在一定的时间范围内做统计分析,那么根据时间字段进行分区是常用的选择。而如果业务更多按照部门做统计分析,那么更适合按照部门代码,地域代码进行分区。所以贴近业务的特点选择分区是第一要素。
另外数据的分布特点也是分区字段选择要考量的重要因素。假如按照用户期望按照某个字段A做分区,但是这个字段A的分布绝对倾斜(譬如字段A一共有1000个不同的数值,但是50%的值都是0,假如按照这个字段分区,那么对应的分区就占了全表50%的数据,这样会导致SQL业务的低效),这个时候选择字段A就不是一个合理的选择。
不过只要数据分布不是绝对倾斜,我们是可以通过Range分区指定不同大小的方式来有效的规避倾斜问题的,因此还是可以选用该字段用于数据分区。譬如企业用户数据,假如2016年用户数是2015年的3倍,我们在选择分区的时候2016年按照1个月为一个分区,而2015年每三个月为一个分区,而不是简单的数值等值切分Range。另外一个常见的情况是按照地域进行分区,我们建议把业务量较多的地域单独放在一个区,其余业务量不多的地域进行整合,从而保证各个区之间数据量大致均衡,避免出现大部分区没有数据或者数据非常少的情况。如果发现某些区数据特别倾斜,则需要考虑进一步切分或者更换分区字段。
-
分区个数
分区个数的选择需要综合考量数据的特性,在选择好分区字段后,我们需要根据数据的特点确定分区个数的可选择区间。
分区个数不宜太少,需要根据业务特点来确定,并保证分区里面不会太多的冷热数据混合。譬如SQL业务大部分都是操作2~3个月的数据,那么我们就尽量按照3个月做一个分区,如果我们选择1年做一个分区的话,每个SQL业务实际执行的时候就会多读取前面9个月的数据,这这部分的资源和IO开销都是没有必要的。
实际情况中我们看到的更多的DDL设计都是分区数量过多,譬如单个分区的数据量不超过1GB,或者按照天来分区,这些都是不合适的设计。分区过多的坏处是会导致过多的系统资源占用(譬如全表扫表类业务,Inceptor会启动 “分区数×分桶数” 的任务去完成这个SQL任务,分区数量或分桶数量过多都会导致集群资源在比较长的周期内被这个任务占据)。一般我们建议分区数量在几十以内。
Reiterate:不要按天分区!
2) 分桶
-
分桶字段选择
一般遵循的原则为,选择离散度高的字段进行分桶。可以通过收集的数据特征,如Distinct Value来做参考,值越大的可以优先作为考虑对象。分桶字段选择时,注意尽量使记录分布均匀,避免数据倾斜。
-
分桶个数
针对不同的存储类型,分桶个数的标准稍微有所差别。以ORC表举例,对于普通ORC表,单分桶大小可以在200M以内;对于ORC事务表,标准适当降低,文件大小限制在100M以内,记录条数限制在几百万条左右。
另外,在考虑分桶个数的时候,同时要考虑是否已经分过区。对于已经分过区的表,要按照单区的大小和条数进行桶数的估计,而不是依照原始表。例如某运行商项目中,我们发现某些表进行分区分桶后,分桶数量过大,导致每个桶的文件大小仅仅为几十K,这样就会使单个Task的执行效率很低,同时总体任务数过大也对系统资源造成极大浪费,并发度上不去。调整方案是根据实际情况,将原桶数降低数量级。
在进行分区分桶时,还应注意以下因素:
因为事务性业务大部分情况下建的都是Range分区分桶表。此种情况下,Map Task的数量=分区数×分桶数,所以,在考虑分区数和分桶数时要综合考虑,Map Task的数量不能过大,比如几千上万,这样可能使单个Task的执行效率太低,并且占用了系统资源,降低了系统并发度。
Task运行情况收集和监控
主要在4040界面上从以下三个方面进行监控:
1) Task数量
Task数量存在过多和过少两种情况,可以通过在4040界面上对Task数量排序进行检查。
对于过多的情况,例如发现某Stage有超过几千上万的Task,应查看是否合理。如上所述的分区分桶导致的任务数量过大就是一个例子。 另外,如果SQL中有针对分区字段的过滤,但是在4040上观察到Task数量的数量仍然很多,需要检查分区剪枝是否成功。
然而,任务数量过少会导致单Task的任务量过大,执行时间过长,也需要进行调整。
2) Task倾斜导致的拖尾。
一般情况的主要成因是某些Key导致的倾斜,如NULL值或者热点地域导致倾斜;还有其他个别情况例如窗口函数导致的单Task任务量过大,引发拖尾。例如我们在某客户业务中遇到,因row_number窗口函数不加partition by,导致单个Task全排序的情况。定位问题后,可采取相应的措施解决。
Case Study:
由4040界面观察出, task 0的单任务执行时间超过10mins。排除由NULL值导致的经典task 0倾斜问题,最后定位是窗口函数row_number不带partition by而导致的全局排序所致。
3) 同时并发执行的stage数量。
一般情况下给定CPU资源以及表的DDL设计后,我们是可以大概确定4040页面的并发任务数总是处在一个合理的范围内。譬如说当前Inceptor配置了400 core,而一般的SQL都操作一个分区的数据,假如这个分区有20个bucket,那么总体上我们应该能够看到同时并发的stage数量应该是 “资源总量 % SQL任务平均任务数”,在这个例子中就是400%20=20个。如果我们观察到并发任务数比预期的要低,这个时候就需要做一些检查。在4040界面上可以观察每个Stage提交到执行结束的时间点,可以监控此类信息,确保执行的合理性。
Case Study:
下图所示为某个测试场景,上一个Stage结束到下一个Stage提交之间的时间间隔超过3mins。分析hive-server2.log发现异常显示有等锁超时的现象,通过有效的规避锁竞争等问题来避免了这个问题,同时也发现系统性能和并发度有较大提升。
总结
本文介绍了关于ETL业务调优的三个思路,并针对每个调优步骤中具体的注意事项和调优原则进行了阐述和分析。
在进行ETL业务调优时,我们要注意把握调优步骤中的关键点,掌握每步骤的调优原则。在遵照一般性原则的基础上,具体问题具体分析,理解和掌握每个步骤可能出现的问题及原因,及时排查解决,将ETL调优尽量应用在关键位置。
下一篇文章我们将通过几则案例,继续介绍其他的几个思路,希望可以帮助读者全面掌握ETL业务调优的具体步骤并加深理解,知道什么时候应该用什么手段实现ETL调优。
感谢原文作者的分享,传送门:http://www.transwarp.cn/news/detail?id=173