Java集群,运行只任务一次

Java cluster, run task only once

我们有一个 java 进程,它使用 apache commons vfs 侦听文件系统上的目录 X。每当将新文件导出到此目录时,我们的流程就会启动。我们首先将文件重命名为 filename.processing 并解析文件名,从文件中获取一些信息并插入表中,然后再将此文件发送到 Document管理系统。这是每个集群的单线程应用程序。 现在在集群环境中考虑这个 运行ning,我们有 5 个服务器。所以 5 个不同的 VM 正在尝试访问同一个文件。整个实现的基础是在给定时间只有一个进程可以将文件重命名为 .processing,因为 OS 不允许多个进程同时修改文件。一旦集群获取并重命名文件为.processing,其他集群将忽略格式为.processing 的文件。

一年多以来一直运行良好,但现在我们几乎没有发现重复项。看起来多个集群都获得了文件,在这种情况下,集群 a、b、c 获得了文件 f.pdf 的访问权限,并且他们同时将其重命名为 f.pdf.processing,(我仍然对 OS 如何允许同时修改文件感到困惑)。结果,集群 a、b、c 处理了文件并将其发送到文档管理系统。所以现在有3个重复文件。

所以简而言之,我所关注的是,在集群环境中仅执行一次 运行 任务。我还希望它有一个故障转移机制,这样如果集群出现问题,另一个集群就会接手这个任务。我们不想设置 env 变量,比如在一个盒子上设置 master=true,因为这会将它限制在一个集群中,并且不会处理故障转移。

感谢任何形式的帮助。

参见以下关于文件锁定的post:How do filesystems handle concurrent read/write?

文件的读写操作(包括重命名)不是原子的,并且进程之间的同步也不是很好,正如您假设的那样 - 至少在大多数操作系统上不是这样。

但是,创建新文件通常是一个原子操作。你可以利用它来发挥你的优势。这个概念叫做全文件锁定。

在将文件重命名为 .processing 之前,您是否尝试使用 FileLock tryLock() 或 lock()?如果你没有,我想你应该试试,所以在这种情况下,只有一个应用程序可以允许更改此文件。

更新:对不起,我忘了你问的是VDF。在 Apache VDF 中(事实上,在 Apache Synapse) I found VFSUtils class 中,有以下方法:

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)。

我们正在应用程序数据库中使用共享锁 table 实现我们自己的同步逻辑。这允许所有集群节点在实际启动作业之前检查作业是否已经 运行。