java.security.SecureRandom导致jetty、hadoop启动受阻问题

最近解决了一个hadoop启动卡死问题,记录一下。

执行start-all.sh 后,发现namenode的http端口无法访问,hadoop启动失败,查看进程发现各个hadoop的java进程都存在。使用jstack查看namenode的stacktrace,发现如下结果:

[java]  view plain copy
  1. "main" prio=10 tid=0x00000000419e0000 nid=0x5031 runnable [0x00007fa79e3e0000]  
  2.    java.lang.Thread.State: RUNNABLE  
  3.     at java.io.FileInputStream.readBytes(Native Method)  
  4.     at java.io.FileInputStream.read(FileInputStream.java:199)  
  5.     at java.io.BufferedInputStream.read1(BufferedInputStream.java:256)  
  6.     at java.io.BufferedInputStream.read(BufferedInputStream.java:317)  
  7.     - locked <0x00007fa796cb5000> (a java.io.BufferedInputStream)  
  8.     at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)  
  9.     at java.io.BufferedInputStream.read1(BufferedInputStream.java:258)  
  10.     at java.io.BufferedInputStream.read(BufferedInputStream.java:317)  
  11.     - locked <0x00007fa796cb4cc8> (a java.io.BufferedInputStream)  
  12.     at sun.security.provider.SeedGenerator$URLSeedGenerator.getSeedByte(SeedGenerator.java:453)  
  13.     at sun.security.provider.SeedGenerator.getSeedBytes(SeedGenerator.java:123)  
  14.     at sun.security.provider.SeedGenerator.generateSeed(SeedGenerator.java:118)  
  15.     at sun.security.provider.SecureRandom.engineGenerateSeed(SecureRandom.java:114)  
  16.     at sun.security.provider.SecureRandom.engineNextBytes(SecureRandom.java:171)  
  17.     - locked <0x00007fa796cb47d0> (a sun.security.provider.SecureRandom)  
  18.     at java.security.SecureRandom.nextBytes(SecureRandom.java:433)  
  19.     - locked <0x00007fa796cb4b00> (a java.security.SecureRandom)  
  20.     at java.security.SecureRandom.next(SecureRandom.java:455)  
  21.     at java.util.Random.nextLong(Random.java:284)  
  22.     at org.mortbay.jetty.servlet.HashSessionIdManager.doStart(HashSessionIdManager.java:139)  
  23.     at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)  
  24.     - locked <0x00007fa796cb4490> (a java.lang.Object)  
  25.     at org.mortbay.jetty.servlet.AbstractSessionManager.doStart(AbstractSessionManager.java:168)  
  26.     at org.mortbay.jetty.servlet.HashSessionManager.doStart(HashSessionManager.java:67)  
  27.     at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)  
  28.     - locked <0x00007fa7965c8108> (a java.lang.Object)  
  29.     at org.mortbay.jetty.servlet.SessionHandler.doStart(SessionHandler.java:115)  
  30.     at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)  
  31.     - locked <0x00007fa7965c81c8> (a java.lang.Object)  
  32.     at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)  
  33.     at org.mortbay.jetty.handler.ContextHandler.startContext(ContextHandler.java:537)  
  34.     at org.mortbay.jetty.servlet.Context.startContext(Context.java:136)  
  35.     at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1234)  
  36.     at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:517)  
  37.     at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:460)  
  38.     at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)  
  39.     - locked <0x00007fa7966327e0> (a java.lang.Object)  
  40.     at org.mortbay.jetty.handler.HandlerCollection.doStart(HandlerCollection.java:152)  
  41.     at org.mortbay.jetty.handler.ContextHandlerCollection.doStart(ContextHandlerCollection.java:156)  
  42.     at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)  
  43.     - locked <0x00007fa796538ed0> (a java.lang.Object)  
  44.     at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)  
  45.     at org.mortbay.jetty.Server.doStart(Server.java:222)  
  46.     at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)  
  47.     - locked <0x00007fa796441098> (a java.lang.Object)  
  48.     at org.apache.hadoop.http.HttpServer.start(HttpServer.java:461)  
  49.     at org.apache.hadoop.hdfs.server.namenode.NameNode.startHttpServer(NameNode.java:246)  
  50.     at org.apache.hadoop.hdfs.server.namenode.NameNode.initialize(NameNode.java:202)  
  51.     at org.apache.hadoop.hdfs.server.namenode.NameNode.<init>(NameNode.java:279)  
  52.     at org.apache.hadoop.hdfs.server.namenode.NameNode.createNameNode(NameNode.java:956)  
  53.     at org.apache.hadoop.hdfs.server.namenode.NameNode.main(NameNode.java:965)  
 

 

进程卡在了namenode启动内部jetty时获取随机数。

 

既然是随机数的问题,简单写了一个测试代码进行测试,测试代码如下:

[java]  view plain copy
  1. import java.security.SecureRandom;  
  2. import java.util.Random;  
  3. /** 
  4.  * created by haitao.yao @ Apr 1, 2011 
  5.  */  
  6. public class TestRandom {  
  7.     /** 
  8.      * @param args 
  9.      */  
  10.     public static void main(String[] args) {  
  11.         int count = 10;  
  12.         while(count -- > 0){  
  13.             Random random = new SecureRandom();  
  14.             long value = random.nextLong();  
  15.             System.out.println(value);  
  16.         }  
  17.     }  
  18. }  
 

 

由于java.security.SecureRandom在linux上依赖于/dev/random (linux随机数生成机制参见这里),因此在出现问题的服务器上运行测试程序后运行测试脚本,结果如下:

[java]  view plain copy
  1. haitao-yao@haitaoyao-laptop:/data/develop/java/jre/lib/security$ jps && lsof /dev/random   
  2. 7399 Jps  
  3. 7382 TestRandom  
  4. COMMAND  PID       USER   FD   TYPE DEVICE SIZE/OFF NODE NAME  
  5. java    7382 haitao-yao    4r   CHR    1,8      0t0 4402 /dev/random  
 

 

因此断定是由于随机数生成策略的问题。

 

google一下发现jetty的这个bug(Jetty HashSessionIdManager hangs on startup),也有人在jdk的bug database中提出过这个问题(参见这里),简单介绍一下:

java.security.SecureRandom依赖与/dev/random 生成随机数,可能由于系统interrupt不足,导致在jdk在使用/dev/random时卡死。jetty无法启动,最后导致整个namenode启动卡死。

 

解决方案在sun的bug database中也已经有人给出,即在java程序启动参数中添加:-Djava.security.egd=file:/dev/urandom,使用/dev/urandom生成随机数。

 

/dev/random和/dev/urandom的差异分析请参见这里 , 不再多说。

 

总结:

hadoop通过http协议提供html页面暴露系统内部状态,这在分布式系统的设计中是个非常好的feature,但是由于集成了jetty,而集成的jetty在hadoop中可配置性又不强,才暴露了这个问题。非常不理解为什么hadoop不使用独立的线程去启动内部的jetty,毕竟这并不是namenode的主要功能,因为这样的附属功能影响了系统的核心功能,未免有些得不偿失。

 

-EOF-

你可能感兴趣的:(java.security.SecureRandom导致jetty、hadoop启动受阻问题)