我有一个文件夹,上游系统会转储为我的应用程序输入的文件。我的应用程序读取这些文件,处理它们然后在某个目录中输出。由于输入文件的数量很大,我决定运行我的应用程序的多个实例,所有实例都将读取输入文件的相同输入目录。现在,由于多个实例将读取同一文件夹,如何防止多个实例同时读取同一文件?
PS:我想过使用Spring集成NIO锁,但是一旦锁定文件,即使同一个线程也无法读取文件。 Camel处理锁定但它锁定了整个目录,并且在2个实例试图获取尚未锁定的文件的那段时间内也没有处理场景。任何建议都会有所帮助。
答案 0 :(得分:2)
Spring Integration为此目的提供CREATE TABLE UpdateTest
(
ID int IDENTITY,
Name varchar(10),
Modified datetime2(2) CONSTRAINT DF_Modified DEFAULT (SYSDATETIME())
)
--ID from IDENTITY, Modified from DEFAULT implicitly
INSERT UpdateTest(Name) VALUES('Test')
--Modified from DEFAULT explicitly
UPDATE UpdateTest SET Name='Test2', Modified=DEFAULT
。您可以使用共享FileSystemPersistentAcceptOnceFileListFilter
impl进行配置,例如ConcurrentMetadataStore
或RedisMetadataStore
。
只有一个应用程序实例会接受一个文件。
尽管存在一些限制,但所有文件只能由一个实例应用:
ZookeeperMetadataStore
您可以克服分布式private void scanInputDirectory() {
List<File> filteredFiles = this.scanner.listFiles(this.directory);
Set<File> freshFiles = new LinkedHashSet<File>(filteredFiles);
if (!freshFiles.isEmpty()) {
this.toBeReceived.addAll(freshFiles);
if (logger.isDebugEnabled()) {
logger.debug("Added to queue: " + freshFiles);
}
}
}
的单例问题,例如MessageChannel
,SubscribableJmsChannel
或任何其他基于PublishSubscribeAmqpChannel
的队列渠道解决方案。
答案 1 :(得分:1)
我不会这样做,因为阅读包含多个实例的文件夹只会使你的流程变得复杂。
我会改为使用单一路径读取文件并将内容放在队列中(可以是jms,amqp等)以及文件名作为标题。然后,您可以在该队列上进行并行处理,并并行写入目标文件夹。这将使您的解决方案更易于处理和扩展,以防您需要阅读其他文件夹。
答案 2 :(得分:0)
您可以为应用程序实例已读取的每个文件创建一个影子文件
为了避免对同一文件进行concancent访问的问题,您需要集中检查一个Thread或一个进程中文件的可读性的过程,这个线程/进程将被同步并与所有其他应用程序实例通信,
例如:
每个实例在访问文件之前都需要执行两个检查级别: