所以,这是我的情景。
我有数百万个事件进来,我不想将这些数据直接丢给我的数据库。我想要一个“批处理”操作,其中java代码保存事件,直到达到阈值(比如说每10秒)并且它们对主数据库进行批量插入。
我还需要容错,因为如果机器崩溃,我不想丢失数据。 我正在考虑将hsqldb用于保存这些事件(将在10k左右)持续10秒。
有什么建议吗?
答案 0 :(得分:2)
如果你想要每秒数百万的entires和持久性,你可以试试。 Java Chronicle 您可以使用不同的进程来使用数据,因此如果程序死亡,数据仍将写入数据库。 (此外,您的主进程不会因为必须执行数据库更新而变慢)它还支持通过TCP复制到多台计算机。
基于此测试的简单示例HERE
// create a Chronicle for reading or writing.
String basePath = TMP + File.separator + "deleteme.ict";
IndexedChronicle tsc = new IndexedChronicle(basePath);
// create a handle to excerpts in the chronicle.
Excerpt excerpt = tsc.createExcerpt();
// add 1024 entries.
int counter = 1;
for (int i = 0; i < 1024; i++) {
excerpt.startExcerpt(129);
for (int j = 0; j < 128; j += 8)
excerpt.writeLong(counter++);
excerpt.write(-1);
excerpt.finish();
}
// somewhere else read the file
int counter2 = 1;
Excerpt excerpt2 = tsc.createExcerpt();
while (excerpt2.nextIndex()) {
for (int j = 0; j < 128; j += 8) {
long actual = excerpt2.readLong();
long expected = counter2++;
if (expected != actual)
assertEquals(expected, actual);
}
assertEquals(-1, excerpt2.readByte());
excerpt2.finish();
}
assertEquals(counter, counter2);
这允许您在可用时进行批处理,以最大程度地降低未将其添加到数据库的风险。当nextIndex()返回false时,您提交批处理的事务,稍等一会再重复。
答案 1 :(得分:0)
Martin Fowler发布了他的LMAX架构文章,该文章允许在主内存中进行数百万次交易,并且可以在发生故障时进行恢复。
答案 2 :(得分:0)
我推断你的问题是数据库负载,而不是进程负载。这就向我提出了一个问题,为什么你期望批量操作更便宜,从你的问题到目前为止,你只想每小时支付600美元,而不是每分钟10美元,但负载也同样糟糕。
如果您可以廉价地处理批处理操作,那么您只需要缓存到便宜的中间件,然后从那里加载。我想到的两件事是用JSON写入平面文件,并使用Memcached(也可能是JSON),其中加载发生在一个单独的进程(或线程池)中。您需要确保两者之间的原子性。可能会有更多开箱即用的解决方案,我将留下更多知识渊博的答案。
根据您预期崩溃的严重程度,您还可以在机器崩溃之前将关闭挂钩设置为转储,尽管这是最好的做法。
答案 3 :(得分:0)
批处理操作实际上是在数据库级别处理的。数据库将单个(或几个)写入中的多个事务合并到事务日志中,写入从事务日志移动到表,但它们被分组以最小化磁盘写入。至少使用 Oracle 。这就是为什么它如此高效,而且如此昂贵。但也可以这样, PostgreSQL 将满足您的期望。首先测试。
在数据库读取方面,还有来自数据库站点的密集缓存。但是解析SQL很昂贵,因此使用客户端缓存是非常好的选择。考虑 EhCache 。它支持2级缓存:预定义数量的项目保留在内存中,其他组溢出到磁盘(如果需要,可以只使用内存缓存)。内存缓存的读取时间与 HashMap 访问时间有关。当然,你拥有的内存越多,内存缓存的效率就越高。
在容错方面,数据库保证不缓存。这只是写入而不是读取的问题。例如,不要尝试使用hsqldb自己实现某些功能。 磁盘写入总是很昂贵。你不会写任何比Oracle好的东西,因为你没有这么多的人和时间:)他们的事务日志机制非常高效。当系统崩溃时,只要执行提交,就会从该日志恢复操作。