2011-05-25 42 views
1

这是情况。如何在有多个线程时减少文件写入次数?

在我被分配到mantain的Java Web App中,我被要求改进QA期间压力测试的一般响应时间。这个网络应用程序不使用数据库,因为它应该是轻而易举的。 (并且我不能改变这个决定)

要持久化配置,我发现每次你对它做出改变时,一个包含config对象列表的通用对象被序列化为一个文件。

使用Jmeter我发现在给定的测试用例中,有2个请求占用大部分时间。这两个请求都添加或更改了一些配置对象。由于必须对文件进行访问,因此许多用户在更改配置时,文件必须在几秒钟内完成多次写入,并且请求正在等待写入文件的发生。

我认为所有这些序列化根本就没有必要,因为我们一次又一次地重写大部分对象,每个请求中的更改都是针对一个对象,但是整个文件都是作为一个整体写入的时间。

那么,有没有办法减少真正的文件写入的数量,但仍然保证所有的更改最终序列化?

任何建议表示赞赏

+0

为什么您将配置存储为序列化对象? – Kaj 2011-05-25 17:02:14

+0

这不是我的选择,设计者认为它会很好很简单,不幸的是,他没有看到结果,我负责“为QA球员做足够快”......任何方式我都可以'在不久的将来会改变这种情况,因为设计已经被批准并且功能测试已经结束。改变其根源以使用[db4o](http://db4o.com/)或JavaDB将使我们回到根据政治的发展阶段......并且至少延迟3周。我讨厌现在为这样一个糟糕的设计负责。 – rsinuhe 2011-05-25 18:01:26

回答

2

一种选择是做改变内存中,并保持在后台一个线程,在给定的时间间隔运行,并刷新更改磁盘。请记住,在发生崩溃的情况下,您将丢失未刷新的数据。

可以使用ScheduledExecutorService来安排后台线程。

IMO,最好使用DB。你不能使用像Java DBH2HSQLDB的嵌入式数据库吗?这些数据库支持并发访问,并且还可以保证数据在崩溃时的一致性。

+0

谢谢!如预期的那样,将写入更改为每隔几秒而不是多次写入一秒钟就已经对这些请求的响应时间产生了奇迹,他们不再等待序列化完成。 – rsinuhe 2011-05-25 21:58:22

+0

很高兴知道。我希望你能够尽快地改变这种设计,这对于像这样的系统来说是非常糟糕的。 – iruediger 2011-05-26 00:10:12

0

如果您绝对不能使用数据库,显而易见的解决方案是将您的单个文件分解为多个文件,每个配置对象一个文件。它可以加速序列化和输出过程,并减少锁争用(更改不同配置对象的请求可能会同时写入其文件,尽管它可能会成为IO限制)。

+0

我试图在各种文件中分割写入,并且它减少了响应时间,不幸的是,正如您指出的那样,在峰值负载期间,它也变成了io绑定并且响应延迟很多。 (但不像它是单个文件那么多)。 – rsinuhe 2011-05-25 21:57:48

0

一种方法是做Lucene所做的事情,根本不覆盖旧文件,而是写一个只包含“更新”的新文件。这依赖于你的更新是关联的,但无论如何通常都是这样。

这个想法是,如果你的旧文件包含“8”,并且你有3个更新,你为新文件写入“3”,新状态为“11”,接下来你写下“-2”有“9”。您可以定期汇总旧版和更新。您所写的任何物理文件都不会更新,但一旦不再使用,可能会被删除。

为了让这个想法更具针对性,考虑一下上面的数字是否是某种记录。 “3”可以翻译为“添加三条新记录”和“-2”到“删除这两条记录”。

Lucene是一个项目的例子,它非常成功地使用了这种添加剂更新策略。