だから、これは私のシナリオです。
何百万ものイベントが発生しているので、そのデータをDBに直接スローしたくありません。「バッチ」操作が必要です。この操作では、Javaコードが、しきい値に達するまで(たとえば、10秒ごとに)着信するイベントを保持し、プライマリデータベースへのバッチ挿入を実行します。
マシンがクラッシュした場合にデータを失いたくないので、フォールトトレランスも必要です。これらのイベント(約10k)を10秒間保持するためにhsqldbを検討しています。
助言がありますか?
だから、これは私のシナリオです。
何百万ものイベントが発生しているので、そのデータをDBに直接スローしたくありません。「バッチ」操作が必要です。この操作では、Javaコードが、しきい値に達するまで(たとえば、10秒ごとに)着信するイベントを保持し、プライマリデータベースへのバッチ挿入を実行します。
マシンがクラッシュした場合にデータを失いたくないので、フォールトトレランスも必要です。これらのイベント(約10k)を10秒間保持するためにhsqldbを検討しています。
助言がありますか?
1 秒あたり数百万の全体数と永続性が必要な場合は、試すことができます。Java Chronicle 別のプロセスでデータを消費することができるため、プログラムが停止した場合でも、データはデータベースに書き込まれます。(また、データベースの更新を実行する必要があるため、メイン プロセスが遅くなることはありません) また、TCP を介した複数のマシンへのレプリケーションもサポートします。
このテストに基づく簡単な例はこちら
// 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 を返したら、バッチのトランザクションをコミットし、少し待ってから繰り返します。
Martin Fowler は、彼の LMAX アーキテクチャの記事を投稿しました。これは、メイン メモリで数百万のトランザクションを可能にし、障害が発生した場合に復元する可能性があります。
少なくともご覧ください: http://martinfowler.com/articles/lmax.html
あなたの問題は、プロセスの負荷ではなく、DB の負荷であると推測しています。これは、なぜバッチ操作が安くなると期待するのかという疑問を私に投げかけます。あなたの質問からすると、これまでのところ、1 分あたり 10 ドルよりも 1 時間あたり 600 ドルを支払うほうがよいように思えますが、負荷は同じくらい悪くなります。
バッチ操作を安価に処理できる場合は、保存が安価な中間媒体にキャッシュし、そこからロードするだけで済みます。頭に浮かぶ2つのことは、JSONでフラットファイルに書き込むことと、ロードが別のプロセス(またはスレッドプール)で行われるMemcached(おそらくJSONも)を使用することです。2 つの間の原子性を確保する必要があります。これには、すぐに使えるソリューションが他にもあるかもしれません。
予想されるクラッシュの程度に応じて、マシンがクラッシュする前にシャットダウン フックをダンプするように設定することもできますが、これは良くても疑わしい方法です。
バッチ操作は、実際にはデータベース レベルで処理されます。データベースは複数のトランザクションを 1 回 (または数回) の書き込みでトランザクション ログにマージします。書き込みはトランザクション ログからテーブルに移動されますが、ディスク書き込みを最小限に抑えるためにグループ化されます。少なくともOracleでは。これが、非常に効率的であり、非常に高価である理由です。しかし、そうかもしれません。PostgreSQLはあなたの期待に応えてくれるでしょう。最初にテストします。
データベースの読み取りに関しては、データベースのサイトからの集中的なキャッシュもあります。ただし、SQL の解析にはコストがかかるため、クライアント キャッシュを使用することは非常に優れたオプションです。EhCacheを検討してください。2 レベルのキャッシュがサポートされています。定義済みの数のアイテムがメモリに保持され、他のセットがディスクにオーバーフローします (必要に応じてメモリ キャッシュのみを使用できます)。メモリ キャッシュからの読み取り時間は、HashMapアクセス時間とほぼ同じです。もちろん、RAM が多ければ多いほど、メモリ キャッシュはより効率的になります。
耐障害性に関して言えば、データベースはキャッシュしないことを保証します。これは書き込みのみの問題であり、読み取りではありません。たとえば、hsqldb を使用して自分で何かを実装しようとしないでください。ディスクへの書き込みは常にコストがかかります。それほど多くの人も時間もないので、Oracle よりも優れたものを書くことはできません :) トランザクション ログを使用するメカニズムは非常に効率的です。また、システムがクラッシュすると、コミットが実行されている限り、操作はそのログから復元されます。