通过多个实例从一个文件夹中读取文件

时间:2016-07-12 16:10:03

标签: java apache-camel spring-integration

我有一个文件夹,上游系统会转储为我的应用程序输入的文件。我的应用程序读取这些文件,处理它们然后在某个目录中输出。由于输入文件的数量很大,我决定运行我的应用程序的多个实例,所有实例都将读取输入文件的相同输入目录。现在,由于多个实例将读取同一文件夹,如何防止多个实例同时读取同一文件?

PS:我想过使用Spring集成NIO锁,但是一旦锁定文件,即使同一个线程也无法读取文件。 Camel处理锁定但它锁定了整个目录,并且在2个实例试图获取尚未锁定的文件的那段时间内也没有处理场景。

任何建议都会有所帮助。

3 个答案:

答案 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进行配置,例如ConcurrentMetadataStoreRedisMetadataStore

只有一个应用程序实例会接受一个文件。

尽管存在一些限制,但所有文件只能由一个实例应用:

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); } } } 的单例问题,例如MessageChannelSubscribableJmsChannel或任何其他基于PublishSubscribeAmqpChannel的队列渠道解决方案。

答案 1 :(得分:1)

我不会这样做,因为阅读包含多个实例的文件夹只会使你的流程变得复杂。

我会改为使用单一路径读取文件并将内容放在队列中(可以是jms,amqp等)以及文件名作为标题。然后,您可以在该队列上进行并行处理,并并行写入目标文件夹。这将使您的解决方案更易于处理和扩展,以防您需要阅读其他文件夹。

答案 2 :(得分:0)

您可以为应用程序实例已读取的每个文件创建一个影子文件

为了避免对同一文件进行concancent访问的问题,您需要集中检查一个Thread或一个进程中文件的可读性的过程,这个线程/进程将被同步并与所有其他应用程序实例通信,

例如:

  • 如果在=&gt;之前已经读取过,则Instance1需要检查file1它将检查此文件是否具有影子文件,如果为true将与集中式线程/进程通信以查看是否有任何其他实例已在处理此文件
  • 集中式线程将允许实例处理file1并将其引用存储在池列表中,该列表将用于阻止任何其他实例处理此文件
  • Instance1已经完成处理文件,一旦完成它将创建影子文件,它将与集中线程通信以从池列表中删除此文件的引用

每个实例在访问文件之前都需要执行两个检查级别:

  • 检查文件是否具有相同名称的影子文件(这意味着之前已经读过)
  • 如果第一个条件为真,请使用集中式流程检查该文件当前是否正由其他任何实例处理。