web-dev-qa-db-ja.com

クラスタリングと複数のコンシューマを備えたキューソリューションの設計

これは私がここにリストアップしている設計問題です。

私は、さまざまなビジネスエンティティに対して実行されるさまざまなビジネスオペレーションのセットを持っています。

操作:

  • オペレーションA
  • オペレーションB
  • オペレーションC

たとえば、私はエンティティAを持っています。エンティティAのデータは、たとえば次のように部分的に分割できます。

  • エンティティA(1月のデータ)
  • エンティティB(2月のデータ)など.

ユースケースを完了するには、すべての操作(A、B、C)を実行する必要があります。これらの操作が実行され、互いに独立しており、並行して実行できるようになりました。唯一の条件は、それらのエンティティが異なる必要があることです。したがって、エンティティAは、すべての操作(A、B、またはC)を並行して実行することはできません。そして、これらの操作はサーバー側で実行されています。

これをスケーリングしてソリューションを提供する方法は?

私は次の解決策を考えており、これについてコミュニティから意見をもらいたいと思います。

上記の操作のキューを3つ考えています

  • 操作Aを実行するキューA
  • 操作Bを実行するキューB
  • 操作Cを実行するキューC

そして、すべてのコンシューマはこれらのキューをリッスンします。

  • 消費者A(または複数の消費者)
  • 消費者B(または複数の消費者)
  • 消費者C(または複数の消費者)

そして、私のサーバーは負荷分散され、これら3つのキューを含む単一のメッセージキューができます。

したがって、2つのサーバーが実行されており、各サーバーでたとえば5つのスレッド(コンシューマー)が実行されている可能性があるため、メッセージキューAからデータを選択して実行されているコンシューマーAのインスタンスが10個あります。

前に述べたように、同じエンティティA(つまり、私が持っているビジネスユースケース)では、これらのすべての操作(操作A、操作B、および操作C)を並行して実行することはできません。 。

したがって、私が考えているのは、エンティティAのデータベースエントリを作成することであり、すべてのコンシューマはエンティティAのデータベースエントリがあるかどうかを確認する必要があります。

  • そうでなければ

    1. エンティティAのデータベースにエントリを作成する
    2. 操作を実行します
    3. エンティティAのデータベースからエントリを削除します
  • データベースにエントリが見つかった場合

    1. エンティティAのデータを、選択されたキューから再度エンキューします。

このような設計上の問題に対して、より良い解決策はありますか?

3
Abhishek

一貫したハッシュを使用してデータを簡単に分割できます。この場合、エンティティをハッシュキーとして使用します。整合性のあるハッシュは、キーと「バケット」の数を入力として受け取り、そのキーのバケットを返します。

複数のサーバーを想定している場合、簡単な解決策は、事前にいくつかのパーティション(6とする)を選択することです。これは、6つのキューがあることを意味します。メッセージを生成するときに、バケット[consistentHash(entity.id、6)]を計算し、そのバケットに対応するキュー(パーティション)にメッセージを書き込みます。これにより、エンティティごとにメッセージの順序を指定できます。

コンシューマー側では、キュー(パーティション)ごとにコンシューマーが1つだけであることを確認してください。競合する消費者がいない限り、サーバーはいくつでも持つことができます。

その後、各サーバーの内部でさらに1つのステップを実行して、並列処理を改善できます。各キュー(パーティション)のコンシューマーはルーターであり、これは単に各メッセージを取得し、エンティティに対して別の一貫したハッシュを実行します。NはNバケットです。Nは並列処理に必要なワーカースレッドの数であり、メッセージを計算されたバケットのスレッド。

この設定により、同じエンティティのメッセージが常に同じサーバーにルーティングされ、サーバーはメッセージを常に同じワーカースレッドにルーティングします。 Nワーカースレッドが比較的高いと仮定すると、必要なキーに基づいたメッセージの順序付けにより、タスクの並列化が優れています。

2
Alex

これは ルーティングスリップパターン の古典的なケースのように聞こえます。

このアプローチは、あなたが説明したとおりです-コンシューマ/メッセージプロセッサごとに個別のキュー。特定のメッセージ(Entity)を同時に処理できるのは1つのコンシューマーだけですが、コンシューマーはキュー内のメッセージを自由に処理できます。

このアプローチの主な利点は、コードを作成するときにメッセージの経路を知る必要がないことです。メッセージタイプに基づいてランタイムルーティングを定義できます。個々の消費者の負担;またはあなたの要件に意味のあるものは何でも。


このアプローチの最大の利点は次のとおりです。

  • 各消費者は他の消費者からの独立性を維持しています。実行時間の長いコンシューマープロセスは、リソースを追加することで個別に補完できます。または、コンシューマーがサポートしている場合、現在のワークロードに基づいて、追加のリソースを動的に追加またはシフトできます。

  • データベースエントリとロックの必要性を回避します。一般的に言って、DBはこのような大規模なイベントメッセージングを適切に処理しません。あなたはそれを機能させることができますが、解決策はもろくなりがちで、要件が変わると壊れる傾向があります。

2
user53019

操作間の同期にDB操作は必要ありません。

データに対して3つの操作すべてを順次実行する必要がある場合:

操作Aを実行するコンシューマーがいるキューAにデータを送信し、最後にキューBに送信します。キューBのコンシューマーは操作Bを実行し、操作の実行を待機しているキューCにデータを送信しますそれにC。

データに対して3つの操作をすべて実行する必要があるが、順序は重要ではない場合:

オペレーションごとに10のコンシューマーを持つキューを1つだけ保持します(各マシンで5つ)。初めてキューに追加するときに、ヘッダーにOpA = true、opB = true、opC = trueを追加します。操作Aのコンシューマーは、WHERE opA = trueのみを選択する必要があります。これに選択的コンシューマーを使用( http://camel.Apache.org/selective-consumer.html )コンシューマーがメッセージを取得すると、それぞれの操作を実行し、それぞれのヘッダーを削除して、同じキューにデータを戻します(独自のヘッダーを削除した後でさらにヘッダーがある場合のみ)。

2
Sagar Mhatre