web-dev-qa-db-ja.com

ファイルシステムのデータからリアルタイムで更新するためのアーキテクチャ

レガシーアプリケーションを改造して、スケーラブルでパフォーマンスの高いものにしようとしています。現在のアーキテクチャはこのようなものです

1日50万回以上呼び出される短期間有効なスクリプトを考えてみましょう。各呼び出しは一意の呼び出し(キーで識別)であり、いくつかの構造化ファイルを独自の一意の日付付きディレクトリに書き込みます。スクリプトの再実行も行われる可能性があります(再実行により、同じパーティション内のファイルが更新されます)。

これで、UIでこのスクリプトの実行からの情報(ファイルシステムで実行されるスクリプトによって保持されるデータ)の情報を表示するWebアプリケーションができました。

このWebアプリケーションのバックエンドはJavaベースです。 7日間のメモリ内キャッシュ(ハッシュマップ)があり、専用スレッドが30秒ごとに起動し、ファイルシステムから最新の情報を読み取ることでキャッシュ内のデータを更新します。 7日間のデータを使用するインメモリキャッシュには、約40 GBのRAMスペース)が必要です。

フロントエンドは反応ベースです。 Javaバックエンドから30秒ごとにAPI呼び出しを実行してデータをクエリすることにより、ブラウザーのデータを更新します。

お気づきのとおり、このアーキテクチャには3つの主要な問題があります。

  1. UIに新しいデータを表示するときに、30秒(バックエンドの更新)+ 30秒(フロントエンドの更新)の遅延が生じる可能性があります。これは、データをポーリングし、更新時にデータをプッシュしているためです。
  2. インメモリキャッシュがあるため、サーバーインスタンスを複製してこのアプリケーションを水平方向にスケーリングすることはできません。サーバーの異なるインスタンス全体で複数のキャッシュを持つことになり、それぞれに独自の更新サイクルがあります。
  3. Javaサーバーのインメモリキャッシュでデータを利用できないため、7日前のクエリは遅すぎます。ファイルシステムからオンザフライで読み取る必要があります。

このアーキテクチャを改善するにはどうすればよいですか?

1つの可能なアーキテクチャ:

Kafka Queueが、ファイルシステムへの書き込みとともにスクリプトがイベントを発行できるキューを導入することを考えていました。JavaサーバーはこれらをサブスクライブできますKafkaイベント。Kafkaからイベントを受信すると、Javaサーバーは

  1. Redisキャッシュへのデータの更新
  2. データベースに永続化し、
  3. WebSocketを介してUIに更新をプッシュする

これはいい音ですか、それとも欠陥がありますか?

3
Lokesh Agrawal

潜在的な解決策は、生のファイルシステムの代わりにデータベースを使用することです。予想されるクエリパターンに基づいて構築されたインデックスを使用すると、生ファイルを処理するよりも信頼性の高いパフォーマンスが得られます。

これをゆっくりとリファクタリングしているので、ストレージメカニズムを複製して、時間の経過とともに拡張する必要がある場合があります。つまり、既存のファイルシステムとDBの両方にデータを書き込みます。次に、理想的には、クエリを1つのデータソースから別のデータソースにゆっくりと移動できます。ここでの欠点/課題は、2つのデータストアが互いに同期していることです。

キャッシュレイヤーの水平方向のスケーラビリティを取得するメカニズムとして、メモリ内キャッシュレイヤーの Redis のようなものを検討することもできます。これは、複数のマシンを使用して7日以上のデータをキャッシュするのに役立つ場合があります。

もう1つの提案は、キャッシュを介して書き込むことです。そのため、データはすぐにキャッシュレイヤーにキャッシュされ、更新機能が有効になるのを待つ必要はありません。 Apache Ignite のような一部のデータファブリックサポート ライトスルーキャッシュ

2
Oleksi

質問の最後のアーキテクチャアプローチについて:

まず、約500.000回の呼び出し、つまり平均0.1728秒ごとに1回の呼び出しについて話します。

私が理解している限り、Kafkaはライブストリーミングデータの配信に優れています。配信の保証が必要な場合は、ActiveMqのような「クラシック」メッセージブローカーを使用する方が良いと思います。スループットが確実にそこにあり、リスナー/ Javaバックエンドが何らかの理由でダウンしている場合、ディスク上にメッセージを保持できます。(これもmight実際のライブでは決して使用しないkafka-確認してください。)

Redisキャッシュを使用するのはいい考えですが、Javaバックエンドの再起動のシナリオをカバーするために、ディスクにキャッシュを永続化する必要があります。redis(ディスクストレージを使用する場合)の理由が正直にわかりませんあなたにとっては大丈夫ですが、データベースはそうではありません。

WebSocketを介してクライアントにプッシュすることは問題ありません(またはSSEを代わりに使用してください)が、0.1728秒ごとにnotです!メッセージを集約する必要があります。メッセージサイズ-クライアントの更新により長い間隔を使用します。これが1秒、10秒、1分、1時間のいずれになるかは、具体的なデータ、そのサイズ、およびその用途によって異なります。

2
mtj