我有两个进程在运行。一种是将文件写入HDFS,另一种是加载这些文件。
第一个进程(写入文件的进程)正在使用:
private void writeFileToHdfs(byte[] sourceStream, Path outFilePath) {
FSDataOutputStream out = null;
try {
// create the file
out = getFileSystem().create(outFilePath);
out.write(sourceStream);
} catch (Exception e) {
LOG.error("Error while trying to write a file to hdfs", e);
} finally {
try {
if (null != out)
out.close();
} catch (IOException e) {
LOG.error("Could not close output stream to hdfs", e);
}
}
}
第二个进程读取这些文件以供进一步处理。 创建文件时,首先创建文件,然后填充内容。此过程需要时间(几毫秒,但仍然),在此期间,第二个进程可能会在完全写入和关闭之前拾取文件。
请注意,HDFS不会在namenode中保留锁定信息 - 因此没有守护进程可以在访问之前检查文件是否被锁定。
我想知道解决此问题的最佳方法是什么。
以下是我的想法:
我有一种感觉,我正在努力解决一个众所周知的问题而且我错过了一些东西。这样的问题是否有最佳实践?
答案 0 :(得分:3)
Apache commons有一些东西。只需touch
该文件,错误就会告诉您它是否已被锁定。
import org.apache.commons.io.*
boolean fileAvail = false;
try {
FileUtils.touch(fileName); //throws IOException if being used
fileAvail = true;
} catch (IOException e) {
fileAvail = false;
}
(也)尝试使用资源
在Java 7中,您可以在实现Closable
的任何文件,套接字和数据库连接上使用此功能,只要try块的作用域结束就会自动关闭
try (FSDataOutputStream out = getFileSystem().create(outFilePath))
{
//use out in here
}
//No finally required - catch is optional
...保存所有额外的代码
答案 1 :(得分:2)
您是在同一个(JVM)流程中讨论two separate processes here or about two separate threads吗?
两种方式,这是一个consumer-producer problem,你在生产者和消费者之间缺少的是some proper synchronization。如果您在同一个JVM进程中运行两个线程,则可以使用BlockingQueue
将某种文件传输完成的令牌从生产者传输到消费者,例如例如,文件完全写入并关闭其流后的文件名称。一旦在队列中找到文件名,消费者就可以确定该文件已完全写入并关闭,因为这是由生产者确认的。
但是,如果您使用两个不同的进程,问题有点难以解决,具体取决于其他组件的语言和网络设置,但您必须实现某些可供两者使用的队列例如,通过本地网络端口发送一些信息,以便进程知道彼此的工作。
无论如何,我总是避免在文件系统上移动文件,因为与发送简单令牌相比,这是一个相当昂贵的操作。此外,移动arround文件可能会暴露尚未完全移动的文件,具体取决于您使用的语言。
答案 2 :(得分:0)
你真的需要两个进程吗?为什么不创建两个线程然后加入它。