背景
前天公司一个hive的一个关键任务挂掉,依赖该任务的下游一共有16000个,可谓真tmd的多
由于公司电脑无法写****博客,也无法带出日志,只能我自己描述了
log日志类似于下面
info 1:35:00 Processing rows: 300w Hashtable size: 1900m Memory usage:1600m percentage: 0.87
- 1
当时是我值班,我3点40看到的最后一条日志就是上述部分,看到是mapjoin,然后最后的时间戳为1:35,立马就觉得不太对,毕竟1个多小时了,mapjoin还没有搞定,大概率是出问题了.联系运维杀掉该任务,重跑
问题排查
由于我的岗位是数仓,排查这种东西轮不到我这种sql工程师,不过我自己好奇,百度了mapjoin的原理,大致如下图:
通过日志查找源码:
/**
* Throws MapJoinMemoryExhaustionException when the JVM has consumed the
* configured percentage of memory. The arguments are used simply for the error
* message.
*
* @param tableContainerSize currently table container size
* @param numRows number of rows processed
* @throws MapJoinMemoryExhaustionException
*/
public void checkMemoryStatus(long tableContainerSize, long numRows)
throws MapJoinMemoryExhaustionException {
long usedMemory = ().getUsed();
double percentage = (double) usedMemory / (double) maxHeapSize;
String msg = () + "\tProcessing rows:\t" + numRows + "\tHashtable size:\t"
+ tableContainerSize + "\tMemory usage:\t" + usedMemory + "\tpercentage:\t" + (percentage);
(msg);
if(percentage > maxMemoryUsage) {
throw new MapJoinMemoryExhaustionException(msg);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
确定出现问题的是我圈出来的部分,应该是这部分把数据赛的太慢了,撑爆了jvm
那么考虑个问题,我们设置的mapjoin文件大小为150兆,为啥从日志上来看,jvm已经使用了超过1.6g,差距太大了,原因是:数仓的表是orc的,150m也许解压缩之后就可以到600兆,最后落在jvm,可能就会变成1g起步
解决办法
方法一
减少mapjoin文件大小,这个肯定可以的,不过导致最后性能上不好说,本来可以走mapjoin的,最后凉凉,走mr,本人不建议,不过鉴于该任务特别重要,毕竟下游16000个任务,各位大佬神仙齐聚会议室(我这种小兵没资格),最后领导拍的是这个,我也是醉了,更牛逼的是,将这个阈值直接调成25m,然后所有脚本使用的全局参数调整成25m,生死有命,富贵在天,真是心疼下一任值班同事了
方法二
提升mr local task对应的jvm堆,应该也可以解决该问题,我一路寻找,最后找到了,启动该任务的类
jarCmd = hiveJar + " " + ();
String hiveConfArgs = (conf, ctx);
String cmdLine = hadoopExec + " jar " + jarCmd + " -localtask -plan " + ()
+ " " + isSilent + " " + hiveConfArgs;
- 1
- 2
- 3
- 4
可以考虑去修改hadoop脚本来解决该问题