我无法找到一种安全的方法来追加HDFS
中的文件。
我正在使用小3-node Hadoop cluster (CDH v.5.3.9 to be specific)
。我们的进程是一个数据管道器multi-threaded (8 threads)
,它有一个阶段,它将分隔行的文本附加到HDFS
上专用目录中的文件。我正在使用锁来将线程的访问同步到附加数据的缓冲编写器。
我的第一个问题是一般地决定方法。
方法A 是打开文件,附加到文件,然后为附加的每一行关闭它。这似乎很慢,似乎创造了太多的小块,或者至少我在各种帖子中看到了一些这样的情绪。
方法B 是缓存编写器,但是定期刷新它们以确保编写器列表不会无限增长(当前,它是由管道器处理的每个输入文件的一个编写器)。这似乎是一种更有效的方法,但我想在一段时间内有开放流,但是受控制可能是一个问题,特别是对于输出文件读取器(?)
除此之外,我的真正问题是两个。我使用FileSystem Java Hadoop API
进行追加,并且间歇性地获得了这两个例外:
org.apache.hadoop.ipc.RemoteException: failed to create file /output/acme_20160524_1.txt for DFSClient_NONMAPREDUCE_271210261_1 for client XXX.XX.XXX.XX because current leaseholder is trying to recreate file.
org.apache.hadoop.ipc.RemoteException: BP-1999982165-XXX.XX.XXX.XX-1463070000410:blk_1073760252_54540 does not exist or is not under Constructionblk_1073760252_545
40{blockUCState=UNDER_RECOVERY, primaryNodeIndex=1, replicas=[ReplicaUnderConstruction[[DISK]DS-ccdf4e55-234b-4e17-955f-daaed1afdd92:NORMAL|RBW], ReplicaUnderConst
ruction[[DISK]DS-1f66db61-759f-4c5d-bb3b-f78c260e338f:NORMAL|RBW]]}
任何人都有任何想法吗?
对于第一个问题,我尝试过在this post中讨论过的仪器逻辑,但似乎没有帮助。
我也对dfs.support.append
属性的作用感兴趣,如果适用的话。
获取文件系统的代码:
userGroupInfo = UserGroupInformation.createRemoteUser("hdfs"); Configuration conf = new Configuration();
conf.set(key1, val1);
...
conf.set(keyN, valN);
fileSystem = userGroupInfo.doAs(new PrivilegedExceptionAction<FileSystem>() {
public FileSystem run() throws Exception {
return FileSystem.get(conf);
}
});
获取OutputStream的代码:
org.apache.hadoop.fs.path.Path file = ...
public OutputStream getOutputStream(boolean append) throws IOException {
OutputStream os = null;
synchronized (file) {
if (isFile()) {
os = (append) ? fs.append(file) : fs.create(file, true);
} else if (append) {
// Create the file first, to avoid "failed to append to non-existent file" exception
FSDataOutputStream dos = fs.create(file);
dos.close();
// or, this can be: fs.createNewFile(file);
os = fs.append(file);
}
// Creating a new file
else {
os = fs.create(file);
}
}
return os;
}
答案 0 :(得分:2)
我得到了附加CDH 5.3 / HDFS 2.5.0的文件。到目前为止,我的结论如下:
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=[XXX.XX.XXX.XX:50010, XXX.XX.XXX.XX:50010], original=[XXX.XX.XXX.XX:50010, XXX.XX.XXX.XX:50010]). 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:969) ~[hadoop-hdfs-2.5.0.jar:?]
at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.addDatanode2ExistingPipeline(DFSOutputStream.java:1035) ~[hadoop-hdfs-2.5.0.jar:?]
at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.setupPipelineForAppendOrRecovery(DFSOutputStream.java:1184) ~[hadoop-hdfs-2.5.0.jar:?]
at org.apache.hadoop.hdfs.DFSOutputStream$DataStreamer.run(DFSOutputStream.java:532) ~[hadoop-hdfs-2.5.0.jar:?]