在执行Reduce Shuffle的过程中,偶尔会遇到Shuffle Error,但是重启任务之后,Shuffle Error会消失,当然这只是在某些特定情况下才会报出来的错误。虽然在每次执行很短的时间报出这个错误,但是如果单个Reducer的错误数量超出maxAttempt,就会导致整个任务失败。

Error: org.apache.hadoop.mapreduce.task.reduce.Shuffle$ShuffleError: error in shuffle in fetcher#50
at org.apache.hadoop.mapreduce.task.reduce.Shuffle.run(Shuffle.java:121)
at org.apache.hadoop.mapred.ReduceTask.run(ReduceTask.java:380)
at org.apache.hadoop.mapred.YarnChild$2.run(YarnChild.java:162)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:415)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1491)
at org.apache.hadoop.mapred.YarnChild.main(YarnChild.java:157)
Caused by: java.lang.OutOfMemoryError: Java heap space
at org.apache.hadoop.io.BoundedByteArrayOutputStream.<init>(BoundedByteArrayOutputStream.java:56)
at org.apache.hadoop.io.BoundedByteArrayOutputStream.<init>(BoundedByteArrayOutputStream.java:46)
at org.apache.hadoop.mapreduce.task.reduce.InMemoryMapOutput.<init>(InMemoryMapOutput.java:63)
at org.apache.hadoop.mapreduce.task.reduce.MergeManagerImpl.unconditionalReserve(MergeManagerImpl.java:297)
at org.apache.hadoop.mapreduce.task.reduce.MergeManagerImpl.reserve(MergeManagerImpl.java:287)
at org.apache.hadoop.mapreduce.task.reduce.Fetcher.copyMapOutput(Fetcher.java:411)
at org.apache.hadoop.mapreduce.task.reduce.Fetcher.copyFromHost(Fetcher.java:341)
at org.apache.hadoop.mapreduce.task.reduce.Fetcher.run(Fetcher.java:165)

本分析过程同时借鉴了这篇blog:

http://www.sqlparty.com/yarn%E5%9C%A8shuffle%E9%98%B6%E6%AE%B5%E5%86%85%E5%AD%98%E4%B8%8D%E8%B6%B3%E9%97%AE%E9%A2%98error-in-shuffle-in-fetcher/

结合hadoop 2.2.0的源代码来对整个失败过程进行简要分析。

从代码分析来看,最底层Fetcher.run方法执行时出现的错误,在Shuffle.run方法中,会启动一定数量的Fetcher线程(数量由参数mapreduce.reduce.shuffle.parallelcopies决定,我们配置的事50个,是不是有点多,默认是5),Fetcher线程用来从map端copy数据到Reducer端本地。

Fetcher<K,V>[] fetchers = new Fetcher[numFetchers];
for (int i=0; i < numFetchers; ++i) {
fetchers[i] = new Fetcher<K,V>(jobConf, reduceId, scheduler, merger,
reporter, metrics, this,
reduceTask.getShuffleSecret());
fetchers[i].start();
} // Wait for shuffle to complete successfully
while (!scheduler.waitUntilDone(PROGRESS_FREQUENCY)) {
reporter.progress(); synchronized (this) {
if (throwable != null) {
throw new ShuffleError("error in shuffle in " + throwingThreadName,
throwable);
}
}
}

当任意一个Fetcher发生异常时,就会在scheduler的等待后能够在主线程发现,停掉整个Reducer。

public synchronized void reportException(Throwable t) {
if (throwable == null) {
throwable = t;
throwingThreadName = Thread.currentThread().getName();
// Notify the scheduler so that the reporting thread finds the
// exception immediately.
synchronized (scheduler) {
scheduler.notifyAll();
}
}
}

在异常堆栈发生的地方,Fetcher中调用copyFromHost方法,调用到Fetcher的114行,merger.reserve方法会调用MergerManagerImpl.reserve

@Override
public synchronized MapOutput<K,V> reserve(TaskAttemptID mapId,
long requestedSize,
int fetcher
) throws IOException {
if (!canShuffleToMemory(requestedSize)) {
LOG.info(mapId + ": Shuffling to disk since " + requestedSize +
" is greater than maxSingleShuffleLimit (" +
maxSingleShuffleLimit + ")");
return new OnDiskMapOutput<K,V>(mapId, reduceId, this, requestedSize,
jobConf, mapOutputFile, fetcher, true);
}
...

重点是这个canShuffleToMemory方法,它会决定是启动OnDiskMapOutput还是InMemoryMapOutput类,标准就是需要的内存数量小于设置的限制。

private boolean canShuffleToMemory(long requestedSize) {
return (requestedSize < maxSingleShuffleLimit);
}

在初始化MergerManageImpl的时候设置了这个限制,MRJobConfig.REDUCE_MEMORY_TOTAL_BYTES(mapreduce.reduce.memory.totalbytes)这个参数我们并没有设置,因此使用的是Runtime.getRuntime.maxMemory()*maxInMemCopyUse, MRJobConfig.SHUFFLE_INPUT_BUFFER_PERCENT(mapreduce.reduce.shuffle.input.buffer.percent) 参数使用的是0.70,也就是最大内存的70%用于做Shuffle/Merge,比如当前Reducer端内存设置成2G,那么就会有1.4G内存。

final float maxInMemCopyUse =
jobConf.getFloat(MRJobConfig.SHUFFLE_INPUT_BUFFER_PERCENT, 0.90f);
this.memoryLimit =
(long)(jobConf.getLong(MRJobConfig.REDUCE_MEMORY_TOTAL_BYTES,
Math.min(Runtime.getRuntime().maxMemory(), Integer.MAX_VALUE))
* maxInMemCopyUse);
final float singleShuffleMemoryLimitPercent =
jobConf.getFloat(MRJobConfig.SHUFFLE_MEMORY_LIMIT_PERCENT,
DEFAULT_SHUFFLE_MEMORY_LIMIT_PERCENT);
this.maxSingleShuffleLimit =
(long)(memoryLimit * singleShuffleMemoryLimitPercent);

而单个Shuffle最大能够使用多少内存,还需要再乘一个参数:MRJobConfig.SHUFFLE_MEMORY_LIMIT_PERCENT(mapreduce.reduce.shuffle.memory.limit.percent),我们当前并没有设置这个参数,那么默认值为0.25f,此时单个Shuffle最大能够使用1.4G*0.25f=350M内存。

InMemory会在初始化时接收一个size参数,这个size的计算方式暂时未知,用于初始化其BoundedByteArrayOutputStream,

public InMemoryMapOutput(Configuration conf, TaskAttemptID mapId,
MergeManagerImpl<K, V> merger,
int size, CompressionCodec codec,
boolean primaryMapOutput) {

这个size也就是BoundedByteArrayOutputStream作为byte[]的大小:

public BoundedByteArrayOutputStream(int capacity, int limit) {
this(new byte[capacity], 0, limit);
}

OOM也就是出现在这一行。

而我们出的错可能就是出现在判定为使用InMemoryMapOutput但是分配内存时出现的错误,试想使用50个Fetcher线程,单个线程设置为最大接收350M,而堆的最大内存为2G,这样只要有7个Fetcher线程判断为使用InMemoryMapOutput,且同时开始接收数据,就可能造成Java Heap的OOM错误,从而导致Shuffle Error。

我觉得我们可以对使用的参数进行一定的调整,比如说减少Fetcher线程的数量,减少单个Shuffle使用InMemory操作的比例让其OnDisk操作等等,来避免这个问题。

hadoop Shuffle Error OOM错误分析和解决的更多相关文章

  1. MySQL常见错误分析与解决方法总结

    MySQL常见错误分析与解决方法总结 一.Can't connect to MySQL server on 'localhost' (10061)翻译:不能连接到 localhost 上的mysql分 ...

  2. Hadoop org.apache.hadoop.util.DiskChecker$DiskErrorException问题等价解决linux磁盘不足解决问题排查

    org.apache.hadoop.util.DiskChecker$DiskErrorException问题等价解决linux磁盘不足解决问题排查 解决"/dev/mapper/cento ...

  3. vss error reading from file 解决方法

    vss error reading from file 解决方法 1 若服务器中存在 vss/data/backup目录,请将该目录删掉2 运行cmd cd.. cd C:\Program Files ...

  4. Error reading from file 解决办法

    最近安装程序遇见这个问题: Error reading from file. 解决办法: 给这个程序添加权限: 添加SYSTEM的读写改..如果比较懒,直接全部允许. 然后Retry.

  5. hadoop Safe mode is ON 的解决办法

    hadoop Safe mode is ON 的解决办法 搭了一个hadoop集群环境,近期总是出现读写文件错误的情况,查看name node的日志显示 (Safe mode is ON) Safe ...

  6. Hadoop build error java.lang.NoClassDefFoundError: org/sonatype/aether/graph/DependencyFilter

    When running the command: + mvn site site:stage -DskipTests -DskipTest -DskipITs   you get an error: ...

  7. 安装CAD出现Error 1904.Module的解决方法

    在安装AutoCAD2008时,安装过程中出现了一个小错误,虽然说不影响使用,也不影响功能,但还是需要把这个问题解决,今天就和大家分享解决这个问题的方法. 错误描述 会在安装过程中出现错误提示:Err ...

  8. Android studio Error: Modules no specified解决和真机调试

    如何配置SDK百度一大堆: 前言:Android Studio很完善,如果SDK配置好,理论上就是 创建项目->创建个APP(名字自己随便起)->打开手机开发者模式运行即可:如果出了问题, ...

  9. 关于163发邮件报错535 Error:authentication failed解决方法

    关于发邮件报错535 Error:authentication failed解决方法 调用163邮箱服务器来发送邮件,我们需要开启POP3/SMTP服务,这时163邮件会让我们设置客户端授权码,这个授 ...

随机推荐

  1. js中Function的apply方法与call方法理解

    最近在使用jQuery的$.each方法时很,突然想到$.each($('div'),function(index,entity){});中的这个index和entity是哪冒出来的,而且可有可无的, ...

  2. is7.0中发布mvc网站,一直无法正常执行路由的解决办法

    在config中加一句话: <system.webServer> <validation validateIntegratedModeConfiguration="fals ...

  3. 2017-2018-2 20165202 实验三《敏捷开发与XP实践》实验报告

    一.实验报告封面 二.实验内容 XP基础 XP核心实践 相关工具 三.实验步骤 (一)格式化代码 实验要求: 在IDEA中使用工具(Code->Reformate Code)把下面代码重新格式化 ...

  4. React之setState()

    我们知道,在react中更新单个组件下state中的数据可以用setState()函数来实现,并且可以通过两种传参方式:对象.函数. 另外从文档中我们也可以了解到react可以将多个setState( ...

  5. TreeMap实现原理及源码分析

    TreeMap是一个有序的key-value集合,基于红黑树(Red-Black tree)实现.该映射根据其键的自然顺序进行排序,或者根据创建时提供的Comparator进行排序. 对于TreeMa ...

  6. Bandit:一种简单而强大的在线学习算法

    假设我有5枚硬币,都是正反面不均匀的.我们玩一个游戏,每次你可以选择其中一枚硬币掷出,如果掷出正面,你将得到一百块奖励.掷硬币的次数有限(比如10000次),显然,如果要拿到最多的利益,你要做的就是尽 ...

  7. 关于Instruments-Leaks工具的归纳总结

    前言: 本篇文章,在于学习,我把别人的一些感觉好的文章汇总成了一篇,亲自实现了一下,留用于今后学习资料. 文章脉络: 文章脉络: 一.内存优化 简介:Objective_C 有3种内存管理方法, 它们 ...

  8. OPEN(SAP) UI5 学习入门系列之三:MVC (下) - 视图与控制器

    继续来学习UI5的MVC模型吧,这次我们来探讨视图与控制器. 1 视图 在MVC中,视图用来定义和渲染UI.在UI5中,视图的类型是可以自定义的,除了以下预定义的四种视图类型之外,你也可以定制自己的视 ...

  9. 《PyQt5 快速开发与实战》 第九章代码Bug修正 DataGrid.py 最后一页下翻页 仍可点击的错误

    # -*- coding: utf-8 -*- import sys import re from PyQt5.QtWidgets import (QWidget , QHBoxLayout , QV ...

  10. 像黑客一样!Chrome 完全键盘操作指南(原生快捷键 + Vimium 插件)

    有那么一波小伙伴,多数时候都不需要用到鼠标,通常他们正好是“黑客”.当你开始使用键盘操作一切时,便能体会到无需用鼠标瞄准按钮时的干脆,无需在键盘和鼠标之间移动手时的轻松. Chrome 原生自带大量快 ...