最近在完善一个Java HDFS 的Api功能类,其功能列表如下(主要利用文件系统进行文件或目录的各种操作):
上述功能有:
1、获取当前HDFS系统的状态,如容量多少,使用了多少,剩余多少(getStatus())
2、打开一个文件,并返回打开后的FS数据的输出流,便于向文件里编写内容(open(destPath))
3、上传本地(local或remote)文件至HDFS文件系统(upLoadFile(srcPath,destPath,dealSrc,override))
4、文件或目录的重命名(rename(srcPath,destPath))
5、验证HDFS的回收站功能是否开启(trashEnabled()) ....etc
上述功能有:
1、拿到文件系统的回收站路径(getTrashDirPath())
2、将文件或目录移除(搬家)到回收站(开启Hadoop回收站功能,并设置文件的回收周期和检查点,可参考我的上一篇文章)
3、将回收站中指定的文件或目录进行还原(恢复,restoreFromTrash(srcPath,destPath))
4、清空回收站(emptyTrash())
5、打开已存在的文件,并进行文件内容的追加(appendStringToFile(srcPath,content)) ....etc
在进行文件追加内容的demo测试时,报了一段异常,以追加文件1.txt为例
测试demo如下:
/**
* 追加文件,添加内容
*/
@Test
public void appendFile() throws Exception {
initApi();
api.appendStringToFile("1.txt", "2018年6月28日17:49:50");
api.close();
}
运行后,报异常如下:
java.io.IOException: Failed to replace a bad datanode on the existing pipeline due to no more good datanodes being available to try. (Nodes: current=[DatanodeInfoWithStorage[192.168.142.142:9866,DS-739b593f-ef79-4b6f-9e88-99761faf4064,DISK], DatanodeInfoWithStorage[192.168.142.143:9866,DS-be84ef18-1fb3-4859-adee-85eef093ac02,DISK]], original=[DatanodeInfoWithStorage[192.168.142.142:9866,DS-739b593f-ef79-4b6f-9e88-99761faf4064,DISK], DatanodeInfoWithStorage[192.168.142.143:9866,DS-be84ef18-1fb3-4859-adee-85eef093ac02,DISK]]). The current failed datanode replacement policy is DEFAULT, and a client may configure this via 'dfs.client.block.write.replace-datanode-on-failure.policy' in its configuration.
at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.findNewDatanode(DFSOutputStream.java:929)
at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.addDatanode2ExistingPipeline(DFSOutputStream.java:984)
at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.setupPipelineForAppendOrRecovery(DFSOutputStream.java:1131)
at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.run(DFSOutputStream.java:455)
Failed to replace a bad datanode on the existing pipeline due to no more good datanodes being available to try. |
异常意思大概是:由于可用的DataNode不多了,导致当前管道中坏掉的DataNode无法被替换
直接贴出解决方案,在Client端,设置conf的properties如下:
Configuration conf = new Configuration();
/**
* dfs.client.block.write.replace-datanode-on-failure.enable=true
* 如果在写入管道中存在一个DataNode或者网络故障时,
* 那么DFSClient将尝试从管道中删除失败的DataNode,
* 然后继续尝试剩下的DataNodes进行写入。
* 结果,管道中的DataNodes的数量在减少。
* enable :启用特性,disable:禁用特性
* 该特性是在管道中添加新的DataNodes。
* 当集群规模非常小时,例如3个节点或更少时,集群管理员可能希望将策略在默认配置文件里面设置为NEVER或者禁用该特性。
* 否则,因为找不到新的DataNode来替换,用户可能会经历异常高的管道写入错误,导致追加文件操作失败
*/
conf.set("dfs.client.block.write.replace-datanode-on-failure.enable", "true");
/**
* dfs.client.block.write.replace-datanode-on-failure.policy=DEFAULT
* 这个属性只有在dfs.client.block.write.replace-datanode-on-failure.enable设置true时有效:
* ALWAYS :当一个存在的DataNode被删除时,总是添加一个新的DataNode
* NEVER :永远不添加新的DataNode
* DEFAULT:副本数是r,DataNode的数时n,只要r >= 3时,或者floor(r/2)大于等于n时
* r>n时再添加一个新的DataNode,并且这个块是hflushed/appended
*/
conf.set("dfs.client.block.write.replace-datanode-on-failure.policy", "NEVER");
看来集群小了,也是事啊(我本地测试环境,只有两个DataNode,索性直接启动该特性,失败的时候添加新的DataNode)
在运行一次demo,这次无异常抛出
我们下载1.txt到本地,并查看内容如下: