阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Hadoop DataNode OOM故障及解决方案

190次阅读
没有评论

共计 9343 个字符,预计需要花费 24 分钟才能阅读完成。

一、故障症状

跑大任务时,datanode 日志报 DataXceiveServer: Exiting due to:java.lang.OutOfMemoryError: unable to create new native thread 异常,然后计算节点上的 DataNode 直接挂掉。DataNode 异常日志截图如下:

2014-03-06 03:41:05,881 ERROR org.apache.Hadoop.hdfs.server.datanode.DataNode: DatanodeRegistration(172.16.8.5:50010, storageID=DS-2085721072-172.16.8.5-50010-1386684967398, infoPort=50075, ipcPort

=50020):DataXceiveServer: Exiting due to:java.lang.OutOfMemoryError: unable to create new native thread

TaskTracker 上的异常日志信息:

2014-03-06 03:43:52,760 ERROR org.apache.hadoop.security.UserGroupInformation: PriviledgedActionException as:job_201403051809_0018 cause:java.io.IOException: Unknown task; attempt_201403051809_0018_r_000000_0. Ignoring getMapCompletionEvents Request

2014-03-06 03:43:52,760 ERROR org.apache.hadoop.security.UserGroupInformation: PriviledgedActionException as:job_201403051809_0018 cause:java.io.IOException: Unknown task; attempt_201403051809_0018_r_000000_0. Ignoring getMapCompletionEvents Request

二、解决故障思路分析

从 TaskTracker 的异常日志来看,报的是一个 IO 异常,反应的情况是无法从 HDFS 中获取到 job 的信息,另外日志中的“Ignoring getMapCompletionEvents Request”则是 Reduce Task 中的 GetMapEventsThreads 线程抛出的,该线程的主要作用是周期性通过 RPC 从 TaskTracker 获取已经完成的 Map Task 列表,为 shuffle 阶段做准备的。再联系 DataNode 上的异常日志信息我们知道 DataNode 进程由于出现 OOM 而挂掉了,那么在 TaskTracker 中获取不到 HDFS 上的作业信息也就可以解析了,因此得出一个结论:TaskTracker 中的异常是由于 DataNode 进程挂掉引起的。接下来,将精力转到 DataNode 上的 OOM 分析。

TaskTracker 报 OOM 异常我们见多了,最常见的就是 reduce 阶段的内存溢出,另外可能在 map 阶段中的 sort 和 spill 中,也就是 io.sort.mb 参数所控制的环形内存所做的快速排序上出现内存溢出,但是 map 阶段的内存溢出几率还是比较少的,因为通常默认情况下一个 map 只是处理一个数据块(一个 block 左右的大小),而且一般 io.sort.mb 设置都比一个 block 大小要大。另外 TaskTracker 上的 OOM 还可以通过 mapred.map.child.java.opts 来进行调整。那么对于现在这种情况,在 DataNode 上出现 OOM,第一感觉是不是 HADOOP_HEAPSIZE 配置的太小了导致 DataNode 和 TaskTracker 进程不够内存用(这个值使用默认的 1000m)?但是仔细想想觉得不怎么可能,因为集群是刚刚部署不久的,数据存储量还不是很多。但是为了测试还是将 HADOOP_HEAPSIZE 跳到了 2000,再跑任务测试,不幸的是 DataNode 还是出现 OOM,进而挂掉。此时,我想会不会是什么配置限制了内存的使用或者限制了新线程的创建?于是看看系统的限制参数,如下图:

Hadoop DataNode OOM 故障及解决方案

看了上面的参数,open files 是当初改大了的,max user processes 这个参数是系统默认的 1024。起初对这个变量值的认识只是认为它仅仅限制了系统的最大进程数,又为了安全起见上网查查看,惊喜地发现,原来这个参数会对系统中所有 application 创建的总线程数有限制的(具体情况请参考:http://www.linuxidc.com/Linux/2014-03/97857p2.htm)。这样一下子明白什么回事了,将 max user processes 调大,调到 81920(可以直接在 bash_profiles 添加 ulimit -u 81920 进行设置)。设置完了,如图:

Hadoop DataNode OOM 故障及解决方案

起任务再跑,观察 DataNode 日志,一切正常,不会出现 OOM,稳!!

二、总结

OOM 是 hadoop 集群运行时比较容易出现的故障,其解决方案也各有不同,要看实际情况而定。对于在 Map 或者 reduce 出现的 OOM 故障还是比较容易处理的,具体的可以看上面分析,对于 DataNode 中的 OOM 故障,其原因还是比较隐蔽的,需要一定的运维知识和工作经验的积累。

相关阅读

Ubuntu 13.04 上搭建 Hadoop 环境 http://www.linuxidc.com/Linux/2013-06/86106.htm

Ubuntu 12.10 +Hadoop 1.2.1 版本集群配置 http://www.linuxidc.com/Linux/2013-09/90600.htm

Ubuntu 上搭建 Hadoop 环境(单机模式 + 伪分布模式)http://www.linuxidc.com/Linux/2013-01/77681.htm

Ubuntu 下 Hadoop 环境的配置 http://www.linuxidc.com/Linux/2012-11/74539.htm

单机版搭建 Hadoop 环境图文教程详解 http://www.linuxidc.com/Linux/2012-02/53927.htm

搭建 Hadoop 环境(在 Winodws 环境下用虚拟机虚拟两个 Ubuntu 系统进行搭建)http://www.linuxidc.com/Linux/2011-12/48894.htm

更多 Hadoop 相关信息见Hadoop 专题页面 http://www.linuxidc.com/topicnews.aspx?tid=13

java.lang.OutOfMemoryError: unable to create new native thread

早上到了公司,据称产品环境抛出了最可爱的异常—OutOfMemory, 它是这样来描述他自己的:

java.lang.OutOfMemoryError: unable to create new native thread

而且这位仁兄竟然还堂而皇之地同时出现在了 3 个 application 里面,所有应用全部遭殃。

那可爱的 OOM 是如何产生的呢?直接原因是创建的线程太多了,根本原因是某个地方的内存限制了。

搜罗了一下在网上找到了一个计算公式:

(MaxProcessMemory – JVMMemory – ReservedOsMemory) / (ThreadStackSize) = Number of threads

MaxProcessMemory:进程最大的寻址空间,但我想这个值应该也不会超过虚拟内存和物理内存的总和吧。关于不同系统的进程可寻址的最大空间,可参考下面表格:

Maximum Address Space Per Process

Operating System

Maximum Address Space Per Process

RedHat Linux 32 bit

2 GB

Redhat Linux 64 bit

3 GB

Windows 98/2000/NT/Me/XP

2 GB

Solaris x86 (32 bit)

4 GB

Solaris 32 bit

4 GB

Solaris 64 bit

Terabytes

JVMMemory: Heap + PermGen

ReservedOSMemory:Native heap,JNI

便可推导出单个 JVM Instance 可支持的最大线程数的估计值:

(MaxProcessMemory< 固定值 > – Xms< 初始化值,最小值 > – XX:PermSize< 初始化值,最小值 > – 100m< 估算值 >) / Xss = Number of threads< 最大值 >

在本地 (32bit windows) 试了试,可达的线程的最大值差不多就是这个数,它不受物理内存的限制,会利用虚拟内存,从任务管理器看到 memory 已经是 5500 m 左右了(开了两个 jvm),我机器的物理内存是 2g,也不知道这个准不准,后来还抛出了“unable to create new native thread”的兄弟“Exception in thread “CompilerThread0” java.lang.OutOfMemoryError: requested 471336 bytes for Chunk::new. Out of swap space?“。

本地测完了后,就该轮到 dev 环境了,linux2.6,64bit,双核,8G(虚拟机),总的物理内存是 16g。在上面整了一下,创建到了 15000 多个线程的时候挂掉了。此时其他 application 也不能创建新的线程,而且 db 也报错了,操作系统不能 fork 新的线程了。这应该是操作系统的哪里限制了新线程的创建,

·        max thread,linux2.6 似乎是 32000

·        最大可用内存:物理内存 + 虚拟内存

·        配置,在 linux 可以限制可用资源的大小,show 一下这些参数

core file size          (blocks, -c) 0
data seg size          (kbytes, -d) unlimited
file size              (blocks, -f) unlimited
pending signals                (-i) 1024
max locked memory      (kbytes, -l) 32
max memory size        (kbytes, -m) unlimited
open files                      (-n) 65536
pipe size            (512 bytes, -p) 8
POSIX message queues    (bytes, -q) 819200
stack size              (kbytes, -s) 10240
cpu time              (seconds, -t) unlimited
max user processes              (-u) 16384
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

为了进一步确定在 linux 上一个 jvm 因为达到了最大寻址空间 OOM 了,不会影响其他 jvm,我在 Linux 做了进一步测试,一开始用 Sun 文档中说的最大寻址空间 3G 试了一下,发现根本不对,达到了 3G 后还是非常 high 地在创建新的线程。于是出动超级无敌变态的 JVM 初始化配置。

Oracle  27408 27017 12 13:45 ?        00:00:07 /home/oracle/ias1013/FWAPP/FWDev/jdk/bin/java -server -Xmx4096m -Xms4096m -XX:+HeapDumpOnOutOfMemoryError -XX:PermSize=4096m -XX:MaxPermSize=4096m -XX:HeapDumpPath=/home/oracle/ias1013/FWAPP/FWDev/j2ee/OC4J_OOMTest/workEnv/log -Xss100m

结果在 create 3379 个线程后,“unable to create new native thread”出现了,这时其他 jvm 都是可以 create 新线程的。如果按照上面公式计算,linux 64bit,2.6kernel,它的最大寻址空间肯定超过了 300g,当然应该还没有达到可用内存的限制,因为其他 JVM 还能 create 新线程。

我还怀疑是不是 oracle application server 上的某个配置参数限制了总的线程数,影响了所有 application,但我们的产品环境一个 application 就是一个单独的 application server。

现在基本上可以确定是操作系统哪里设置错了,我想 System team 的帅哥们应该把产品环境的某个参数配置错了,系统本身的影响肯定不会有了,因为产品环境上我们只 create 了 800 左右个线程,就 OOM 了,那应该就是配置的问题了,怀疑的参数有下面四个

max user processes              (-u) 2048

virtual memory          (kbytes, -v) unlimited

max memory size        (kbytes, -m) unlimited

stack size              (kbytes, -s) 10240

最后发现只有 max user processes 和 virtual memory 对总的线程数有影响,我把 max user processes 降到 2048 后,发现此时只能创建 2000 左右个线程了(Xms64m, Xss1m),进一步地把 virtual memory 下调到 2048000K 发现能创建的就更少了 1679(Xms64m, Xss1m),但 virtual memory 只对单个进程有效,不会影响其他 jvm,可以确定它是来打酱油的。另外两个参数好像就是来做俯卧撑的,操作系统 stack size 是不应该会有什么影响,我们把它上调到 102400,还是可以创建 2000 左右的线程数(max user processes),因为 java 有自己的线程模型,它的栈的大小是用 Xss 来控制的。Max memory size 不知道是啥东东,照理说如果是最大内存应该不会只在旁边做俯卧撑,那这个参数到底是春哥还是曾哥,查了一下 man ulimit,有下面解释

              -a    All current limits are reported

              -c    The maximum size of core files created

              -d    The maximum size of a process data segment

              -f    The maximum size of files created by the shell

              -l    The maximum size that may be locked into memory

              -m    The maximum resident set size (has no effect on Linux)

              -n    The maximum number of open file descriptors (most systems do not allow this value to be set)

              -p    The pipe size in 512-byte blocks (this may not be set)

              -s    The maximum stack size

              -t    The maximum amount of cpu time in seconds

              -u    The maximum number of processes available to a single user

              -v    The maximum amount of virtual memory available to the shell

“Has no effect on Linux”就足以证明它确实只是来做做俯卧撑的。最后查出只有“max user processes”会对所有 application 能创建总的线程数有限制。

一、故障症状

跑大任务时,datanode 日志报 DataXceiveServer: Exiting due to:java.lang.OutOfMemoryError: unable to create new native thread 异常,然后计算节点上的 DataNode 直接挂掉。DataNode 异常日志截图如下:

2014-03-06 03:41:05,881 ERROR org.apache.Hadoop.hdfs.server.datanode.DataNode: DatanodeRegistration(172.16.8.5:50010, storageID=DS-2085721072-172.16.8.5-50010-1386684967398, infoPort=50075, ipcPort

=50020):DataXceiveServer: Exiting due to:java.lang.OutOfMemoryError: unable to create new native thread

TaskTracker 上的异常日志信息:

2014-03-06 03:43:52,760 ERROR org.apache.hadoop.security.UserGroupInformation: PriviledgedActionException as:job_201403051809_0018 cause:java.io.IOException: Unknown task; attempt_201403051809_0018_r_000000_0. Ignoring getMapCompletionEvents Request

2014-03-06 03:43:52,760 ERROR org.apache.hadoop.security.UserGroupInformation: PriviledgedActionException as:job_201403051809_0018 cause:java.io.IOException: Unknown task; attempt_201403051809_0018_r_000000_0. Ignoring getMapCompletionEvents Request

二、解决故障思路分析

从 TaskTracker 的异常日志来看,报的是一个 IO 异常,反应的情况是无法从 HDFS 中获取到 job 的信息,另外日志中的“Ignoring getMapCompletionEvents Request”则是 Reduce Task 中的 GetMapEventsThreads 线程抛出的,该线程的主要作用是周期性通过 RPC 从 TaskTracker 获取已经完成的 Map Task 列表,为 shuffle 阶段做准备的。再联系 DataNode 上的异常日志信息我们知道 DataNode 进程由于出现 OOM 而挂掉了,那么在 TaskTracker 中获取不到 HDFS 上的作业信息也就可以解析了,因此得出一个结论:TaskTracker 中的异常是由于 DataNode 进程挂掉引起的。接下来,将精力转到 DataNode 上的 OOM 分析。

TaskTracker 报 OOM 异常我们见多了,最常见的就是 reduce 阶段的内存溢出,另外可能在 map 阶段中的 sort 和 spill 中,也就是 io.sort.mb 参数所控制的环形内存所做的快速排序上出现内存溢出,但是 map 阶段的内存溢出几率还是比较少的,因为通常默认情况下一个 map 只是处理一个数据块(一个 block 左右的大小),而且一般 io.sort.mb 设置都比一个 block 大小要大。另外 TaskTracker 上的 OOM 还可以通过 mapred.map.child.java.opts 来进行调整。那么对于现在这种情况,在 DataNode 上出现 OOM,第一感觉是不是 HADOOP_HEAPSIZE 配置的太小了导致 DataNode 和 TaskTracker 进程不够内存用(这个值使用默认的 1000m)?但是仔细想想觉得不怎么可能,因为集群是刚刚部署不久的,数据存储量还不是很多。但是为了测试还是将 HADOOP_HEAPSIZE 跳到了 2000,再跑任务测试,不幸的是 DataNode 还是出现 OOM,进而挂掉。此时,我想会不会是什么配置限制了内存的使用或者限制了新线程的创建?于是看看系统的限制参数,如下图:

Hadoop DataNode OOM 故障及解决方案

看了上面的参数,open files 是当初改大了的,max user processes 这个参数是系统默认的 1024。起初对这个变量值的认识只是认为它仅仅限制了系统的最大进程数,又为了安全起见上网查查看,惊喜地发现,原来这个参数会对系统中所有 application 创建的总线程数有限制的(具体情况请参考:http://www.linuxidc.com/Linux/2014-03/97857p2.htm)。这样一下子明白什么回事了,将 max user processes 调大,调到 81920(可以直接在 bash_profiles 添加 ulimit -u 81920 进行设置)。设置完了,如图:

Hadoop DataNode OOM 故障及解决方案

起任务再跑,观察 DataNode 日志,一切正常,不会出现 OOM,稳!!

二、总结

OOM 是 hadoop 集群运行时比较容易出现的故障,其解决方案也各有不同,要看实际情况而定。对于在 Map 或者 reduce 出现的 OOM 故障还是比较容易处理的,具体的可以看上面分析,对于 DataNode 中的 OOM 故障,其原因还是比较隐蔽的,需要一定的运维知识和工作经验的积累。

相关阅读

Ubuntu 13.04 上搭建 Hadoop 环境 http://www.linuxidc.com/Linux/2013-06/86106.htm

Ubuntu 12.10 +Hadoop 1.2.1 版本集群配置 http://www.linuxidc.com/Linux/2013-09/90600.htm

Ubuntu 上搭建 Hadoop 环境(单机模式 + 伪分布模式)http://www.linuxidc.com/Linux/2013-01/77681.htm

Ubuntu 下 Hadoop 环境的配置 http://www.linuxidc.com/Linux/2012-11/74539.htm

单机版搭建 Hadoop 环境图文教程详解 http://www.linuxidc.com/Linux/2012-02/53927.htm

搭建 Hadoop 环境(在 Winodws 环境下用虚拟机虚拟两个 Ubuntu 系统进行搭建)http://www.linuxidc.com/Linux/2011-12/48894.htm

更多 Hadoop 相关信息见Hadoop 专题页面 http://www.linuxidc.com/topicnews.aspx?tid=13

正文完
星哥说事-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-20发表,共计9343字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中