我们有一个java进程,它使用apache commons vfs监听文件系统上的目录X.每当一个新文件被导出到这个目录时,我们的进程就会启动。我们首先将文件重命名为filename.processing并解析文件名,从文件中获取一些信息并插入表中,然后再将这个文件发送到文档管理系统。这是每个群集的单线程应用程序。 现在考虑在集群环境中运行,我们有5台服务器。因此,5个不同的VM正在尝试访问同一个文件。整个实现的基础是,只有一个进程可以在给定时间将文件重命名为.processing,因为操作系统不允许多个进程同时修改文件。一旦群集保持并将文件重命名为.processing,其他群集将忽略格式为.processing的文件。
这项工作一年多以来一直很好,但刚才我们发现很少重复。看起来多个集群都拥有该文件,在这种情况下,集群a,b,c可以访问文件f.pdf,并且同时将它重命名为f.pdf.processing,(我仍然感到困惑,OS如何允许同时修改文件)。由于这些,群集a,b,c他们处理文件并将其发送到文档管理系统。所以现在有3个重复的文件。
因此,简而言之,我所关注的是在集群环境中仅运行一次任务的方法。我还希望它具有故障转移机制,以便在群集出现问题时,另一个群集会接收任务。我们不想在框上设置env变量,例如master = true,因为这会将其限制为仅一个集群,并且不会处理故障转移。
感谢任何形式的帮助。
答案 0 :(得分:1)
请参阅以下有关文件锁定的帖子:How do filesystems handle concurrent read/write?
文件的读写操作(包括重命名)不是原子的,并且在进程之间没有很好地同步,正如您所假设的那样 - 至少在大多数操作系统上都不是这样。
但是,创建新文件通常是原子操作。您可以利用它来获得优势。这个概念称为整个文件锁定。
答案 1 :(得分:1)
我们正在使用应用程序数据库中的共享锁表来实现我们自己的同步逻辑。这允许所有群集节点在实际启动它之前检查作业是否已在运行。
答案 2 :(得分:0)
在将文件重命名为.processing之前,您是否尝试使用FileLock tryLock()或lock()?如果你没有,我认为你应该尝试,所以在这种情况下只允许一个应用程序更改此文件。
更新:抱歉,我忘记了您询问VDF。在Apache VDF中(事实上,在Apache Synapse中)我找到了VFSUtils类,它有以下方法:
public static boolean acquireLock(org.apache.commons.vfs2.FileSystemManager fsManager,
org.apache.commons.vfs2.FileObject fo)
Acquires a file item lock before processing the item, guaranteing that the file is not processed while it is being uploaded and/or the item is not processed by two listeners
Parameters:
fsManager - used to resolve the processing file
fo - representing the processign file item
Returns:
boolean true if the lock has been acquired or false if not
我认为,该方法可以解决您的问题(如果您可以在项目中使用Apache Synapse)。