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上面示例,只需修改下面标记出来的即可,其余的不用修改。

相关推荐
江畔独步3 小时前
Flink TaskManager日志时间与实际时间有偏差
大数据·flink
TDengine (老段)3 小时前
TDengine 选择函数 Last() 用户手册
大数据·数据库·sql·物联网·时序数据库·tdengine·涛思数据
TDengine (老段)4 小时前
TDengine 选择函数 First 用户手册
大数据·数据库·物联网·时序数据库·iot·tdengine·涛思数据
沧海一粟青草喂马5 小时前
抖音批量上传视频怎么弄?抖音矩阵账号管理的专业指南
大数据·人工智能·矩阵
理智的煎蛋6 小时前
CentOS/Ubuntu安装显卡驱动与GPU压力测试
大数据·人工智能·ubuntu·centos·gpu算力
赵孝正6 小时前
GitLab 分支管理与 Push 问题全解析
大数据·elasticsearch·gitlab
嘉禾望岗5037 小时前
Yarn介绍与HA搭建
大数据·hadoop·yarn
小麦矩阵系统永久免费7 小时前
小麦矩阵系统:让短视频分发实现抖音快手小红书全覆盖
大数据·人工智能·矩阵
IT研究室7 小时前
大数据毕业设计选题推荐-基于大数据的国家药品采集药品数据可视化分析系统-Spark-Hadoop-Bigdata
大数据·hadoop·信息可视化·spark·毕业设计·数据可视化·bigdata
Lx3528 小时前
Hadoop性能瓶颈分析:从JVM到磁盘IO的全链路优化
大数据·hadoop