2

我们在一张小桌子和一张倾斜的大桌子之间做一个简单的猪连接。"using skewed"由于另一个错误,我们无法使用(猪倾斜连接与大表导致“拆分元数据大小超过 10000000”):(

如果我们使用默认值mapred.job.shuffle.input.buffer.percent=0.70,我们的一些 reducer 在 shuffle 阶段会失败:

org.apache.hadoop.mapred.Task: attempt_201305151351_21567_r_000236_0 : 
Map output copy failure : java.lang.OutOfMemoryError: GC overhead limit exceeded

如果我们将其更改为mapred.job.shuffle.input.buffer.percent=0.30它可以很好地完成,尽管在 2 小时内(我们使用的 1000 个减速器中有 3 个滞后减速器),我们可以在滞后减速器日志中看到如下内容:

SpillableMemoryManager: first memory handler call- 
Usage threshold init = 715849728(699072K) used = 504241680(492423K) committed = 715849728(699072K) max = 715849728(699072K)

为什么会这样?当 shuffle 输入缓冲区为 70% 时,SprilableMemoryManager 为何不能保护我们免于失败?

4

1 回答 1

2

一般来说,mapred.job.shuffle.input.buffer.percent=0.70 不会触发 OutOfMemory 错误,因为这个配置保证了reducer的堆最多有70%用于存储shuffled数据。但是,在我的实践中,有两种情况可能会导致 OutOfMemory 错误。

1) 你的程序有 combine() 函数,而你的 combine() 是消耗内存的。所以在shuffle阶段内存使用可能会超过堆的70%,这可能会导致OutOfMemory错误。但总的来说,Pig 在 Join 运算符中没有 combine()。

2)JVM自己管理内存,将其堆划分为Eden、S0、S1和old space。S0 和 S1 用于 GC。在某些情况下,S0 + S1 + 部分洗牌数据(70% 堆)> 堆大小。于是OutOfMemory 发生了。

如您所述,当 mapred.job.shuffle.input.buffer.percent=0.30 时,只有 30% 的堆用于存储 shuffle 数据,堆很难被填满。我需要job的详细配置(比如Xmx)、数据大小、日志给你一个更具体的答案。

说到 SpillableMemoryManager。Pig 中的默认集合数据结构是“Bag”。包是可溢出的,这意味着如果没有足够的内存来保存 RAM 中包中的所有元组,Pig 会将包的一部分溢出到磁盘。这允许大型作业取得进展,尽管进展缓慢,而不是因“内存不足”错误而崩溃。(此段来自猪的博客

但是shuffle阶段是由Hadoop自己控制的,所以SpillableMemoryManager在shuffle阶段是不生效的(确切的说是在Group By中使用的combine()中生效,但是Join没有combine())。SpillableMemoryManager 通常用于 map()、combine()、reduce() 函数中。这就是为什么当 shuffle 输入缓冲区为 70% 时 SpplilableMemoryManager 不能保护我们免于失败的原因。请注意,Hadoop 不会将所有 shuffle 数据保存在内存中,如果它们太大,它会将部分 shuffle 数据合并到磁盘上。

于 2013-08-14T09:05:44.293 回答