最近公司部署了新的hadoop集群。以前部署的cloudera是阿里云的经典网络。默认是在内网环境,需要vpn才能访问。现在cloudera是部署在专有网络。绑定动态IP后开通相应的端口就能通过公有IP访问对应的服务器节点。
因此,问题来了。在本地公网跑一个程序,往hdfs集群放文件的时候报如下错误。
java.io.IOException: File /user/appuser/sunshine/file/project/seedqueue.txt could only be replicated to 0 nodes instead of minReplication (=1). There are 3 datanode(s) running and 3 node(s) are excluded in this operation.
at org.apache.hadoop.hdfs.server.blockmanagement.BlockManager.chooseTarget4NewBlock(BlockManager.java:1622)
at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.getAdditionalBlock(FSNamesystem.java:3351)
at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.addBlock(NameNodeRpcServer.java:683)
at org.apache.hadoop.hdfs.server.namenode.AuthorizationProviderProxyClientProtocol.addBlock(AuthorizationProviderProxyClientProtocol.java:214)
at org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolServerSideTranslatorPB.addBlock(ClientNamenodeProtocolServerSideTranslatorPB.java:495)
at org.apache.hadoop.hdfs.protocol.proto.ClientNamenodeProtocolProtos$ClientNamenodeProtocol$2.callBlockingMethod(ClientNamenodeProtocolProtos.java)
at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:617)
at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:1073)
at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2216)
at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:2212)
at java.security.AccessController.doPrivileged(Native Method)
at javax.security.auth.Subject.doAs(Subject.java:422)
at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1796)
at org.apache.hadoop.ipc.Server$Handler.run(Server.java:2210)
代码如下:
public static void main(String[] args) {
Configuration conf = new Configuration();
System.setProperty("HADOOP_USER_NAME", "appuser");
conf.set("fs.defaultFS", "hdfs://106.102.93.31:8020");
HdfsUtil hdfsFile = new HdfsUtil(conf);
if(hdfsFile.checkFileExist("/user/appuser/sunshine")){
System.out.println("file is existing!");
}else{
System.out.println("file is not existing!");
}
String srcFile = "C:/tmp/seedqueue.txt";
String dstFile = "/user/appuser/sunshine/file/project/";
hdfsFile.putFile(srcFile, dstFile);
hdfsFile.readFile("/user/appuser/nginx.conf",System.out);
System.out.println();
hdfsFile.getFile("/user/appuser/nginx.conf", "C:/tmp/");
}
上面的代码可以打印"file is existing"。但是当我存放这个txt文件的时候就报错了。查看hdfs对应的文件目录,文件已经被创建,但是大小为0。
查看namde的hdfs日志报同样的错误。
初步分析,Namenode能通过公网IP正常访问。也能读取结构目录。但是往datanode里面读写数据的时候出错。这种情况可能有两个原因,一是namenode和datanode通信的时候出错,或者是本地服务和datanode通信的时候出错。
网上的解决方案大多是format datanode之类的。这个是解决数据版本不一致的问题。我试着在服务器上执行文件上传命令,可以成功。
hadoop fs -put XXX.txt /user/appuser/
这个可以排除是数据版本不一致的问题,也可以排除是namenode和datanode的通信问题。那就还剩一种可能,本地服务和datanode的通信问题。
再回想hdfs的读写机制,dfsClient先从namenode那获取,数据在datanode的存储信息。然后再直接从datanode里面读写数据。关于这个我以前有整理过《Hadoop 原理总结》。
验证猜想,查看namenode的监听IP.
可见,namenode的监听IP正是内网IP。这种情况肯定是和本地的公网IP无法通信的。
所以,解决方案有两个:
- 所有hadoop节点绑定公网IP。这样namenode返回给本地服务的datanode地址就是公网IP;
- 搭建内网访问的VPN。这样连上vpn后就可以采用内网IP进行通信。
第一种相对麻烦,修改的配置较多,容易出错。我采用的是第二种,用pptpd搭建一个VPN。这是我以前记录的搭建pptpd的方式,可以参考一下《阿里云ecs pptpd vpn配置》。
网友评论