Hive实战-join导致的数据倾斜问题排查

1.场景

如果某个key下记录数远超其他key,在join或group的时候可能会导致某个reduce任务特别慢。本文分析下join的场景。
SQL如下:查询每个appid打开的次数,需要排除掉作弊的imei。
复制代码
SELECT
    appid,
    count(*) 
FROM
    (
    SELECT
        md5imei,
        appid 
    FROM
        (
        SELECT
            t1.md5imei,
            t1.appid,
            t2.cheat_flags 
        FROM
            imei_open_app t1
            LEFT OUTER JOIN cheat_imei t2 ON t1.md5imei = t2.md5imei 
        ) t3 
    WHERE
        t3.cheat_flags IS NULL 
    ) t4 
GROUP BY
    appid;
复制代码

说明:表cheat_imei,7500万条,无大key,为作弊的imei。表imei_open_app,5亿6526万条,为每个imei打开的appid。该表中存在大key,md5imei=54bc0748b1c0fb46135d117b6d26885e的记录数有2亿3659万条。

2.导致的问题

2.1任务卡住

某个reduce task卡在99.9%不动

2.2任务超时被杀掉

Reduce task处理的数据量巨大,在做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。

 3.定位问题

3.1通过时间定位

如果某个reduce的时间比其他reduce时间长的多。(注意:如果每个reduce执行时间差不多,都特别长,则可能是reduce设置过少导致的)。如下图。大部分task在4分钟之内完成,只有r_000021这个task在33分钟内还没完成。

另外注意,这里面需要排除一种特殊情况。有时候,某个task执行的节点可能有问题,导致任务跑的特别慢。这个时候,mapreduce的推测执行,会重启一个任务。如果新的任务在很短时间内能完成,通常则是由于task执行节点问题导致的个别task慢。如果推测执行后的task执行任务也特别慢,那更能说明该task可能会有倾斜问题。

3.2通过任务Counter定位

Counter会记录整个job以及每个task的统计信息。counter的url一般类似:

http://rm:9099/proxy/application_1498075186313_242232/mapreduce/taskcounters/task_1498075186313_242232_r_000017  

  • 通过输入记录数

普通的task counter如下

 而task=000021的counter如下,其输入记录数是2亿4000万。是其他任务的10几倍

  • 通过输出字符数

普通的task counter如下

 

 

 而task=000021的counter如下,是其他任务的几十倍

 4.找到大key及对应SQL执行代码

4.1找到对应的大key

一般情况下,hive在做join的时候,会打印join的日志。我们通过日志查找大key。

  1. 找到任务特别慢的那个task,打开对应日志,url类似于http://rm:8042/node/containerlogs/container_e115_1498075186313_242232_01_000416/hdp-ads-audit/syslog/?start=0
  2. 搜索日志中出现的“rows for joinkey”,如下图
  3. 找到时间跨度最长的那条记录,如下图。比如[54bc0748b1c0fb46135d117b6d26885e],处理的时间从2017-08-03 11:31:30 一直到2017-08-03 11:46:35,耗时15分钟,任务依然没有结束。

。。。。。。由于日志过长,中间部分省略。。。。。。。


另外,从日志中也可能看到,54bc0748b1c0fb46135d117b6d26885e已经处理了236528000条数据,实际情况是该key在imei_open_app中有2亿3659万条数据。该key为导致join倾斜的key。

4.2确定任务卡住的stage

1.通过jobname确定stage

一般通过Hive的默认jobname会带上名称会带上stage阶段,如下为Stage-1。

 2.如果jobname是自定义的,那可能没法通过jobname判断stage。需要借助于任务日志。找到执行特别慢的那个task,搜索 “CommonJoinOperator: JOIN struct” 。Hive在做join的时候,会把join的key打印到日志中,如下。

 上图中的关键信息是struct<_col1:string,_col6:string>

这时候,需要参考该SQL的执行计划。通过参考执行计划,可以断定该阶段为stage1阶段。

 4.3确定SQL执行代码

确定了执行阶段(即stage),那么通过执行计划,就可以判断出是执行哪段代码时出现了倾斜。还是从上图,可以推测出是在执行下面红框中代码时出现了数据倾斜。

 5.解决方案

5.1 过滤掉脏数据

如果大key是无意义的脏数据,直接过滤掉。本场景中大key无实际意义,为脏数据,直接过滤掉。

5.2 数据预处理

数据做一下预处理,尽量保证join的时候,同一个key对应的记录不要有太多。

3.3 增加reduce个数

如果数据中出现了多个大key,增加reduce个数,可以让这些大key落到同一个reduce的概率小很多。

5.4 转换为mapjoin

如果两个表join的时候,一个表为小表,可以用mapjoin做。

5.5 大key单独处理

将大key和其他key分开处理,SQL如下

复制代码
SELECT
    appid,
    count(*) 
FROM
    (
    SELECT
        md5imei,
        appid 
    FROM
        (
        SELECT
            md5imei,
            appid,
            cheat_flags 
        FROM
            ( SELECT md5imei, appid, t2.cheat_flags FROM imei_open_app WHERE md5imei = "54bc0748b1c0fb46135d117b6d26885e" ) t1
            LEFT OUTER JOIN cheat_imei t2 ON t1.md5imei = t2.md5imei UNION ALL
        SELECT
            md5imei,
            appid,
            cheat_flags 
        FROM
            ( SELECT md5imei, appid, t2.cheat_flags FROM imei_open_app WHERE md5imei != "54bc0748b1c0fb46135d117b6d26885e" ) t11
            LEFT OUTER JOIN cheat_imei t12 ON t11.md5imei = t12.md5imei 
        ) t3 
    WHERE
        t3.cheat_flags IS NULL 
    ) t4 
GROUP BY
    appid;
复制代码

 5.6 hive.optimize.skewjoin

会将一个join SQL 分为两个job。另外可以同时设置下hive.skewjoin.key,默认为10000。参考:

https://cwiki.apache.org/confluence/display/Hive/Configuration+Properties。但该

参数对full outer join无效。

5.7 调整内存参数

适用于那些由于内存超限内务被kill掉的场景。通过加大内存起码能让任务跑起来,不至于被杀掉。该参数不一定会降低任务执行时间。

如:

setmapreduce.reduce.memory.mb=5120 ;

setmapreduce.reduce.java.opts=-Xmx5000M -XX:MaxPermSize=128m;

 

posted @   民宿  阅读(602)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
点击右上角即可分享
微信分享提示