首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java -并发处理大型文件

Java -并发处理大型文件
EN

Software Engineering用户
提问于 2016-11-28 13:49:56
回答 2查看 32.4K关注 0票数 10

所以在高层次上我的用例如下-

我定期(每24小时)得到一个非常大的文件(大小可以从MBs到10秒的GBs),我需要在24小时内处理。处理过程包括读取记录、应用一些业务逻辑和用记录更新数据库。

当前的解决方案是一个单线程版本,

  1. 最初在内存中读取整个文件,也就是说,它读取每一行并构造一个POJO。所以从本质上说,它创造了一个大列表
  2. 然后对列表进行迭代,并在每个Pojo上应用业务逻辑,并将它们保存在数据库中。

这适用于记录少于1000万条的小文件。但是随着系统的扩展,我们得到了更多的负载,即更大的文件(偶尔有超过1亿条记录)。在这个场景中,我们看到超时,也就是说,我们无法在24小时内处理整个文件。

所以我打算在这里加入一些并发性。

一个简单的解决办法是-

  1. 在内存中读取整个文件(为每个记录创建POJO,就像我们目前正在做的那样),或者逐个读取每条记录并创建POJO
  2. 生成线程来并发处理这些POJO。

这个解决方案看起来很简单,我看到的唯一缺点是文件解析可能需要时间,因为它是单线程的(内存不是问题,我使用了一个相当大的EC2实例)。

另一个解决办法是-

  1. 以某种方式将文件分解为多个子文件。
  2. 并行处理每个文件

这似乎有点复杂,因为我必须将文件分解成多个较小的文件。

欢迎在此就这些办法提出任何建议。

EN

回答 2

Software Engineering用户

回答已采纳

发布于 2016-11-28 14:39:12

最有可能做到这一点的有效方法是:

  • 有一个读取输入文件的线程。硬盘在按顺序读取时处于最快状态。
  • 不要一下子把它读入记忆!这是一个巨大的内存浪费,可以更好地使用,以加快处理!
  • 相反,让这个单个线程立即读取一捆条目(可能是100条,也许是1000条,这是一个调优参数),并将它们提交给一个线程来处理。如果每一行代表一条记录,则读取线程可以将所有解析(查找换行符除外)推迟到处理线程。但是,即使不是,解析记录也不太可能成为您的瓶颈。
  • 通过固定大小线程池执行线程处理,选择大小作为机器上CPU核心的数目,或者更多。
  • 如果您的数据库是SQL数据库,请确保单个线程通过连接池访问数据库,并对单个事务中的一个绑定项执行所有DB更新,并使用批处理插入。

您可能希望为此使用弹簧批,因为它将指导您做正确的事情。但它在某种程度上被过度设计,难以使用。

请记住,如果DB成为您的瓶颈(这很容易成为瓶颈),那么所有这些都可能是徒劳的-- SQL数据库在处理并发更新方面是出了名的糟糕,它可能需要相当大的代价才能避免锁争用和死锁。

票数 18
EN

Software Engineering用户

发布于 2016-11-28 14:12:36

让我们从一些基本的算术开始。

代码语言:javascript
复制
(* 24 60 60)
86400

这意味着一天中有86400秒。

代码语言:javascript
复制
(/ 100e6 86400)
1157.4074074074074

这意味着,要在一天内处理1亿条记录,您必须能够每秒处理1157.4条记录。

再向前走一步:

代码语言:javascript
复制
(/ 1.0 1157.4074074074074)
0.000864

这意味着你必须能够处理一个记录,端到端,在864微秒内。

不管你做什么,这都是事实。如果处理一个记录需要超过864微秒,你将无法在24小时内处理1亿条记录。

添加“线程”将使其更糟,而不是更好,因为您增加了开销,并且不删除任何底层工作负载。

我怀疑,在这个疯狂的喧嚣中度过了近40年之后,将文件读入内存并将结果写入DBMS是在活生生地吞噬着您。

票数 7
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/337018

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档