Hive万亿级表联合分析故障排查与优化过程

2019-03-11 15:59:12 浏览数 (1)

关键字:

Hive,万亿级,大表,join,联合查询

摘要:

随着大数据技术日趋成熟,行业生态愈发完善,腾讯云大数据团队服务的大客户越来越多。在笔者服务的众多大客户之中,PB级海量数据已经成为常态。笔者负责大数据技术支持的某个腾讯云大数据项目,单张数据表的行数超过万亿级、数据量PB级,而且还需要对万亿级数据表做表与表的多维分析。比如本文介绍的故障排查过程,客户提交的就是 “万亿级大表 join 普通表” 的海量数据关联多维分析任务。这类任务,如果不对大数据平台进行优化,往往很容易运行失败,而且排查过程异常艰难。

一、故障现象

客户的离线海量数据分析任务,底层使用Hive数仓进行存储,并使用hive sql进行分析。因为某些项目原因,hive sql的执行引擎,没有选择spark和tez,最终使用的是mr。客户在半个月前反馈一个故障信息:他们有一类sql任务,无论提交多少次,都会100%失败;其它类型的sql任务,均能运行成功。根据客户反馈的这个信息,可以基本判断,腾讯云大数据平台TBDS内部集成的Hive集群功能绝对是正常的,只是这一类sql任务需要进行 “某方面的故障排查和优化”。

二、故障分析

2.1 sql语句分析

既然是这一类任务均失败,则我们只需要从这一类任务入手分析即可。我们通过项目现场的驻场工程师拿到了sql语句,如下所示:

代码语言:sql复制
create table dbname.tablename row format delimited fields terminated by 't' stored as orc tblproperties ('orc.compression'='snappy') 
as 
SELECT begintime, callduration, usernum, homearea, relatenum, relatehomeac, calltype, callflag, calldesc, imsi, imei, neid, curarea, routerout, routerin, lai, ci, origfileid, relatenumip, longitude, latitude, msid, ipaddress, nai, hamip, pdsnip, pcfip, bsid, esn, roamingid, phs_id, usernum_curarea, relate_lai, relate_curarea, accountno, origin_data, import_time, action_time 
FROM
(
SELECT * FROM 
(SELECT begintime, callduration, usernum, homearea, relatenum, relatehomeac, calltype, callflag, calldesc, imsi, imei, neid, curarea, routerout, routerin, lai, ci, origfileid, relatenumip, longitude, latitude, msid, ipaddress, nai, hamip, pdsnip, pcfip, bsid, esn, roamingid, phs_id, usernum_curarea, relate_lai, relate_curarea, accountno, origin_data, import_time, action_time FROM (select begintime,callduration,usernum,homearea,relatenum,relatehomeac,calltype,callflag,calldesc,imsi,imei,neid,curarea,routerout,routerin,lai,ci,origfileid,relatenumip,longitude,latitude,msid,ipaddress,nai,hamip,pdsnip,pcfip,bsid,esn,roamingid,phs_id,usernum_curarea,relate_lai,relate_curarea,accountno,origin_data,import_time,action_time from simba.dc_cdr) table_1) table_1 
INNER JOIN 
(SELECT field_3 FROM (select field_1,field_2,field_3,import_time from simba.t_res_20190226145527) table_2) table_2 
ON 
table_1.relatenum = table_2.field_3
) join_result;

稍微分析上面的sql语句,可以知道这个任务主要对两张表做join,然后把join的结果存储到一张新表,类似于:

代码语言:sql复制
create table t1 as select xxx from ( t2 join t3) 

按照一般的情况,这类任务也不复杂,属于非常普通的sql任务,为什么会100%失败呢?

我们通过客户那里了解到,sql语句设计到的两张Hive表:simba.dc_cdr是一张大表,大概有1.2万亿行、40列;simba.t_res_20190226145527属于普通表,数据量很小,只有几万行数据。因此,这类任务属于 “万亿级大表 join 普通表” 的海量数据关联多维分析任务。

得到这个信息之后,我们大概知道排查的方向,任务失败多半是因为mapreduce运行过程中,因为某些原因使得部分container出现了OutOfMomery(OOM),这在大表做join的过程中属于常见的故障。至于产生OOM的原因,一般都是两类:数据倾斜导致shuffle过程中部分container数据量过大,超过container内存;另一个原因就是配置的mapper和reducer内存太小。顺着这个思路,我们进行排查。

2.1.1 提高mapper和reducer的参数

我们让现场的同事自己做测试,通过把mapper和reducer的参数从4GB提高到16GB,然后做测试。5个sql任务,全部失败;mapper和reducer的参数再次提高到32GB,依然全部失败。内存参数不足导致的OOM,这个可能的原因被排除了。当然为了保险起见,我们还是建议客户至少设置mapper和reducer的参数不能低于8GB,防止其他sql可能出现内存不足导致的OOM。

2.1.2 排查数据倾斜情况

我们通过排查simba.dc_cdr这张万亿级大表存储在HDFS内部的所有分区的数据量,发现:

(1)这张表每个分区的数据量非常均匀,并不存在数据切斜的情况;

(2)几个关键字段取值,在1.2万亿行中,也不存在明显的取值分布不均衡的情况。 因此,数据倾斜这个因素也被排除了。

2.2 任务日志分析

我们通过分析AM和部分container的日志,确实发现了部分container存在OOM情况。但是,这部分失败的任务都迁移到其它container执行,而且成功。因此,OOM不是这类 “万亿级大表 join 普通表” 的海量数据关联多维分析失败的根本原因。

我们通过现场工程师将日志传递回公司,经过日志分析,发现了这类任务都有一个重要的特征:任务在yarn上面运行的最终状态不是FAILED,全部都是KILLED。这类任务最终是被“KILLED”进而导致失败的。非常诡异的现象呀!

失败的任务状态信息失败的任务状态信息

我们通过分析几个任务的AM日志,也得到以下信息:

AM日志信息AM日志信息
AM日志信息AM日志信息
代码语言:json复制
2019-03-05 01:07:11,046 INFO [IPC Server handler 0 on 3860] org.apache.hadoop.mapreduce.v2.app.client.MRClientService: 
Kill job job_1551324751809_8924 received from simba (auth:TOKEN) at 115.15.3.200

2.3 应用程序排查

既然任务都是被KILLED导致的失败,那么最大的可能就是被应用程序KILLED杀掉了。我们通过与应用程序开发者详细讨论,他们的确使用yarn application -kill命令去杀掉任务的情况,但是仅限于以下两种情况:

(1)任务运行的任务模型本身有误,被甲方客户在应用系统界面点击了“停止运行按钮”,然后应用系统下发了yarn application -kill appid命令杀死任务;

(2)任务运行过程中出现问题,比如无法获取任务的进度、无法获取任务的状态等,此时应用程序会下发yarn application -kill appid命令杀死任务。

我们在现场的同事自己做sql测试,不会触发上述两种情况,因此,这一类任务被“KILLED”,显然不是被应用程序、也不是被人为下发kill命令的。

三、最终确定故障原因

3.1 找出下发kill任务关键信息

既然不是应用程序下发的killed命令,也不是人为下发的kill命令,那么只可能是系统自己下发的kill命令。我们通过排查yarn、hive、mr的源代码,发现主动下发kill application命令的地方很多,如果逐一赛选可能会耗时太久。因此,最方便的方法,还是通过分析日志得到。

首先我们通过查看任务的AM日志、yarn resourcemanager的日志。对照日志分析,应该不是由yarn kill的:

(1)任务是client发起kill的,打日志的地方都在mr的client代码里面;

(2)yarn本身也无法获取到具体用户的认证信息,所以无法以某个用户的身份kill任务,如果kill的话只能以yarn用户身份。因此,确定yarn不会主动发起kill命令;

因此,最可能发起主动kill任务命令的就是hive或者mr。为了得到mr和hive客户端的日志信息,防止hiveserver2的干扰,我们跳过hiveserver2,直接采用原生hive shell进行sql测试,并且读取hive shell客户端的日志。通过日志,我们终于发现问题所在的关键点:

hive 客户端关键日志信息hive 客户端关键日志信息
代码语言:java复制
[Fatal Error] total number of created files now is100004, which exceeds100000. Killing the job.

也就是说,hive sql创建的文件数量运行到此时已经达到100004,超过100000个,因此下发了kill 任务的命令。

我们查看hive的源码,确实也发现了这一段:

Hive源码Hive源码

这段源码在Hive的源码处:apache-hive-2.2.0-srcqlsrcjavaorgapachehadoophiveqlexecmrHadoopJobExecHelper.java,第316到320行:

代码语言:java复制
 if (fatal = checkFatalErrors(ctrs, errMsg)) {
     console.printError("[Fatal Error] "   errMsg.toString()   ". Killing the job.");
     rj.killJob();
     continue;
 }

因此,我们对比日志信息和hive源码信息,可以基本确定,上述日志才是程序真正下发kill命令的根源。

3.2 错误的根源所在

那么怎么解释上述错误的原因呢?这个错误的原因是因为Hive对创建文件的总数有限制(hive.exec.max.created.files),默认是100000个。而客户运行的SQL任务,“万亿级大表 join 普通表” 的关联多维分析任务,在yarn上面观察启动了114486个mapper任务、0个reducer任务:

map任务超过11万个map任务超过11万个

因为每个mapper任务会在HDFS上面创建一个临时文件,因此整个任务需要创建的临时文件也是11万多个,超过了hive.exec.max.created.files默认设置的100000个,因此才会触发hive源码里面的kill命令。为了能够成功地运行上述的SQL,最简单的方法就是加大hive.exec.max.created.files参数的设置。

同时,考虑到分区表的限制因此,我们通过设置以下参数:

代码语言:javascript复制
hive.exec.dynamic.partition=true;
hive.exec.max.dynamic.partitions=5000000;
hive.exec.max.dynamic.partitions.pernode=500000;
hive.exec.max.created.files=5000000;

将hive.exec.max.created.files提高到500万,动态分区参数提高到500万(单节点50万),再次运行任务。最终发现,客户提交的就是“万亿级大表 join 普通表”的海量数据关联多维分析任务运行成功:

几个测试任务都运行成功几个测试任务都运行成功

四、总结

本次客户反馈的 “万亿级大表 join 普通表” 的海量数据关联多维分析任务运行失败故障,也给腾讯云大数据技术支持工作足足上了一堂课:对于真正的海量数据分析场景,系统优化需要做到极致。就拿本次 “万亿级大表 join 普通表” 的hive sql任务而言,如此海量数据分析的任务,使用Hive集群默认参数肯定是要吃亏的。Hadoop的基础组件HDFS、Yarn、mapreduce、Hive、HBase等,在海量数据场景下各种参数都是需要优化到极致的。因此,本次故障排查与优化过程,确确实实让我们意识到,在以后的腾讯云toB大数据项目技术支持过程中,提前对超过100台服务器、数据量超过百TB(甚至PB级)的大型集群进行各种性能优化。

当然,除了大数据集群自身优化以外,数据本身优化也挺重要。比如对于HDFS而言,严格控制小文件数量;对于Hive而言,做好分区以及数据切斜控制;对于HBase而言,设计好regionserver的GC机制等。这些都是需要在部署完成大数据集群以后,提前进行优化。

0 人点赞