パーティション分割されたキューとトピック
Azure Service Bus では、メッセージを処理する複数のメッセージ ブローカーとメッセージを格納する複数のメッセージング ストアを採用しています。 従来のキューまたはトピックは、単一のメッセージ ブローカーで処理されて 1 つのメッセージング ストアに格納されます。 Service Bus "パーティション" では、キューとトピック、つまり "メッセージング エンティティ" を複数のメッセージ ブローカーとメッセージング ストアにパーティション分割することもできます。 パーティション分割は、パーティション分割されたエンティティの全体のスループットが、単一のメッセージ ブローカーまたはメッセージング ストアのパフォーマンスによって制限されなくなることを意味します。 また、1 つのメッセージング ストアが一時的に停止しても、パーティション分割されたキューまたはトピックは使用することができます。 パーティション分割されたキューとトピックには、トランザクションやセッションのサポートなど、あらゆる高度な Service Bus 機能を含めることができます。
Note
パーティション分割に関しては、Basic または Standard SKU と Premium SKU の間にいくつかの違いがあります。
- パーティション分割は、Basic または Standard SKU のすべてのキューおよびトピックに対するエンティティの作成で使用できます。 1 つの名前空間に、パーティション分割されたエンティティとパーティション分割されていないエンティティの両方を含めることができます。
- Premium メッセージング SKU 用の名前空間の作成時にパーティション分割を使用でき、その名前空間内のすべてのキューとトピックがパーティション分割されます。 以前に移行された、Premium 名前空間内のパーティション分割されたエンティティは、引き続き期待どおりに動作します。
- Basic または Standard SKU でパーティション分割が有効になっている場合、常に 16 個のパーティションが作成されます。
- Premium SKU でパーティション分割が有効になっている場合、パーティションの数は名前空間の作成時に指定されます。
既存の名前空間、キュー、またはトピックのパーティション分割オプションを変更することはできません。このオプションを設定できるのは、エンティティを作成するときだけです。
しくみ
パーティション分割されたキューまたはトピックはそれぞれ、複数のパーティションで構成されます。 パーティションはそれぞれ別々のメッセージング ストアに格納され、別々のメッセージ ブローカーで処理されます。 パーティション分割されたキューまたはトピックにメッセージが送信されると、Service Bus はそのメッセージをいずれかのパーティションに割り当てます。 対象のフラグメントは、Service Bus によってランダムに選択されるか、送信側で指定できるパーティション キーによって選択されます。
クライアントがパーティション分割されたキューからのメッセージまたはサブスクリプションからパーティション分割されたトピックへのメッセージを受信する場合、Service Bus はすべてのパーティションを照会してメッセージを探し、いずれかのメッセージング ストアから取得された最初のメッセージを受信側に返します。 Service Bus では、その他のメッセージをキャッシュし、追加の受信要求を受信したときにそれらを返します。 受信側のクライアントは、パーティション分割を認識していません。パーティション分割されたキューまたはトピックのクライアントから見た動作 (読み取り、完了、遅延、配信不能、プリフェッチなど) は、通常のエンティティの動作と同じです。
パーティション分割されていないエンティティに対するピーク操作では、常に最も古いメッセージが返されますが、パーティション分割されたエンティティでは返されません。 代わりに、メッセージ ブローカーが最初に応答したパーティションのうち、最も古いメッセージが返されます。 返されるメッセージが、すべてのパーティションで最も古いメッセージであることは保証されません。
パーティション分割されたキューまたはトピックとの間でメッセージを送受信するとき、追加コストは発生しません。
Note
ピーク操作によって、最も古いメッセージがシーケンス番号に基づいてパーティションから返されます。 パーティション分割されたエンティティの場合、シーケンス番号はパーティションを基準として発行されます。 詳細については、「メッセージのシーケンス処理とタイムスタンプ」を参照してください。
パーティション キーの使用
パーティション分割されたキューまたはトピックにメッセージがエンキューされると、Service Bus はパーティション キーが存在するかどうかを調べます。 パーティション キーが見つかった場合は、そのキーに基づいてパーティションを選択します。 パーティション キーが見つからない場合は、内部アルゴリズムに基づいてパーティションを選択します。
パーティション キーを使用する場合
セッションやトランザクションなどの一部のシナリオでは、メッセージを特定のパーティションに格納する必要があります。 このようなシナリオでは必ず、パーティション キーを使用する必要があります。 同じパーティション キーを使用するメッセージはすべて、同じパーティションに割り当てられます。 そのパーティションが一時的に使用できなくなると、Service Bus はエラーを返します。
以下に示すように、シナリオに応じて、さまざまなメッセージ プロパティがパーティション キーとして使用されます。
SessionId: メッセージにセッション ID プロパティが設定されている場合、Service Bus では、それをパーティション キーとして使用します。 このように、同じセッションに属するメッセージはすべて、同じメッセージ ブローカーによって処理されます。 セッションでは、Service Bus はメッセージの順序と、セッション状態の整合性を保証することができます。
PartitionKey: メッセージにセッション ID プロパティではなく、パーティション キー プロパティが設定されている場合、Service Bus では、そのパーティション キー プロパティ値をパーティション キーとして使用します。 メッセージにセッション ID プロパティとパーティション キー プロパティの両方が設定されている場合、この両方のプロパティは同じである必要があります。 パーティション キー プロパティがセッション ID プロパティとは異なる値に設定されている場合、Service Bus では無効な操作の例外を返します。 送信者がセッションに対応していないトランザクション メッセージを送信する場合は、パーティション キー プロパティを使用する必要があります。 パーティション キーを使用することにより、トランザクション内で送信されるすべてのメッセージを同じメッセージング ブローカーで処理することができます。
MessageId: キューまたはトピックが重複データ検出機能で作成され、セッション ID プロパティもパーティション キー プロパティも設定されていない場合は、メッセージ ID プロパティ値がパーティション キーとして機能します。 (メッセージ ID が送信側のアプリケーションで割り当てられていない場合は、Microsoft クライアント ライブラリによって自動的に割り当てられます)。この場合は、同じメッセージのすべてのコピーが同じメッセージ ブローカーによって処理されます。 この ID により、Service Bus は重複したメッセージの検出と削除ができるようになります。 重複データ検出機能が有効になっていない場合、Service Bus では、メッセージ ID プロパティをパーティション キーと見なしません。
パーティション キーを使用しない場合
パーティション キーが存在しない場合、Service Bus は、ラウンドロビン方式で、パーティション分割されたキューまたはトピックのすべてのパーティションにメッセージを配信します。 選択されたパーティションが使用できない場合、Service Bus では、そのメッセージを別のパーティションに割り当てます。 このように、メッセージング ストアが一時的に使用できなくても送信操作は成功します。 ただし、パーティション キーによって提供される保証された順序は実現されません。
可用性 (パーティション キーなし) と一貫性 (パーティション キーを使用) の間のトレードオフの詳細については、「Event Hubs における可用性と一貫性」を参照してください。 ユーザーに公開されていないパーティション ID を除き、これらの情報は、パーティション分割された Service Bus エンティティにも同様に適用されます。
Service Bus に、メッセージを別のパーティションにエンキューするための十分な時間を与えるには、そのメッセージを送信するクライアントによって指定されるタイムアウト値が 15 秒を超えている必要があります。 60 秒の既定値が推奨されます。
パーティション キーは、メッセージを特定のパーティションに "ピン留め" します。 このパーティションを保持しているメッセージング ストアを使用できない場合、Service Bus はエラーを返します。 パーティション キーが存在しない場合、Service Bus は異なるパーティションを選択できるので、操作は成功します。 そのため、必要でない限り、パーティション キーを指定しないことをお勧めします。
高度なトピック
パーティション分割されたエンティティでトランザクションを使用する
トランザクションの一部として送信されるメッセージでは、パーティション キーを指定する必要があります。 このキーには、セッション ID、パーティション キー、またはメッセージ ID のいずれのプロパティを使用できます。 同じトランザクションの一部として送信されるすべてのメッセージで、同じパーティション キーを指定する必要があります。 トランザクション内でパーティション キーなしのメッセージを送信しようとすると、Service Bus は無効操作例外を返します。 同じトランザクション内で異なるパーティション キーを持つ複数のメッセージを送信しようとすると、Service Bus は無効操作例外を返します。 次に例を示します。
CommittableTransaction committableTransaction = new CommittableTransaction();
using (TransactionScope ts = new TransactionScope(committableTransaction))
{
ServiceBusMessage msg = new ServiceBusMessage("This is a message");
msg.PartitionKey = "myPartitionKey";
await sender.SendMessageAsync(msg);
ts.Complete();
}
committableTransaction.Commit();
パーティション キーとなるプロパティが設定されている場合、Service Bus はメッセージを特定のパーティションに "ピン留め" します。 この動作は、トランザクションが使用されているかどうかにかかわらず起こります。 必要でない限り、パーティション キーを指定しないことをお勧めします。
パーティション分割されたエンティティのあるセッション内でトランザクションを使用する
トランザクション メッセージをセッションに対応したトピックまたはキューに送信するには、そのメッセージにセッション ID プロパティが設定されている必要があります。 パーティション キー プロパティも指定されている場合は、それがセッション ID プロパティと同じである必要があります。 これらが異なる場合、Service Bus は無効操作例外を返します。
通常の (パーティション分割されていない) キューまたはトピックとは異なり、1 つのトランザクションを使用して、複数のメッセージを異なるセッションに送信することはできません。 これを試みると、Service Bus は無効操作例外を返します。 次に例を示します。
CommittableTransaction committableTransaction = new CommittableTransaction();
using (TransactionScope ts = new TransactionScope(committableTransaction))
{
ServiceBusMessage msg = new ServiceBusMessage("This is a message");
msg.SessionId = "mySession";
await sender.SendMessageAsync(msg);
ts.Complete();
}
committableTransaction.Commit();
パーティション分割されたエンティティでのメッセージの自動転送
Service Bus では、パーティション分割されたエンティティを送信元または送信先とするメッセージの自動転送、およびパーティション分割されたエンティティ間でのメッセージの自動転送をサポートしています。 この機能は、キューやサブスクリプションを作成または更新するときに有効にすることができます。 詳細については、メッセージ転送の有効化に関するページを参照してください。 メッセージでパーティション キー (セッション ID、パーティション キー、またはメッセージ ID) が指定されている場合、そのパーティション キーは宛先エンティティのために使用されます。
考慮事項とガイドライン
- 高い整合性機能: パーティション キーの明示的制御、重複データ検出、セッションといった機能が使用されるエンティティの場合、メッセージング操作は常に特定のパーティションにルーティングされます。 いずれかのパーティションにトラフィックが集中した場合や、基になるストアに異常が生じた場合、それらの操作は失敗し、可用性が低下します。 それでも全体として堅牢性は、パーティション分割されていないエンティティと比べれば、はるかに高くなります。問題が発生するのはトラフィックの一部だけです。すべてのトラフィックで問題が発生するわけではありません。 詳細については、「Event Hubs における可用性と一貫性」を参照してください。
- 管理: 作成、更新、削除といった操作は、エンティティのすべてのパーティションに対して実行する必要があります。 異常のあるパーティションが 1 つでもあると、それらの操作は失敗します。 Get 操作に関して言えば、メッセージ数などの情報は、全パーティションから集計する必要があります。 いずれかのパーティションに異常があった場合、そのエンティティの可用性ステータスは "制限あり" として報告されます。
- メッセージ ボリュームの削減に伴うシナリオ: 特に HTTP プロトコルを使用している場合は、すべてのメッセージを取得するために、複数の受信操作を実行しなければならないことがあります。 受信要求の場合、フロント エンドは、すべてのパーティションを受信し、返されたすべての応答をキャッシュします。 以降、同じ接続上で行われる受信要求でこのキャッシュを利用できるため、受信で発生する遅延は小さくなります。 ただし、複数の接続がある場合、または HTTP を使っている場合は、要求ごとに新しい接続が確立されます。 そのため、同じノードに接続することは保証されません。 既存のメッセージがすべてロックされ、別のフロント エンドでキャッシュされている場合は、受信操作から nullが返されます。 最終的にはメッセージの有効期限が切れ、再度受信できる状態になります。 HTTP キープアライブの使用をお勧めします。 低量のシナリオでパーティション分割を使用する場合、受信操作に予想以上の時間がかかることがあります。 そのため、このようなシナリオではパーティション分割を使用しないことをお勧めします。 パーティション分割された既存のエンティティをすべて削除し、パフォーマンスを向上させるためにパーティション分割を無効にして再作成してください。
- メッセージの参照またはピーク: ピーク操作により、要求されたメッセージの数が常に返されるわけではありません。 一般に、この動作には 2 つの理由があります。 1 つ目は、メッセージのコレクションの総サイズが、最大サイズを超えていることです。 もう 1 つの理由は、パーティション分割されたキューまたはトピックでは、あるパーティションに、要求されたメッセージの数を返すための十分なメッセージがない可能性があることです。 一般に、アプリケーションは特定の数のメッセージをピークまたは参照しようとする場合、その数のメッセージを取得するか、またはピークするメッセージが存在しなくなるまで、ピーク操作を繰り返し呼び出す必要があります。 コード サンプルを含む詳細については、「メッセージの読み取り」を参照してください。
パーティション分割されたエンティティの制限事項
現在、Service Bus は、パーティション分割されたキューまたはトピックに以下の制限を適用します。
パーティション分割された Premium 名前空間の場合、メッセージが個別に送信されたときはメッセージ サイズが 1 MB に制限され、メッセージがバッチ内で送信されたときはバッチ サイズが 1 MB に制限されます。
パーティション分割されたキューおよびトピックでは、異なるセッションに属するメッセージの 1 つのトランザクションでの送信をサポートしていません。
Basic および Standard SKU の場合、現在、Service Bus は、名前空間ごとに最大 100 個のパーティション分割されたキューまたはトピックをサポートします。 パーティション分割された各キューまたはトピックは、名前空間あたり 10,000 エンティティのクォータに対してカウントされます。
次のステップ
Azure portal、PowerShell、CLI、Resource Manager テンプレート、.NET、Java、Python、JavaScript を使用して、パーティション分割を有効にすることができます。 詳細については、パーティション分割の有効化 (Basic と Standard) に関する記事を参照してください。
Advanced Message Queueing Protocol (AMQP) 1.0 プロトコル ガイドで、AMQP 1.0 メッセージング仕様の核となる概念を確認します。