HiveQL中如何排查数据倾斜问题
引言如果某个key下记录数远超其他key在join或group的时候可能会导致某个reduce任务特别慢。本文分析下join的场景。示例SQL本例子SQL如下查询每个appid打开的次数需要排除掉作弊的imei。说明表cheat_imei7500万条无大key为作弊的imei。表imei_open_app5亿6526万条为每个imei打开的appid。该表中存在大keymd5imei54bc0748b1c0fb46135d117b6d26885e的记录数有2亿3659万条。环境信息Hadoop环境Hadoop 2.6.0-cdh5.8.0 hive-1.1.0-cdh5.8.0大key导致的问题可能会导致下面2个问题某个reduce task卡在99.9%半天不动任务超时被杀掉Reduce处理的数据量巨大在做full gc的时候stop the world。导致响应超时超出默认的600秒任务被杀掉。报错信息AttemptID:attempt_1498075186313_242232_r_000021_1 Timed outafter 600 secs Container killed by the ApplicationMaster. Container killed onrequest. Exit code is 143 Container exited with a non-zero exit code 143。如何判断是大key导致的问题可以通过下面方法判断4.1 通过时间判断如果某个reduce的时间比其他reduce时间长的多。注意如果每个reduce执行时间差不多都特别长则可能是reduce设置过少导致的。如下图。大部分task在4分钟之内完成只有r_000021这个task在30分钟内还没完成。另外注意这里面需要排除一种特殊情况。有时候某个task执行的节点可能有问题导致任务跑的特别慢。这个时候mapreduce的推测执行会重启一个任务。如果新的任务在很短时间内能完成通常则是由于task执行节点问题导致的个别task慢。如果推测执行后的task执行任务也特别慢那更能说明该task可能会有倾斜问题。4.2 通过任务Counter判断Counter会记录整个job以及每个task的统计信息。counter的url一般类似http://rm:9099/proxy/application_1498075186313_242232/mapreduce/taskcounters/task_1498075186313_242232_r_0000171通过输入记录数普通的task counter如下而task000021的counter如下其输入记录数是2亿4000万。是其他任务的10几倍2通过输出字符数普通的task counter如下而task000021的counter如下是其他任务的几十倍如何找到大key及对应SQL执行代码5.1 找到对应大key一般情况下hive在做join的时候会打印join的日志。我们通过日志查找大key。找到任务特别慢的那个task打开对应日志url类似于http://rm:8042/node/containerlogs/container_e115_1498075186313_242232_01_000416/hdp-ads-audit/syslog/?start0搜索日志中出现的rows for joinkey如下图找到时间跨度最大的那条记录如下图比如[54bc0748b1c0fb46135d117b6d26885e]处理的时间从2017-08-03 11:31:30 一直到2017-08-03 11:46:35耗时15分钟任务依然没有结束。。。。。。。由于日志过长中间部分省略。。。。。。。另外从日志中也可能看到54bc0748b1c0fb46135d117b6d26885e已经处理了236528000条数据实际情况该key在imei_open_app中确实有2亿3659万条数据。5.2 确定任务卡住的stage通过jobname确定stage一般通过Hive的默认jobname会带上名称会带上stage阶段如下为Stage-1。如果jobname是自定义的那可能没法通过jobname判断stage。需要借助于任务日志。找到执行特别慢的那个task搜索 CommonJoinOperator: JOIN struct 。Hive在做join的时候会把join的key打印到日志中。如下上图中的关键信息是struct_col1:string,_col6:string这时候需要参考该SQL的执行计划。通过参考执行计划可以断定该阶段为stage1阶段。5.3 确定SQL执行代码确定了执行阶段即stage。通过执行计划则可以判断出是执行哪段代码时出现了倾斜。还是从上图可以推测出是在执行下面红框中代码时出现了数据倾斜。解决方案针对大key数据倾斜问题可以从预防、运行时优化和应急处理三个维度来应对。以下是七种常见方案已按类别重新组织并补充了适用场景或优缺点说明。1. 预防类在数据开发阶段采取措施从源头避免大key的产生。过滤掉脏数据说明如果大key是无意义的脏数据如测试数据、异常值直接过滤掉。适用场景/优缺点适用于大key本身无业务意义的场景如本案例中的异常imei。优点是简单直接、效果显著缺点是可能误伤少量正常数据需结合业务判断。数据预处理说明在ETL或数据清洗阶段对数据进行预处理尽量保证join时同一个key对应的记录数不要过多。适用场景/优缺点适用于数据分布可预测、有固定倾斜模式的场景。优点是能从根源上解决问题缺点是需要额外的计算和存储资源且可能增加数据管道的复杂度。2. 运行时优化类在任务执行时通过调整配置或使用特定技术来缓解或解决倾斜问题。增加reduce个数说明如果数据中出现了多个大key增加reduce个数可以降低这些大key落到同一个reduce的概率。适用场景/优缺点适用于存在多个大key且数据量总体较大的场景。优点是配置简单能一定程度上分散压力缺点是如果单个key的数据量极大增加reduce个数可能无法根本解决且会消耗更多资源。转换为mapjoin说明如果两个表join时其中一个表为小表可以使用mapjoin广播join来避免shuffle和reduce阶段。适用场景/优缺点适用于小表join大表的场景。优点是完全避免了数据倾斜和shuffle性能极佳缺点是要求小表足够小能完全加载到每个Mapper的内存中。hive.optimize.skewjoin说明开启此参数后Hive会将一个倾斜的join SQL拆分为两个job来处理。适用场景/优缺点适用于Hive引擎且已知存在倾斜的join场景。优点是Hive自动处理对用户透明缺点是只对部分join类型有效对full outer join无效且可能增加整体作业运行时间。3. 应急处理类当任务已经因倾斜而运行缓慢或失败时采取的补救措施。大key单独处理说明将大key和其他key分开处理通常使用UNION ALL将大key的查询结果与其他结果合并。适用场景/优缺点适用于大key数量较少且可以明确识别的场景。优点是能精准解决特定key的倾斜问题缺点是SQL逻辑变得复杂且需要提前知道哪些是大key。SQL示例如下调整内存设置说明通过加大Reduce任务的内存参数避免任务因内存不足OOM而被kill。适用场景/优缺点适用于任务因内存超限被kill的应急场景。优点是能让任务先跑起来不至于失败缺点是不会明显降低任务执行时间且可能掩盖根本的性能问题属于“治标不治本”。参数设置示例set mapreduce.reduce.memory.mb5120;set mapreduce.reduce.java.opts-Xmx5000M -XX:MaxPermSize128m;