アプリケーションのパフォーマンスの制限を克服する一般的な方法は、計算を並列化することです。該当するアプリケーションが処理するイベントやデータを受信する場合、これはコンシューマスケーリングと呼ばれます。コンシューマースケーリングとは、コンシューマーアプリケーションインスタンスの複数の並列インスタンスを実行して、着信メッセージまたはイベントストリームの同時処理を可能にすることを指します。
コンシューマースケーリングを実現するにはいくつかの異なる方法があります。最も注目すべきものは、競合するコンシューマーのエンタープライズ統合パターン、つまり複数のコンシューマーがメッセージを同時に処理できる通信パターンです。これにより、コンシューマープロセスの拡張が可能になり、並列化によってシステム全体のパフォーマンスが向上します。
Solace PubSub+ では、複数の方法でコンシューマースケーリングを実現できます。適切なアプローチの選択方法はアプリケーションの要件によって異なります。大きく分けると、ラウンドロビン配信とスティッキーロードバランシングの 2 つのカテゴリに分類されます。この記事では、利用可能なさまざまな選択肢について説明します。
ラウンドロビン配信
競合するコンシューマーパターンをスケーリング用に実装する最初の、最も簡単な方法が、ラウンドロビン方式で、すべてのコンシューマー間で着信メッセージを負荷分散することです。これにより、すべてのコンシューマーに負荷が均一に分散されます。このパターンは、メッセージの順序を維持する必要がない場合に好都合です。各メッセージは、他のすべてのメッセージから独立して処理される必要があります。また、何らかの依存関係がある場合、コンシューマーはこの依存関係を調整する何らかの共有状態を持ちます(例: 共有バックエンドデータベース、メモリ内データグリッド)。
ラウンドロビン配信の主な利点の 1 つは、動的かつほぼ無限に拡張可能であり、数百または数千のコンシューマーが参加してイベントやメッセージを全員に拡散できることです。また、処理負荷の指示に合わせてコンシューマーを追加または削除できます。
共有サブスクリプション — 非永続 QoS ラウンドロビン
非永続的(またはダイレクトメッセージング)のサービス品質の場合、Solace は共有サブスクリプションと呼ばれる機能をサポートしています。この機能を使用すると、複数のコンシューマーが動的にグループに参加したり、参加解除したりできます。このパターン/機能は、通常、非永続的なダイレクト QoS を使用するため、サービス要求を処理して応答する(要求/応答)バックエンドコンポーネントで特に役立ちます。
共有サブスクリプション機能を使用するため、コンシューマーは特別なトピックを使用して、参加するグループと、目的のトピック: #share/<ConsumerGroupName>/topicFilter>/
を示すよう登録します。例: #share/backend/estore/order/new
は、コンシューマーをグループ「backend」に追加し、estore/order/new
に登録します。パブリッシャーがトピック estore/order/new
で公開するたびに、Solace PubSub+ は、そのメッセージのコピーを「backend」共有グループ内の 1 人のコンシューマーに配信します。
この機能は、メッセージ配信にパブリッシュ/サブスクライブ(pub/sub)のパターンを使用するため、別の共有グループ名でサブスクライブすることで、メッセージのコピーを同時に受信するよう 2 番目のコンシューマグループを設定することもできます。
上の図に示すように、これは、パブリッシャーや元のコンシューマーのコードを変更しなくても、estore/order/new
の各メッセージのコピーが、「analytics」グループの 1 人のコンシューマーにも送信されます。これが、パブリッシュ/サブスクライブパターンの力です。
共有サブスクリプションの概念は、Solace のみの機能ではありません。これは MQTT 3.1.1 仕様の一部ではありませんが、共有サブスクリプションは、IoT アプリケーション用の軽量なパブリッシュ/サブスクライブプロトコル MQTT でよく使用されます。Solace はネイティブで MQTT をサポートしているため、同等のサブスクリプションパターンは $share/<ShareGroupName>/<topicFilter>
となります。
共有サブスクリプションを使用するようにアプリケーションを設定する方法の詳細については、Solace PubSub+ ドキュメントの「共有サブスクリプション」を参照してください。
非排他的キュー — 永続的な QoS ラウンドロビン
永続的(または保証付きメッセージング)サービス品質のために、Solace は「非排他的キュー」と呼ばれる機能を利用します。キューは、データを格納するための永続的なエンドポイントです。キューに送られるすべてのメッセージは、障害の状況(例: ネットワークの停止、停電、高可用性フェールオーバーなど)に関係なく、ディスクに永続化され、コンシューマーに確実に配信されます。また、非排他的キューでは、複数のコンシューマーがキューにバインドし、ラウンドロビン方式でメッセージを受信できます。
非排他的キューを使用すると、コンシューマーは(最大 10,000 コンシューマーに)動的に参加/参加解除でき、再調整などで他のコンシューマーに影響を与えることなく、処理をスケールアップおよびスケールダウンできます。
Solace PubSub+ で永続的なラウンドロビン配信を使用するには、グループごとに 1 つの非排他的キューを設定し、それぞれを必要なトピック(1 つまたは複数)に登録します。上記の例では、2 つのキューが設定され、それぞれが estore/order/new
に登録されます。パブリッシャーがキューのサブスクリプションに一致するメッセージを送信するたびに、コピーがそのキューに配置され、各グループ内で 1 つのコンシューマーのみに配信されます。(注: Solace の永続ストアは参照ベースであるため、メッセージの 1 つのコピーのみがディスクに保持されます。)これはキューで設定されているため、コンシューマーはメッセージを受信するためにキューにバインドするだけで、トピックに直接登録する必要はありません。
永続コンシューマーがキューからバインド解除する場合、その永続的なフローをまず stop()
して新しいメッセージの受信を停止し、受信したすべての未処理/送信中のメッセージをすべて確認する必要があります。これにより、コンシューマがバインド解除された場合、他のコンシューマーに再配信されたメッセージが届かなくなります。
永続的コンシューマーおよび保証付きメッセージの受信の詳細については、Solace PubSub+ ドキュメントの「保証付きメッセージングの基本操作」および「保証付きメッセージの受信」を参照してください。
スティッキーロードバランシング、またはキー付け/ハッシュ配信
特定の属性(例: 顧客 ID、注文 ID、製品 ID など)を含む公開されたイベントやメッセージデータを、常に最初に生成された順序で処理しなければならないことがあります。この要件は、すべての関連メッセージが同じコンシューマーに配信されることを意味します。つまり、メッセージにはキーが含まれているため、同じキーを持つ後続のメッセージは常に同じコンシューマーに配信され、順番に処理されます。これにより、特定の属性に関する変更または更新は、常に順番に処理されます。
「コンシューマーグループ」という用語は、ログ配布アプリケーションである Apache Kafka によって普及しました。Kafka では、コンシューマーグループは、1 つのトピックから読み取るための「論理的なコンシューマー」を形成するコンシューマーのグループです。Kafka コンシューマーグループのコンシューマーは、Kafka のトピック内の 1 つ以上のパーティションに接続し、パーティションファイルから一連のログレコードを読み取ります。Kafka トピック内のパーティションにレコード(「メッセージ」)が追加されると、パブリッシャーによって定義されたキー属性によってパーティションが選択されます。
これにより、同じキーを持つレコードが同じパーティションに格納され、同じコンシューマーによって処理される「スティッキーロードバランシング」形式が提供されます。
階層型トピック構造と Solace の高度なトピックフィルター機能を使用して、Solace PubSub+ で同じ(そしてそれ以上の)機能を実現できます。
Solace トピックをパーティショニングに使用する
トピック階層または分類を定義するときは、トピック階層の 1 つのレベルをパーティションキーとして指定します。たとえば、受注入力システムの場合、トピック構造は次のようになります:
estore/order/[ORDER_ID_PARTITION_KEY]/more/specific/rest/of/topic
キーは通常、前述のように、公開されたデータの重要な属性のハッシュです。この例では、キー付けされた属性は、大きな整数である注文 ID です。わかりやすくするために、パーティションキーが <Order ID modulo 8>: 0…7 の間の整数の場合、8 つの利用可能なパーティションに、8 つの値を使用できるとしましょう。Solace PubSub+ では、トピックとサブスクリプションが「安価」なので、必要なだけパーティションを作成します。
次に、「コンシューマーグループ」内の予想される将来のコンシューマーの数と同じ数のキューを設定します。コンシューマーとまったく同じ数のキューを設定することもできますが、Solace PubSub+ のキューも「安価」であるため、最初に必要な数より多くキューを設定すると、将来高い柔軟性を容易に実現できます。
図の例に示すように:
-
- 4 つのキューが設定されており、それぞれが 2 つのパーティションに登録されます。
(サブスクリプションの最後の、パーティションキーレベルの後にマルチレベルのワイルドカード「>」を使用することに注意してください) - コンシューマーは 2 人のみで、それぞれが 2 つのキューからデータを受信します。したがって、各コンシューマーは 4 パーティション分のデータを受信します。
- 4 つのキューが設定されており、それぞれが 2 つのパーティションに登録されます。
この eStore の例では、カスタマーゲートウェイ/API がさまざまなタイプの注文イベント(例: 新規、修正、キャンセル)を許可するように拡張された場合、同じ注文 ID に関連するイベントは同じバックエンドプロセッサーに移動することが望ましいでしょう。これにより、「新規」注文が 1 つのプロセッサーによって受信されず、「キャンセル」が別のプロセッサーに転送されるようになります。パブリッシャーによって注文タイプイベントが生成されるたびに、トピックの(この場合は)3 番目のレベルを使用し、注文 ID のモジュロである 8 を取得して、メッセージを特定のパーティションにキー付けします。
このアプローチを使用すると、基本的にアーキテクチャパターンには変更を加えず、トピックを使用してパーティションを定義して、多数のパーティションを作成することが可能です。これにより、新しい数のキュー間でキーサブスクリプションを再度分散させることで、コンシューマーグループにコンシューマーを追加できるようになり、将来の柔軟性が得られます。
Solace PubSub+ のスティッキーロードバランシングパターンの詳細については、Mat Hobbis による Solace PubSub+ Event Broker の「スティッキーロードバランシング」をご確認ください。
付録
付録 A: パーティションの将来の柔軟性
Kafka パーティションはログファイルとして実装されているため、維持するにはオープンファイルハンドルが必要です。これにより、作成できるパーティションの数に現実的な制限が課されます。
Solace パーティショニングはトピックとトピックサブスクリプションを使用して行われ、トピックサブスクリプションは一般的に Solace ブローカーの制約付きリソースではないため、モジュロが非常に大きいハッシュ/キー関数を選択します。この軽量パーティショニングを使用することで、コンシューマーは卓越したスケーラビリティを実現できます。
たとえば、360 のモジュロとしてキー関数を選択すると、サイズ 2、3、4、5、6、8、9、12、15、20、24、… などのバランスのとれたコンシューマーグループを作成できます。これらすべてのトピックサブスクリプションは、最初に少ない数のキューにマッピングできます。
付録 B: マルチキーハッシュ
Solace は階層トピック構造をサポートしているため、1 つのトピックを複数のキーでエンコードできます。たとえば、「注文 ID」と「顧客 ID」の両方が、トピック階層の異なるレベルになる可能性があります。これにより、異なるコンシューマーグループが、順番どおりに受け取るようキー設定する属性を決定できます。
Kafka ではこの場合、異なる Kafka のトピックへ 2 回公開し、それぞれに異なるパーティションキーを使用する必要があります。
付録 C: パーティションのオーバードライブと優先度の低い拒否
適切と思われる、Solace PubSub+ の高度な機能の 1 つは、優先度の低い拒否の永続キュー機能です。これにより、管理者は、優先度の低いメッセージの拒否を開始する前に、キューの深度の制限を構成できます。これにより、オーバードライブになっているパーティションは新しいメッセージを抑制できます。
先程の例では、「新規」メッセージの優先度は低く、「修正」と「キャンセル」のメッセージの優先度は高くなります。このため、後者は常に正しいキューに入ります。ただし、キューがいっぱいだと「新規」メッセージは拒否され、パブリッシャーはハッシュキーを再計算し、別のパーティションに再送信します。
優先度の低い拒否の設定の詳細については、Solace PubSub+ ドキュメントの「優先度の低いメッセージの拒否の有効化」を参照してください。