Hive执行脚本: Return Code 2 from org.apache.hadoop.hive.ql.exec.MapRedTask
0. 写在前面
- Hadoop:Hadoop2.9.2
- Hive:Hive2.3.7
1. 实验场景
离线数仓之留存会员
1. 留存会员与留存率说明
某段时间的新增会员,经过一段时间后,仍继续使用应用认为是`留存会员`
这部分会员占当时新增会员的比例为 留存率
2. 需求:1日、2日、3日的会员留存数和会员留存率
30 |
31 |
1 |
2 |
---- |
10w新会员 | 3w | 1日会员留存数 | ||
20w | 5w | 2日会员留存数 | ||
30w | 4w | 3日会员留存数 |
10W新会员
:dws_member_add_day(dt=08-01) 明细数据
3W
:特点 --> 在1号是新会员,在2日启动了(2日的启动日志)
dws_member_start_day
3. 脚本
- 原始脚本
source /etc/profile if [ -n"$1" ] ;then do_date=$1elsedo_date=`date -d "-1 day" +%F`fisql="insert overwrite table dws.dws_member_retention_daypartition(dt='$do_date')(select t2.device_id, t2.uid, t2.app_v, t2.os_type, t2.language, t2.channel, t2.area, t2.brand, t2.dt add_date, 1from dws.dws_member_start_day t1 join dws.dws_member_add_dayt2 on t1.device_id=t2.device_idwhere t2.dt=date_add('$do_date', -1)and t1.dt='$do_date'union allselect t2.device_id, t2.uid, t2.app_v, t2.os_type, t2.language, t2.channel, t2.area, t2.brand, t2.dt add_date, 2from dws.dws_member_start_day t1 join dws.dws_member_add_dayt2 on t1.device_id=t2.device_idwhere t2.dt=date_add('$do_date', -2)and t1.dt='$do_date'union allselect t2.device_id, t2.uid, t2.app_v, t2.os_type, t2.language, t2.channel, t2.area, t2.brand, t2.dt add_date, 3from dws.dws_member_start_day t1 join dws.dws_member_add_dayt2 on t1.device_id=t2.device_idwhere t2.dt=date_add('$do_date', -3)and t1.dt='$do_date');"hive -e"$sql"
2. 报错信息
- 报错信息
Return Code XXX 一般是
内部错误
3. 解决方法
查看日志信息
前置芝士
Hive中的日志分为 系统日志
和 Job 日志
两种
系统日志
记录了hive的运行情况,错误状况。
Job 日志
记录了Hive 中job的执行的历史过程。
- 系统日志存储位置:
$HIVE_HOME/conf/hive-log4j.properties
文件
- Job日志存储位置:
hive.querylog.location
参数值
hive.log
日志文件「该日志文件内容是比较简略的」
hive.log 在 缺省情况
下 存储位置是:/tmp/「当前用户名字」/hive.log
缺省情况
下该日志文件目录查找方法:
可以在Hive安装目录下的 conf/hive-log4j.properties
中查看
hive-log4j.properties
内容如下:
# Define some default values that can be overridden by system properties hive.root.logger=WARN,DRFA hive.log.dir=/tmp/${user.name} hive.log.file=hive.log # Define the root logger to the system property "hadoop.root.logger". log4j.rootLogger=${hive.root.logger}, EventCounter # Logging Threshold log4j.threshhold=WARN # # Daily Rolling File Appender # log4j.appender.DRFA=org.apache.log4j.DailyRollingFileAppender log4j.appender.DRFA.File=${hive.log.dir}/${hive.log.file} # Rollver at midnight log4j.appender.DRFA.DatePattern=.yyyy-MM-dd # 30-day backup #log4j.appender.DRFA.MaxBackupIndex=30 log4j.appender.DRFA.layout=org.apache.log4j.PatternLayout # Pattern format: Date LogLevel LoggerName LogMessage #log4j.appender.DRFA.layout.ConversionPattern=%d{ISO8601} %p %c: %m%n # Debugging Pattern format log4j.appender.DRFA.layout.ConversionPattern=%d{ISO8601} %-5p %c{2} (%F:%M(%L)) - %m%n # # console # Add "console" to rootlogger above if you want to use this # log4j.appender.console=org.apache.log4j.ConsoleAppender log4j.appender.console.target=System.err log4j.appender.console.layout=org.apache.log4j.PatternLayout log4j.appender.console.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{2}: %m%n #custom logging levels #log4j.logger.xxx=DEBUG # # Event Counter Appender # Sends counts of logging messages at different severity levels to Hadoop Metrics. # log4j.appender.EventCounter=org.apache.hadoop.metrics.jvm.EventCounter log4j.category.DataNucleus=ERROR,DRFA log4j.category.Datastore=ERROR,DRFA log4j.category.Datastore.Schema=ERROR,DRFA log4j.category.JPOX.Datastore=ERROR,DRFA log4j.category.JPOX.Plugin=ERROR,DRFA log4j.category.JPOX.MetaData=ERROR,DRFA log4j.category.JPOX.Query=ERROR,DRFA log4j.category.JPOX.General=ERROR,DRFA log4j.category.JPOX.Enhancer=ERROR,DRFA
在最前面可以看到以下信息:
# 默认 hive.root.logger=WARN,DRFA hive.log.dir=/tmp/${user.name} hive.log.file=hive.log
如果不是 default
情况下,需要到Hive安装目录下的conf目录下查看 hive-site.xml
中的 hive.querylog.location
参数指定的位置
hive.querylog.location
参数的官网说明
- 查看MR的日志「详细」
需要提前开启 历史服务器
+ 打开 日志聚合
+ SQL运行在集群模式
查看MR日志,发现日志的时间点对不上,需要查看是不是打开了 本地模式「local」
- 查看
$HIVE_HOME/conf/hive-site.xml
<!-- 操作小规模数据时,使用本地模式提高效率 --> <property> <name>hive.exec.mode.local.auto</name> <value>true</value> </property>
确认是启用了local模式
直接在脚本中新增 set hive.exec.mode.local.auto = false;
即可
- 重新执行脚本再查看MR日志
此时日志可以查看到, 对于此项目场景
,错误解决方法如下:
- 改动SQL
使用 中间表
进行过渡
不要直接将最终的查询结果插入目标表,而是先插入到中间表,再从中间表查询全部数据插入到目标表中
- 最终脚本
source /etc/profile if [ -n"$1" ] ;then do_date=$1elsedo_date=`date -d "-1 day" +%F`fisql="drop table if exists tmp.tmp_member_retention;create table tmp.tmp_member_retention as( select t2.device_id, t2.uid, t2.app_v, t2.os_type, t2.language, t2.channel, t2.area, t2.brand, t2.dt add_date, 1from dws.dws_member_start_day t1 join dws.dws_member_add_dayt2 on t1.device_id=t2.device_idwhere t2.dt=date_add('$do_date', -1)and t1.dt='$do_date'union allselect t2.device_id, t2.uid, t2.app_v, t2.os_type, t2.language, t2.channel, t2.area, t2.brand, t2.dt add_date, 2from dws.dws_member_start_day t1 join dws.dws_member_add_dayt2 on t1.device_id=t2.device_idwhere t2.dt=date_add('$do_date', -2)and t1.dt='$do_date'union allselect t2.device_id, t2.uid, t2.app_v, t2.os_type, t2.language, t2.channel, t2.area, t2.brand, t2.dt add_date, 3from dws.dws_member_start_day t1 join dws.dws_member_add_dayt2 on t1.device_id=t2.device_idwhere t2.dt=date_add('$do_date', -3)and t1.dt='$do_date');insert overwrite table dws.dws_member_retention_daypartition(dt='$do_date')select * from tmp.tmp_member_retention;"hive -e"$sql"
问题解决
4. 一个有趣的发现
查找资料过程中发现 [StackOverFlow] 有关于这样的回答
I recently faced the same issue/error in my cluster. The JOB would always get to some 80%+ reduction and fail with the same error, with nothing to go on in the execution logs either. Upon multiple iterations and research I found that among the plethora of files getting loaded some were non-compliant with the structure provided for the base table(table being used to insert data into partitioned table).
Point to be noted here is whenever I executed a select query for a particular value in the partitioning column or created a static partition it worked fine as in that case error records were being skipped.
- 翻译如下
我最近在集群中遇到了同样的问题/错误。 JOB 总是会减少 80% 以上,并因同样的错误而失败,执行日志中也没有任何内容。经过多次迭代和研究,我发现在加载的大量文件中,有些文件不符合为基表提供的结构(用于将数据插入分区表的表)。
这里要注意的一点是,每当我对分区列中的特定值执行选择查询或创建静态分区时,它都可以正常工作,因为在这种情况下会跳过错误记录。
其中有一句:
在加载的大量文件中,有些文件不符合为基表提供的结构(用于将数据插入分区表的表)
这句话值得我们关注
5. 参考
https://stackoverflow.com/questions/11185528/what-is-hive-return-code-2-from-org-apache-hadoop-hive-ql-exec-mapredtask https://www.bilibili.com/video/BV1TB4y117vj?p=40&spm_id_from=pageDriver&vd_source=2b8af863001fac2c89aab4db5ba5b9db