Mapreduce 工业界批式计算经验汇总(下)

MR添加缓存文件

Hadoop提供了两种DistributedCache使用方式,一种是通过API,在程序中设置文件路径,另外一种是通过命令行(-files、-archives、-libjars)参数告诉Hadoop,命令行方式使用以下三个参数设置文件:

  1. -files:将指定的本地/hdfs文件分发到各个Task的工作目录下,不对文件进行任何处理;
  2. -archives:将指定文件分发到各个Task的工作目录下,并对名称后缀为".jar"、".zip",".tar.gz"、".tgz"的文件自动解压,默认情况下,解压后的内容存放到工作目录下名称为解压前文件名的目录中,比如压缩包为dict.zip,则解压后内容存放到目录dict.zip中。为此,你可以给文件起个别名/软链接,比如dict.zip#dict,这样,压缩包会被解压到目录dict/dict中。
  3. -libjars:指定待分发的jar包,Hadoop将这些jar包分发到各个节点上后,会将其自动添加到任务的CLASSPATH环境变量中。

社区提供的示例比较好,见https://hadoop.apache.org/docs/r2.6.0/hadoop-mapreduce-client/hadoop-mapreduce-client-core/HadoopStreaming.html#Working_with_Large_Files_and_Archives

Tips: 可以登录 Yarn Container WebShell 来验证所需文件是否被localized到container的执行环境里。

需要注意的是,DistributedCache 是每个 node 只会下载一份,然后同一个 node 上的多个 task 是使用软链共享这一份数据的,因此如果是不允许并发读的数据的话是不能够使用 DistributedCache的。替代方式是手动在 task 中下载。

MR用户主动Debug

找到作业链接

通过 applicationId 在 https://cloud.bytedance.net/megatron/jobs 找到作业链接,例如application_1583916629750_4673851

如果作业id是以"job_xxx"形式开头,请替换成"application_xx"查询

错误诊断

点击"作业诊断"

一般在stderr有错误抛出

或者直接进入web UI查看任务,进入failed查看失败task

进入log链接查看日志

常规错误

Pipe failed

java.lang.RuntimeException: PipeMapRed.waitOutputThreads(): subprocess failed with code 1.

用户进程退出

在stderr一般有退出原因,没有找到多看一些错误的task

如果还是没有找到,很有可能是用户没有把stdin的数据读完主动退出,或者依赖的脚本有exit(0)的逻辑,请用户加日志输出到stderr主动debug

ImportError: No module named xxx

如果用户有用-file, -cacheArchive传递了依赖,请在import之前sleep住脚本(任务必须是运行状态,失败和运行结束的task无法进入webshell),进入webshell查看运行目录是否存在这些依赖(执行appcache)。如果不存在,说明-file, -cacheArchive没有设置正确,请详细检查;如果存在,说明import路径不正确,请认真检查。

执行命令appcache,进入运行目录

如果用-file, -cacheArchive传递依赖不方便,可以使用docker镜像Docker on Yarn

Error: java.lang.RuntimeException: Error in configuring object

可能是Hadoop调不到Mapper和Reducer造成的,检查是否有-file配置;

-file把文件上传到hdfs,container本地化的时候会把这些文件拉到程序的启动目录。

bash 复制代码
hadoop xxx \
-mapper mapper.py \
-file mapper.py \
-reducer reducer.py \
-file reducer.py \

java.lang.ClassNotFoundException

缺相对应的jar包

解决办法:

  1. 通过libjars将缺的jar包传入(多个包中间用逗号隔开,不要加空格),Hadoop将这些jar包分发到各个节点上后,会将其自动添加到任务的CLASSPATH环境变量中,如:
plain 复制代码
-libjars /data01/home/xxx/lib/parquet-common-1.11.0.jar,/data01/home/xxx/lib/parquet-hadoop-1.11.0.jar

在pom.xml文件中加入dependency,然后用shade方式把新引入的依赖包打入jar包里

plain 复制代码
<dependencies> 
    <dependency> 
        <groupId>org.apache.parquet</groupId> 
        <artifactId>parquet-common</artifactId> 
        <version>1.8.3-bd2</version> 
    </dependency> 
    <dependency> 
        <groupId>org.apache.parquet</groupId> 
        <artifactId>parquet-hadoop</artifactId> 
        <version>1.8.3-bd2</version> 
    </dependency> 
</dependencies>
plain 复制代码
<plugin> 
    <groupId>org.apache.maven.plugins</groupId> 
    <artifactId>maven-shade-plugin</artifactId> 
    <executions> 
    <!-- Run shade goal on package phase --> 
    <execution> 
        <phase>package</phase> 
        <goals> 
            <goal>shade</goal> 
        </goals> 
    <configuration> 
     
    <transformers> 
        <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> 
        <!-- <mainClass>${groupId}.${mainClass}</mainClass> --> 
        </transformer> 
    </transformers> 
     
    <createDependencyReducedPom>false</createDependencyReducedPom> 
    </configuration> 
    </execution> 
    </executions> 
</plugin>

OOM:OutOfMemoryError

OOM的问题需要调整相应的内存,详见7. MR任务的CPU内存设置

如果map/reduce很快出现(通常几秒钟)出现oom/java heap的错误,很有可能数据损坏,或者数据格式不正确,需要用户检查数据格式,或者通过打日志输出到stderr进行debug。

reducer copier failed

复制代码
1. 可能是shuffle阶段数据量太大:reducer task数量过少导致heap不足,尝试增大reduce task数量
2. 可能是combiner有问题:combiner需要保证输入和输出的数据格式相同,因为combiner可能会被运行0次,1次或多次。

core dump

一般退出码为137或者139。

公司对core dump做了限制,简单来讲,

  • 所有的core文件均在/opt/tiger/cores路径下;
  • 可以通过container日志链接获取出core的机器,之后请oncall或者自己申请权限;
  • 如果想定制core文件名称,需要在map or reduce的env里设置,比如-D mapreduce.map.env=CORE_DUMP_PROC_NAME={my-core-file-name};

作业启动/运行缓慢

复制代码
1. 
plain 复制代码
20/06/10 15:27:22 INFO mapreduce.Job: MapReduce job is waiting for execution ... 
20/06/10 15:27:54 INFO mapreduce.Job: MapReduce job is waiting for execution ... 
20/06/10 15:28:26 INFO mapreduce.Job: MapReduce job is waiting for execution ... 
20/06/10 15:28:26 INFO mapreduce.Job: Your job wait too much time to start up

作业启动缓慢

当看到提交日志里有"MapReduce job is waiting for execution"时,代表作业启动缓慢,启动指作业从提交到到第一个container(即AM)运行起来的时间,包括为AM申请container的调度时间和NM拉起该container的时间。比如hdfs name node 有故障的时候,启动时长会变长。

  1. 作业运行缓慢

运行指即AM启动后到作业结束前,从Yarn的维度查看是否是调度缓慢或者队列资源不足造成。

如果非调度原因,则需要根据不同的监控来看哪个阶段比较慢,详见【MR作业调优】一节

container is beyond the '2.5' load limit

container报错: Exit Code: -10002 Container [pid=3748398,containerID=container_e159_1627974704104_780030_01_008229] is beyond the '2.5' load limit. Current container load is 11.000063840290364.

原因:混部环境限制load 。load申请超过cpu的2.5倍报错

解决方案:增加cpu申请量(mapreduce.map.cpu.vcores)或者降低 container 的线程数

mapreduce 任务信息经常打不开

无法查看mapreduce任务信息,am日志可以查看,查看am资源【MR任务的CPU内存设置】一节, cpu,mem是否满了,增加yarn.app.mapreduce.am.resource.mb yarn.app.mapreduce.am.resource.cpu-vcores

MR作业调优

常用的优化方式

当 map 输出数据量很大时:

  1. 设置 mapred.compress.map.output=true, 在 map/reduce 间使用压缩数据格式;
  2. 使用 combiner 减少 map/reduce 间 shuffle 的数据量;
  3. 增大 io.sort.factor(缺省为10),加快 map 输出的数据的 merge 并发

慢节点问题

从Counter中查看HDFS的读写时间监控,_DecodeSpentMs 表示读取HDFS的累积时间,单位ms; EncodeSpentNs_表示写入HDFS的时间总和,单位ns。

解决方式

DFSClient Hedged Read是Hadoop-2.4.0引入的一个新特性,如果读取一个数据块的操作比较慢,DFSClient Hedged Read将会开启一个从另一个副本的hedged读操作。

  • dfs.client.hedged.read.enable=true,开启hedged read,
  • dfs.client.hedged.read.threadpool.size 开启多少hedged read线程读block, 默认16
  • dfs.client.hedged.read.threshold.millis,开启一个Hedged 读前的等待时间(毫秒), 默认60s.

MR 控制map数量

先确定是否是以下几种InputFormat,压缩格式的input一般无法修改map数量

对于FileInputFormat

plain 复制代码
minSize = Max(formatMinSize, mapreduce.input.fileinputformat.split.minsize); 
maxSize = mapreduce.input.fileinputformat.split.maxsize; 
blockSize = dfs.block.size;   
splitSize = Math.max(minSize, Math.min(maxSize, blockSize)); 
splitNum = fileLength / splitSize;

dafault值

key value
formatMinSize 与format相关,一般是1
mapreduce.input.fileinputformat.split.minsize 1
mapreduce.input.fileinputformat.split.maxsize Long.MAX_VALUE
dfs.block.size 我们集群是512m

主要是设置 mapreduce.input.fileinputformat.split.maxsize 数值。

大多数的 input format 的基类都是 FileInputFormat,因此都是上面的逻辑。

注意,如果数据是压缩格式,有些压缩格式导致文件不可切分。

对于CombineFileInputFormat

plain 复制代码
minSizeNode = mapreduce.input.fileinputformat.split.minsize.per.node; 
minSizeRack = mapreduce.input.fileinputformat.split.minsize.per.rack; 
maxSplitSize = mapreduce.input.fileinputformat.split.maxsize; 
# 头条自定义参数 
maxSplits = mapreduce.max.splits;

社区逻辑

foreach file

按maxSplitSize将文件切分若干block

统计所有block所在的node和rack

foreach node

将node上的所有block按maxSplitSize的大小生成split

如果node上剩余的block总大小>minSizeNode则将剩余block新建一个split

foreach rack

将rack上所有block按maxSplitSize的大小生成split

如果rack上剩余block总大小>minSizeRack则将剩余block新建一个split

foreach 剩余的小block

将剩余block按maxSplitSize的大小生成split

将剩余block生成split

头条逻辑

plain 复制代码
while(splits.size() > maxSplits): 
  maxSize = Math.max(1, maxSize * (splits.size() / maxSplits + 1)); 
    splits = 社区逻辑

dafault值

key value
mapreduce.input.fileinputformat.split.minsize.per.node 0
mapreduce.input.fileinputformat.split.minsize.per.rack 0
mapreduce.input.fileinputformat.split.maxsize 0
mapreduce.max.splits 50000

CustomCombineFileInputFormat: 合并多个文件

功能

  • 通过将多文件合并为一个 split,减少 split 数(同时也是 map task 数量)

用法

  • 如果未使用 mr 命令,需要在 -libjars 中加入 /opt/tiger/yarn_deploy/hadoop/bytedance-data-1.0.1.jar;
  • 指定 -inputformat com.bytedance.data.CustomCombineFileInputFormat;
  • 如果是PB格式 使用 -inputformat com.bytedance.hadoop.mapred.CombinePBInputFormat
  • 默认只保留一个 split(即所有输入文件合并到一起),可配置 split 数:-Dmapreduce.input.combinefileformat.tasks=10000。
  • **如果数据较大,建议配置到 10000 以上。**任何情况下不要超过 30000。
  • 指定 split 数后,split 的数量将尽量控制在指定值附近(近似)。
  • Hadoop streaming 的参数需要考虑顺序,所有 -D 参数需要出现在非 -D 参数前 ,例如:
    • 正例:

-Dmapreduce.input.combinefileformat.tasks=10000 -inputformat com.bytedance.data.CustomCombineFileInputFormat

  • 反例:-inputformat com.bytedance.data.CustomCombineFileInputFormat -Dmapreduce.input.combinefileformat.tasks=10000

注意

  • 如果之前没有设置 inputformat,streaming 输入可能多出一列 key,需要额外设置

-Dstream.map.input.ignoreKey=true 来忽略。

  • 使用 Combine 以后,Mapper 当中不能再通过环境变量 os.environ['map_input_file'] 获取当前输入文件。此时需要根据字段等其它特性来判别输入数据。

应用:基于MapReduce执行简单并行任务

背景

希望实现一个简单并发执行的作业(用于压测等),这个作业可以控制总的task个数最大并发task个数,但数据不从HDFS中读取。

实现及示例

  1. 增加一个NullInputFormat,作为MapReduce的输入InputFormat格式,其会忽略HDFS的输入,只执行task的逻辑。
  2. 设置reduce个数为0,不需要跑reduce。
  3. 其他的MR参数在此均适用,按需添加,里面配置的hdfs输入输出目录随意设置即可,不会使用到。
plain 复制代码
hadoop fs -rm -R -f hdfs://haruna/user/xxx/no_output 
/opt/tiger/yarn_deploy/hadoop/bin//hadoop jar /opt/tiger/yarn_deploy/hadoop/./share/hadoop/tools/lib/hadoop-streaming-2.6.0-cdh5.4.4.jar \ 
 -D mapreduce.job.name=xxx \ 
 -D mapreduce.job.maps=100 \ 
 -D mapreduce.job.running.map.limit=10 \ 
 -D mapred.reduce.tasks=0 \ 
 -libjars /opt/tiger/yarn_deploy/hadoop/bytedance-data-1.0.3.jar \ 
 -inputformat com.bytedance.data.mapred.NullInputFormat \ 
 -input /user/xxx/no_input \ 
 -output /user/xxx/no_output \ 
 -mapper task.py \ 
 -file task.py

task.py逻辑很简单,

plain 复制代码
#!/usr/bin/env python 
import sys 
 
sys.stderr.write("hello world!")

我该如何使用

Copy上面示例,只需修改下面标记出来的即可,其余的不用修改。

相关推荐
爱吃面的猫8 小时前
大数据Hadoop之——Flink1.17.0安装与使用(非常详细)
大数据·hadoop·分布式
Fireworkitte9 小时前
安装 Elasticsearch IK 分词器
大数据·elasticsearch
ywyy679810 小时前
短剧系统开发定制全流程解析:从需求分析到上线的专业指南
大数据·需求分析·短剧·推客系统·推客小程序·短剧系统开发·海外短剧系统开发
暗影八度12 小时前
Spark流水线数据质量检查组件
大数据·分布式·spark
白鲸开源12 小时前
Linux 基金会报告解读:开源 AI 重塑经济格局,有人失业,有人涨薪!
大数据
海豚调度12 小时前
Linux 基金会报告解读:开源 AI 重塑经济格局,有人失业,有人涨薪!
大数据·人工智能·ai·开源
白鲸开源12 小时前
DolphinScheduler+Sqoop 入门避坑:一文搞定数据同步常见异常
大数据
学术小八13 小时前
第二届云计算与大数据国际学术会议(ICCBD 2025)
大数据·云计算
求职小程序华东同舟求职14 小时前
龙旗科技社招校招入职测评25年北森笔试测评题库答题攻略
大数据·人工智能·科技