将数据保存在内存中,设计方法

时间:2011-08-24 22:41:50

标签: java algorithm design-patterns caching batch-file

我有一个问题,我需要处理一些大小在几kbs到最大1 GB范围内的文件。用例是这样的输入是一些平面文件格式,其中数据存储在一行中,比如一些支付指令。应用程序必须根据某些分组逻辑检查每个付款指令和表单组。最后,这些组必须转换为另一种格式(ISO 20022 xml),使用该格式进行支付处理。

目前的设计是这样的,我们有两个表,其中分组标准数据存储在一个表中,而单个支付指令存储在另一个表中(从组表到付款指令表的一对多关系)。在第1步中:当我们浏览平面文件时,我们识别它所属的组,并写入数据库(批量提交btw)。

在第2步:批处理中,逐个读取组并形成输出xml并发送到目的地。

我现在面临的问题是,如果整个事情可以在内存中完成,那么写入两个表并从中获取是一种矫枉过正的行为。

我正在考虑一种方法,我可以保持HashTable(google guava(MapMaker))缓存类型,以及我可以指定的大小,一旦缓存达到上限I可以将它们写入数据库表(在put缓存中编织一个方面)。

以同样的方式检索条目时,我可以先在缓存中检查密钥,如果不存在,则查询数据库。

您对此设计方法有何看法(是否是另一个错误或者我可以实现并且同时稳定且可以扩展的事情。)

为什么我想到这一点,我们总是没有大文件,只有当我们无法在内存中处理整个文件并且可能导致OutOfMemory问题时,我们才需要这些临时表。

你能提出一些建议吗?

由于

4 个答案:

答案 0 :(得分:2)

我看不出您的缓存需求如此奇特,以至于您无法使用现成的组件。 您可以尝试使用Hibernate访问您的数据库。它支持缓存。

答案 1 :(得分:1)

我认为你的设计听起来很合理。但是,有一些事情需要牢记。首先,您确定增加额外的复杂性是否合理?也就是说,写入一堆文件然后在一个重要的瓶颈中读回来的性能是否受到影响?如果浪费的时间不重要,我会强烈提醒您不要做出这种改变。你只是在增加系统的复杂性而没有太大的好处。我假设你已经考虑过这个问题了,但万一你还没想到我会在这里发帖。

其次,您是否考虑通过MappedByteBuffer使用内存映射文件?如果您正在处理超出Java堆空间且愿意付出一些努力的大型对象,您可能需要考虑设计对象以便将它们存储在内存映射文件中。您可以通过创建一个包装器类来实现这一点,该类本质上是一个瘦包装器,它将请求转换为映射字节缓冲区中的操作。例如,如果要存储请求列表,可以通过创建使用MappedByteBuffer存储磁盘上字符串列表的对象来实现。例如,字符串可以由换行符或空终止符分开存储。然后,您可以遍历字符串,遍历文件的字节并重新水合它们。这种方法的优点在于它将缓存复杂性卸载到操作系统,操作系统经过数十年的性能调整(假设您正在使用主要操作系统!)来有效地处理这种情况。我曾经在一个Java项目上工作,在那里我构建了一个框架来实现自动化,在许多情况下它运行得非常好。这肯定是一个学习曲线,但一旦它工作,你可以在Java堆空间中保留比以前更多的数据。这基本上与你上面提出的相同,只是它交换了一些前期实现复杂性,让操作系统处理所有缓存。

第三,有没有办法结合传球(1)和(2)?也就是说,您是否可以在生成数据库的同时生成XML文件?我从您的描述中假设问题是,在所有条目都准备好之前,您无法生成XML。但是,您可能需要考虑在磁盘上创建几个不同的文件,每个文件以序列化XML格式存储一种类型的对象,并且在传递结束时可以使用标准命令行实用程序(如cat)来加入它们全部一起。由于这可以通过执行批量字节连接而不必解析数据库内容来实现,因此这可能比您提出的方法快得多(并且更容易实现)。如果文件在操作系统缓存中仍然很热(他们可能就是这样,因为你刚刚写过它们),这实际上可能比你当前的方法更快。

第四,如果您关注性能,您是否考虑过并行化代码?鉴于要处理的文件非常庞大,您可以考虑将该文件拆分为许多较小的区域。然后,每个任务都将从文件中读取并将这些部分分发到正确的输出文件中。然后,您可以有一个最终过程将相同的文件合并在一起,并生成整个XML报告。因为我认为这是一个主要是I / O绑定的操作(它主要只是文件读取),所以这可以比单线程方法提供更大的性能获胜,它试图将所有内容保存在内存中。

希望这有帮助!

答案 2 :(得分:1)

您是否看过Spring Batch,它支持处理平面文件,按字段值和并行处理结果拆分它们。使用Spring jdbc,您仍然可以将分组条件存储在数据库中,但只需处理该文件而无需使用中间表。

答案 3 :(得分:1)

不,这可能不值得做缓存和退回(临时?)表,这主要是因为它会变得复杂,增加风险和成本。

但是,有可能加快初始排序到组中,并且没有任何内容表明您需要使用RDMS。

我建议您跳过自制缓存,并使用持久集合,即由本地磁盘上的文件支持的集合。这种方法很可能加速 小文件和大文件(与使用关系数据库相比。)

但是,你应该进行性能测试......我不确定一个不太合适的java b-tree可以击败正确配置的数据库服务器。但是,如果典型的管理不善的数据库运行在一个糟糕的系统上,在慢速网络的另一端,则绝对有机会。

Google for persistent collections或nosql for java;以下是我所知道的一些内容:

http://jdbm.sourceforge.net/可用作“持久/可扩展”地图。 也许http://code.google.com/p/pcollections/(但我自己没试过)

你应该能够找到更多;尝试并测试: - )

相关问题