今天收到报警Datanode is dead,登录上去看下发现datanode进程还“活着”,没有高负载,内存也正常,datanode日志发现只有几处block传输异常,之后就是在接收block,但是心跳超时导致被NN认为死亡:
1 2 3 4 5 6 7 8 9 | WARN org.apache.hadoop.hdfs.server.datanode.DataNode: IOException inBlockReceiver.run(): java.net.SocketException:Connection reset at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java: 96 ) at java.net.SocketOutputStream.write(SocketOutputStream.java: 136 ) at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java: 65 ) at java.io.BufferedOutputStream.flush(BufferedOutputStream.java: 123 ) at java.io.DataOutputStream.flush(DataOutputStream.java: 106 ) at org.apache.hadoop.hdfs.server.datanode.BlockReceiver$PacketResponder.run(BlockReceiver.java: 1003 ) at java.lang.Thread.run(Thread.java: 662 ) |
查看了ThreadDump(见附1)后终于发现原因:
在pipeline失败后,需要创建一个新的DataXceiver进行pipeline recovery,1.调用recoverRbw方法会锁定FsDatasetImp;2.然后调用stopWriter:即在进行错误恢复时,如果该数据节点的写线程DataReceiver如果还没有结束,要首先中断并等待该线程退出,保证后续恢复:
1 2 3 4 5 6 7 8 9 10 | public void stopWriter() throws IOException { if (writer != null && writer != Thread.currentThread() && writer.isAlive()) { writer.interrupt(); try { writer.join(); } catch (InterruptedException e) { throw new IOException( "Waiting for writer thread is interrupted." ); } } } |
3.同时老的写入线程可能正在提交block,因此需要对FsDatasetImpl进行锁定,这时死锁发生了!!!
4.而Datanode发送Heartbeat前也需要获取FsDatasetImpl的锁定获取节点容量,因此发生超时!
其实这是一个Bug,在CDH4.4.0已经修复了,引入隐藏参数dfs.datanode.xceiver.stop.timeout.millis默认1min,对stopWriter引入超时join.
附1:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | "DataXceiverfor client xxx at xxx [Receiving block xxx]" daemon prio=10tid= 0x00000000406bc000 nid= 0x612d in Object.wait() [ 0x00007ffdcb314000 ] java.lang.Thread.State: WAITING (on objectmonitor) at java.lang.Object.wait(Native Method) atjava.lang.Thread.join(Thread.java: 1186 ) - locked < 0x00000007ca882a30 > (aorg.apache.hadoop.util.Daemon) atjava.lang.Thread.join(Thread.java: 1239 ) atorg.apache.hadoop.hdfs.server.datanode.ReplicaInPipeline.stopWriter(ReplicaInPipeline.java: 157 ) atorg.apache.hadoop.hdfs.server.datanode.fsdataset.impl.FsDatasetImpl.recoverRbw(FsDatasetImpl.java: 707 ) - locked < 0x0000000784acf478 > (aorg.apache.hadoop.hdfs.server.datanode.fsdataset.impl.FsDatasetImpl) atorg.apache.hadoop.hdfs.server.datanode.fsdataset.impl.FsDatasetImpl.recoverRbw(FsDatasetImpl.java: 91 ) atorg.apache.hadoop.hdfs.server.datanode.BlockReceiver.<init>(BlockReceiver.java: 163 ) atorg.apache.hadoop.hdfs.server.datanode.DataXceiver.writeBlock(DataXceiver.java: 457 ) at org.apache.hadoop.hdfs.protocol.datatransfer.Receiver.opWriteBlock(Receiver.java: 103 ) atorg.apache.hadoop.hdfs.protocol.datatransfer.Receiver.processOp(Receiver.java: 67 ) atorg.apache.hadoop.hdfs.server.datanode.DataXceiver.run(DataXceiver.java: 221 ) at java.lang.Thread.run(Thread.java: 662 ) |
1 2 3 4 5 6 | "PacketResponder:xxx, type=HAS_DOWNSTREAM_IN_PIPELINE" daemon prio=10tid= 0x00007ffde0248000 nid= 0x5ed7 waiting for monitor entry [ 0x00007ffdccbf9000 ] java.lang.Thread.State: BLOCKED (on objectmonitor) atorg.apache.hadoop.hdfs.server.datanode.fsdataset.impl.FsDatasetImpl.finalizeBlock(FsDatasetImpl.java: 846 ) - waiting to lock< 0x0000000784acf478 > (a org.apache.hadoop.hdfs.server.datanode.fsdataset.impl.FsDatasetImpl) atorg.apache.hadoop.hdfs.server.datanode.BlockReceiver$PacketResponder.run(BlockReceiver.java: 964 ) atjava.lang.Thread.run(Thread.java: 662 ) |
本文转自MIKE老毕 51CTO博客,原文链接:http://blog.51cto.com/boylook/1313655,如需转载请自行联系原作者