调试 Hadoop reducer OutOfMemoryError
Debugging Hadoop reducer OutOfMemoryError
我正在尝试调试 OutOfMemoryError
我正在进入我的 Hadoop 减速器。映射器成功完成。它们生成小于 128 字节的小记录。在我的 reducer 中,我使用相同的键(大约有 15 个可能的键)收集记录,并将它们写入带有 MultipleOutputs
的单独输出文件。每个键的记录分布不均匀。
在减少阶段的中间,我开始得到 OutOfMemoryErrors
。我检查了很多东西:
- reducer不保存数据;一旦它得到一个值,它就会把它写出到相应的输出
- 我为 reduce 任务的数量尝试了不同的值。在我的情况下调整这个有点奇怪,因为超过 15 个将无济于事,因为只有 15 个键
- 在
reduce()
中实例化 MultipleOutputs
并关闭它 ,认为它保留了输出文件的资源。这只有效,因为密钥和输出文件具有一对一的映射。
- 我尝试将数据添加到键的末尾,以便数据在 reduce 任务之间均匀分布
- 摆脱偏执,
mapreduce.reduce.shuffle.memory.limit.percent=0
- 已验证的键和值确实很小
- 禁用输出压缩,认为压缩器中存在内存泄漏
- 盲目调整
mapreduce.reduce.shuffle.merge.percent
除了积极缓冲随机播放输出之外,我不确定内存还能去哪里。
这是使用 Hadoop 3.2.2 的 GCP Dataproc 上的 运行。很多指南推荐设置mapreduce.reduce.java.opts
。我尝试这个没有成功,但我还假设 Google 为主机大小选择了一个合理的默认值,而且我没有关于内存去向的令人信服的故事。我的另一个理论是 GoogleHadoopOutputStream
中写入云存储的内容正在缓冲。我有一些输出文件在 10GB 到 100GB 之间——比机器的内存还大。
我还应该看什么?我应该尝试调整这些其他标志吗?附加 VisualVM 看起来并不容易,但是堆转储会有帮助吗?
每个 GoogleHadoopOutputStream
消耗大约 70 MiB 的 JVM 堆,因为它默认以 64 MiB 块将数据上传到 Google Cloud Storage。这就是为什么如果您使用 MultipleOutputs
在同一个 MR 任务中编写许多对象,每个任务将需要 number of outputs x 70 MiB
个 JVM 堆。
您可以通过 fs.gs.outputstream.upload.chunk.size
property 减少每个 GoogleHadoopOutputStream
消耗的内存,但这也会降低上传到 Google 云存储的速度,这就是为什么更好的方法是重构您的 MR 作业在每个 MR 任务中写入 single/fewer 个文件。
我正在尝试调试 OutOfMemoryError
我正在进入我的 Hadoop 减速器。映射器成功完成。它们生成小于 128 字节的小记录。在我的 reducer 中,我使用相同的键(大约有 15 个可能的键)收集记录,并将它们写入带有 MultipleOutputs
的单独输出文件。每个键的记录分布不均匀。
在减少阶段的中间,我开始得到 OutOfMemoryErrors
。我检查了很多东西:
- reducer不保存数据;一旦它得到一个值,它就会把它写出到相应的输出
- 我为 reduce 任务的数量尝试了不同的值。在我的情况下调整这个有点奇怪,因为超过 15 个将无济于事,因为只有 15 个键
- 在
reduce()
中实例化MultipleOutputs
并关闭它 ,认为它保留了输出文件的资源。这只有效,因为密钥和输出文件具有一对一的映射。 - 我尝试将数据添加到键的末尾,以便数据在 reduce 任务之间均匀分布
- 摆脱偏执,
mapreduce.reduce.shuffle.memory.limit.percent=0
- 已验证的键和值确实很小
- 禁用输出压缩,认为压缩器中存在内存泄漏
- 盲目调整
mapreduce.reduce.shuffle.merge.percent
除了积极缓冲随机播放输出之外,我不确定内存还能去哪里。
这是使用 Hadoop 3.2.2 的 GCP Dataproc 上的 运行。很多指南推荐设置mapreduce.reduce.java.opts
。我尝试这个没有成功,但我还假设 Google 为主机大小选择了一个合理的默认值,而且我没有关于内存去向的令人信服的故事。我的另一个理论是 GoogleHadoopOutputStream
中写入云存储的内容正在缓冲。我有一些输出文件在 10GB 到 100GB 之间——比机器的内存还大。
我还应该看什么?我应该尝试调整这些其他标志吗?附加 VisualVM 看起来并不容易,但是堆转储会有帮助吗?
每个 GoogleHadoopOutputStream
消耗大约 70 MiB 的 JVM 堆,因为它默认以 64 MiB 块将数据上传到 Google Cloud Storage。这就是为什么如果您使用 MultipleOutputs
在同一个 MR 任务中编写许多对象,每个任务将需要 number of outputs x 70 MiB
个 JVM 堆。
您可以通过 fs.gs.outputstream.upload.chunk.size
property 减少每个 GoogleHadoopOutputStream
消耗的内存,但这也会降低上传到 Google 云存储的速度,这就是为什么更好的方法是重构您的 MR 作业在每个 MR 任务中写入 single/fewer 个文件。