この記事では、ブローカー メッセージを交換する際のパフォーマンスを Azure Service Bus を使用して最適化する方法について説明しています。 この記事の前半では、パフォーマンスを向上させるためのさまざまなメカニズムについて説明します。 後半では、特定のシナリオで最大限のパフォーマンスを実現できるような方法で Service Bus を使用するためのガイダンスを示します。
この記事全体で、"クライアント" という用語は Service Bus にアクセスするすべてのエンティティを指します。 クライアントは送信側または受信側の役割を実行できます。 "送信側" という用語は、Service Bus キューまたはトピックにメッセージを送信する Service Bus キュー クライアントまたはトピック クライアントを指します。 "受信側" という用語は、Service Bus キューまたはサブスクリプションからメッセージを受信する Service Bus キュー クライアントまたはサブスクリプション クライアントを指します。
リソースの計画と考慮事項
技術的リソースと同様に、アプリケーションに必要なパフォーマンスを Azure Service Bus で提供するには、用意周到な計画が鍵になります。 Service Bus 名前空間の適切な構成またはトポロジは、アプリケーションのアーキテクチャや各 Service Bus 機能の使用方法など、多数の要因によって決まります。
価格階層
Service Bus には、さまざまな価格レベルが用意されています。 アプリケーションの要件に適したレベルを選択することをお勧めします。
Standard レベル - 開発やテスト環境、またはアプリケーションがスロットル調整の影響を受けない低スループットのシナリオに適しています。
Premium レベル - 予測可能な待機時間とスループットが必要な、さまざまなスループット要件を持つ運用環境に適しています。 さらに、Service Bus Premium 名前空間は 自動スケーリング でき、スループットの急増に対応するために有効にすることができます。
注
適切なレベルが選択されていない場合は、Service Bus 名前空間が過負荷になり、 調整につながる可能性があります。
スロットリングによってデータが失われることはありません。 Service Bus SDK を使用するアプリケーションでは、既定の 再試行ポリシー を使用して、データが最終的に Service Bus によって受け入れられるようにすることができます。
Premium のスループットの計算
Service Bus に送信されるデータはバイナリにシリアル化され、受信側が受信すると逆シリアル化されます。 したがって、アプリケーションは メッセージ をアトミック作業単位と見なしますが、Service Bus はバイト (またはメガバイト) の観点からスループットを測定します。
スループットの要件を計算するときは、Service Bus に送信されるデータ (イングレス) と、Service Bus から受信されるデータ (エグレス) について考慮してください。
当然ですが、スループットは、まとめてバッチ処理できるメッセージ ペイロードが小さければ小さいほど大きくなります。
ベンチマーク
Service Bus 名前空間で受け取る予想スループットを確認するために実行できる GitHub サンプル を次に示します。 ベンチマーク テストでは、イングレスとエグレスのメッセージング ユニット (MU) あたり約 4 MB/秒を確認しました。
このベンチマークのサンプルでは高度な機能は使用しないため、シナリオによってアプリケーションで観測されるスループットが異なります。
コンピューティングに関する考慮事項
Service Bus は、コンピューティング使用率に影響を与える可能性のある複数のバックグラウンド プロセスを運用します。 これらには、タイマー、スケジュール、メトリクスの使用が含まれますが、これだけに限りません。 さらに、特定の Service Bus 機能を使用すると、予想スループットを低下させる可能性があるコンピューティング使用率が必要になります。 これらの機能の一部を次に示します。
- セッション。
- 1 つのトピックで複数のサブスクリプションに展開する。
- 1 つのサブスクリプションで多数のフィルターを実行する。
- スケジュール設定されたメッセージ。
- 遅延メッセージ。
- トランザクション。
- 重複除去とルックバックの時間枠。
- 転送 (一方のエンティティから他方のエンティティへの転送)。
アプリケーションで上記のいずれかの機能を使用していて、予想されるスループットを受け取っていない場合は、 CPU 使用率 メトリックを確認し、Service Bus Premium 名前空間のスケールアップを検討できます。 また、Azure Monitor を使用して Service Bus 名前空間を自動的にスケーリングすることもできます。 最適なパフォーマンスを確保するために、CPU 使用率が 70% を超える場合は、メッセージ ユニット (RU) の数を増やすことをお勧めします。
名前空間間のシャーディング
名前空間に割り当てられたコンピューティング (メッセージング ユニット) のスケールアップは簡単なソリューションですが、スループットが直線的に増加 しない可能性があります 。 これは、Service Bus 内部 (ストレージ、ネットワークなど) によって、スループットが制限される場合があるためです。
この場合の比較的クリーンな解決策は、異なる Service Bus Premium 名前空間間でエンティティ (キューとトピック) をシャードすることです。 また、異なる Azure リージョン内の異なる名前空間間でのシャーディングも検討できます。
プロトコル
Service Bus を使用すると、クライアントは次の 3 つのプロトコルのいずれかを使用してメッセージを送受信できます。
- Advanced Message Queuing Protocol (AMQP) (アドバンスト メッセージ キュー プロトコル (AMQP))
- Service Bus メッセージング プロトコル (SBMP)
- ハイパーテキスト転送プロトコル (HTTP)
AMQP は、Service Bus への接続を維持するため、最も効率的です。 また、バッチ処理と プリフェッチも実装します。 明示的に示されていない限り、この記事のすべてのコンテンツで AMQP または SBMP を使用するものとします。
重要
SBMP プロトコルは、.NET Framework のみで使用できます。 AMQP は、.NET Standard の既定です。
2026 年 9 月 30 日に Azure Service Bus 用の SBMP プロトコルのサポートは終了するため、2026 年 9 月 30 日以降はこのプロトコルを使用できなくなります。 その日付より前に、(重要なセキュリティ更新プログラムと強化された機能が提供される) AMQP プロトコルを使った最新の Azure Service Bus SDK ライブラリに移行してください。
詳細については、 サポート終了のお知らせを参照してください。
適切な Service Bus .NET SDK の選択
Azure.Messaging.ServiceBus
パッケージは、2020 年 11 月の時点で利用可能な最新の Azure Service Bus .NET SDK です。 2026 年 9 月 30 日まで重要なバグの修正プログラムが提供され続ける 2 つの古い .NET SDK が存在しますが、代わりに最新の SDK を使うことを強くお勧めします。 古い SDK から移行する方法の詳細については、 移行ガイド を参照してください。
NuGet パッケージ | プライマリ名前空間 | 最小プラットフォーム | プロトコル |
---|---|---|---|
Azure.Messaging.ServiceBus (最新) | Azure.Messaging.ServiceBus Azure.Messaging.ServiceBus.Administration |
.NET Core 2.0 (英語) .NET Framework 4.6.1 (英語) モノラル5.4 ユニバーサル Windows プラットフォーム 10.0.16299 |
AMQP HTTP |
マイクロソフト.Azure.ServiceBus | Microsoft.Azure.ServiceBus Microsoft.Azure.ServiceBus.Management |
.NET Core 2.0 (英語) .NET Framework 4.6.1 (英語) モノラル5.4 ユニバーサル Windows プラットフォーム 10.0.16299 |
AMQP HTTP |
.NET Standard プラットフォームの最小サポートの詳細については、 .NET 実装のサポートを参照してください。
2026 年 9 月 30 日に、Azure SDK ガイドラインに準拠していない Azure Service Bus SDK ライブラリ WindowsAzure.ServiceBus、Microsoft.Azure.ServiceBus、および com.microsoft.azure.servicebus は廃止されます。 SBMP プロトコルのサポートも終了するため、2026 年 9 月 30 日以降はこのプロトコルを使用できなくなります。 この日付より前に、重要なセキュリティ更新プログラムと強化された機能が提供される、最新の Azure SDK ライブラリに移行してください。
古いライブラリは 2026 年 9 月 30 日以降も引き続き使用できますが、Microsoft から公式のサポートと更新プログラムは提供されなくなります。 詳細については、 サポート終了のお知らせを参照してください。
ファクトリとクライアントの再利用
ServiceBusClient、ServiceBusSender、ServiceBusReceiver、ServiceBusProcessor など、サービスと対話する Service Bus クライアントは、依存関係の挿入用にシングルトンとして登録する (または 1 回インスタンス化して共有する) 必要があります。 ServiceBusClient (ファクトリ) は、 ServiceBusClientBuilderExtensions を使用して依存関係の挿入に登録できます。
これらのクライアントは、各メッセージの送信または受信後に閉じたり破棄したりしないことをお勧めします。 エンティティ固有のオブジェクト (ServiceBusSender/Receiver/Processor) を閉じるたり破棄したりすると、Service Bus サービスへのリンクが解除されます。 ServiceBusClient を破棄すると、Service Bus サービスへの接続が切断されます。
ServiceBusSessionReceiver の有効期間はセッション自体と同じであるため、このガイダンスは適用されません。
ServiceBusSessionReceiver
と連携するアプリケーションでは、ServiceBusClient
のシングルトン インスタンスを使用して各セッションを受け入れることをお勧めします。これには、そのセッションにバインドされた新しい ServiceBusSessionReceiver
が含まれます。 アプリケーションがそのセッションの処理を完了すると、関連付けられている ServiceBusSessionReceiver
を破棄する必要があります。
次の注意事項はすべての SDK に当てはまります。
注
接続の確立は費用のかかる操作です。この操作は、同じファクトリまたはクライアント オブジェクトを複数の操作に再利用することで回避できます。 これらのクライアントオブジェクトは、同時実行の非同期操作のために、複数のスレッドから安全に使用できます。
同時実行の操作
送信、受信、削除などの操作には、時間がかかります。 この時間には、Service Bus サービスが操作を処理するための時間や、要求と応答の待機時間が含まれます。 時間あたりの操作数を増やすには、操作を同時に実行する必要があります。
クライアントは、 非同期 操作を実行して同時実行操作をスケジュールします。 前の要求が完了する前に次の要求が開始されます。 次のコード スニペットは、非同期送信操作の例です。
var messageOne = new ServiceBusMessage(body);
var messageTwo = new ServiceBusMessage(body);
var sendFirstMessageTask =
sender.SendMessageAsync(messageOne).ContinueWith(_ =>
{
Console.WriteLine("Sent message #1");
});
var sendSecondMessageTask =
sender.SendMessageAsync(messageTwo).ContinueWith(_ =>
{
Console.WriteLine("Sent message #2");
});
await Task.WhenAll(sendFirstMessageTask, sendSecondMessageTask);
Console.WriteLine("All messages sent");
次のコードは、非同期受信操作の例です。
var client = new ServiceBusClient(connectionString);
var options = new ServiceBusProcessorOptions
{
AutoCompleteMessages = false,
MaxConcurrentCalls = 20
};
await using ServiceBusProcessor processor = client.CreateProcessor(queueName,options);
processor.ProcessMessageAsync += MessageHandler;
processor.ProcessErrorAsync += ErrorHandler;
static Task ErrorHandler(ProcessErrorEventArgs args)
{
Console.WriteLine(args.Exception);
return Task.CompletedTask;
};
static async Task MessageHandler(ProcessMessageEventArgs args)
{
Console.WriteLine("Handle message");
await args.CompleteMessageAsync(args.Message);
}
await processor.StartProcessingAsync();
受信モード
キューまたはサブスクリプション クライアントを作成する場合は、受信モード ( ピーク ロック または 受信と削除) を指定できます。 既定の受信モードは PeekLock
です。 この規定のモードで操作するとき、クライアントは Service Bus からメッセージを受信する要求を送信します。 クライアントはメッセージを受信した後で、メッセージを完了する要求を送信します。
受信モードを ReceiveAndDelete
に設定すると、1 つの要求に両方の手順が連結されます。 これらの手順によって、操作全体の数が削減され、全体的なメッセージ スループットを改善できます。 この方法でパフォーマンスを改善すると、メッセージを失うリスクが生じます。
Service Bus は "受信して削除" 操作のトランザクションをサポートしません。 また、ピーク ロック セマンティクスは、クライアントがメッセージを延期または 配信不能 にするシナリオに必要です。
プリフェッチ
プリフェッチ により、キューまたはサブスクリプション クライアントは、メッセージを受信するときにサービスから追加のメッセージを読み込むことができます。 クライアントはこれらのメッセージをローカル キャッシュに格納します。 キャッシュのサイズは、ServiceBusReceiver.PrefetchCount
プロパティによって決まります。 プリフェッチが有効になっているクライアントはそれぞれ独自のキャッシュを保持します。 キャッシュはクライアント間で共有されません。 クライアントが受信操作を開始するときに、そのキャッシュが空の場合、サービスはメッセージのバッチを送信します。 クライアントが受信操作を開始するときに、そのキャッシュにメッセージが含まれている場合、キャッシュからメッセージが取得されます。
メッセージがプリフェッチされると、サービスはプリフェッチされたメッセージをロックします。 このロックにより、別の受信側はプリフェッチされたメッセージを受信できなくなります。 受信側がメッセージを完了できない状態でロックの有効期限が切れた場合、他の受信側がそのメッセージを使用できるようになります。 プリフェッチされたメッセージのコピーはキャッシュに残ります。 受信側が有効期限の切れたキャッシュのコピーを使用している場合、そのメッセージを完了しようとしたときに例外を受け取ります。 既定では、メッセージのロックは 60 秒後に期限切れになります。 この値は 5 分まで拡張できます。 期限切れのメッセージが使用されないようにするには、キャッシュ サイズを、クライアントがロックタイムアウト期間内に使用できるメッセージの数よりも小さく設定します。
60 秒間の既定のロック有効期限を使用するとき、PrefetchCount
の適切な値はファクトリの全受信者の最大処理レートの 20 倍になります。 たとえば、ファクトリが 3 つの受信側を作成すると、各受信側は 1 秒あたり最大 10 個のメッセージを処理できます。 プリフェッチ数が 20 X 3 X 10 = 600 を超えないようにしてください。 既定では、PrefetchCount
は 0 に設定されます。これはサービスから追加のメッセージがフェッチされないことを意味します。
メッセージをプリフェッチすると、メッセージ操作全体の数、つまりラウンド トリップが減るため、キューまたはサブスクリプションの全体でのスループットが増えます。 ただし、最初のメッセージのフェッチには (メッセージ サイズの増加に起因して) より多くの時間がかかります。 プリフェッチ済みのメッセージはクライアントが既にダウンロードしているため、キャッシュから迅速に受信できます。
サーバーがクライアントにメッセージを送信するとき、メッセージの有効期間 (TTL) プロパティがサーバーによりチェックされます。 クライアントは、メッセージを受信するときに、メッセージの TTL プロパティをチェックしません。 代わりに、メッセージがクライアントによりキャッシュされたときにメッセージの TTL を経過している場合でも、メッセージを受信できます。
プリフェッチは課金対象のメッセージ操作数に影響を与えません。また、Service Bus クライアント プロトコルでのみ利用できます。 HTTP プロトコルはプリフェッチをサポートしません。 プリフェッチは同期受信操作と非同期受信操作の両方で使用できます。
詳細については、次の PrefetchCount
プロパティを参照してください。
これらのプロパティの値は 、ServiceBusReceiverOptions または ServiceBusProcessorOptions で設定できます。
プリフェッチと ReceiveMessagesAsync
複数のメッセージをまとめてプリフェッチするという概念はメッセージのバッチ処理 (ReceiveMessagesAsync
) と似ていますが、いくつかの小さな違いがあり、これらの方法を一緒に使用する場合には覚えておく必要があります。
プリフェッチは ServiceBusReceiver に対する構成 (またはモード) ですが、ReceiveMessagesAsync
は (要求 - 応答のセマンティクスを持つ) 操作です。
これらの方法を一緒に使用する場合には、次のケースを考慮してください。
- プリフェッチは、
ReceiveMessagesAsync
から受信が予想されるメッセージ数と同じか、それよりも多くする必要があります。 - プリフェッチは、1 秒あたりに処理されるメッセージ数の最大で n/3 倍にすることができます。n は既定のロック期間です。
どん欲な方法、つまりプリフェッチ数を高く保つことには、いくつか課題があります。メッセージが特定の受信者にロックされることになるためです。 前述のしきい値の間にあるプリフェッチ値を試し、何が適合するかを特定することをお勧めします。
複数のキューまたはトピック
1 つのキューまたはトピックでは想定されるメッセージ数を処理できない場合は、複数のメッセージング エンティティを使用します。 複数のエンティティを使用するときは、すべてのエンティティに同じクライアントを使用するのではなく、エンティティごとに専用のクライアントを作成します。
キューやトピックが多いほど、デプロイ時に管理するエンティティが増えます。 スケーラビリティの観点からは、Service Bus によって既に内部的に複数のログに負荷が分散されており、ユーザーが気付くほどの大きな違いは実際にはないため、6 つのキューまたはトピックを使っても、2 つのキューまたはトピックを使っても、それほど違いません。
使用するサービス レベルは、パフォーマンスの予測可能性に影響します。 Standard レベルを選択した場合、スループットとレイテンシは、共有マルチテナントインフラに対してベストエフォートで提供されます。 同じクラスター上の他のテナントにより、スループットが影響を受ける可能性があります。 Premium を選択すると、予測可能なパフォーマンスを提供するリソースが得られ、そのリソース プールから複数のキューまたはトピックが処理されます。 詳細については、「 価格レベル」を参照してください。
パーティション分割された名前空間
パーティション分割された Premium レベルの名前空間を使用する場合、メッセージング ユニット (MU) が低い複数のパーティションを使用すると、より高い RU を持つ単一のパーティションに対するパフォーマンスが向上します。
シナリオ
次のセクションでは、一般的なメッセージング シナリオについて説明し、好ましい Service Bus 設定について概要を説明します。 スループット レートは小 (1 メッセージ/秒未満)、中 (1 メッセージ/秒以上、100 メッセージ/秒未満)、高 (100 メッセージ/秒以上) に分類されます。 クライアントの数は、小 (5 以下)、中 (5 以上、20 以下)、および大 (20 を超える) として分類されます。
高スループット キュー
目標: 1 つのキューのスループットを最大にします。 送信側と受信側の数は小です。
- キューへの全体的な送信レートを上げるには、複数のメッセージ ファクトリを使用して送信側を作成します。 送信側ごとに、非同期操作または複数のスレッドを使用します。
- キューからの全体的な受信レートを上げるには、複数のメッセージ ファクトリを使用して受信側を作成します。
- プリフェッチ数をファクトリの全受信側の最大処理レートの 20 倍に設定します。 この数の設定によって、Service Bus クライアント プロトコル伝送の数が減ります。
複数の高スループット キュー
目標: 複数のキューの全体的なスループットを最大にします。 個々のキューのスループットは中または高です。
複数のキュー全体で最大のスループットを得るには、説明にある設定を使用し、1 つのキューのスループットを最大化します。 また、複数のファクトリを使用し、複数のキューと送受信するクライアントを作成します。
低待機時間のキュー
目標: キューまたはトピックの待機時間を最小限に抑えます。 送信側と受信側の数は小です。 キューのスループットは小または中です。
- 1 つのクライアントを使用している場合、プリフェッチ数を受信側の処理レートの 20 倍に設定します。 複数のメッセージが同時にキューに到着すると、Service Bus クライアント プロトコルはそれらすべてを同時に送信します。 クライアントが次のメッセージを受信するとき、そのメッセージは既にローカル キャッシュにあります。 キャッシュは小にします。
- 複数のクライアントを使用している場合、プリフェッチ数を 0 に設定します。 この数を設定することで、最初のクライアントが最初のメッセージを処理している間に、2 番目のクライアントは 2 番目のメッセージを受信できます。
送信側の数が多いキュー
目標: 送信側の数が多いキューまたはトピックのスループットを最大にします。 送信側はそれぞれ中程度のレートでメッセージを送信します。 受信側の数は小です。
Service Bus によって、メッセージング エンティティに最大 1,000 件コンカレント接続できます。 この制限は名前空間レベルで適用され、キュー、トピック、またはサブスクリプションは名前空間あたりのコンカレント接続数の上限によって制限されます。 キューの場合、この数は送信側と受信側で共有されます。 1,000 件の接続すべてが送信側で必要な場合は、キューをトピックと 1 つのサブスクリプションで置き換えます。 トピックは、送信側から最大 1,000 件のコンカレント接続を受け入れます。 サブスクリプションは、受信側から追加の 1,000 件のコンカレント接続を受け入れます。 1,000 件を超える同時接続が送信側で必要な場合は、送信側は HTTP 経由で Service Bus プロトコルにメッセージを送信する必要があります。
スループットを最大化するには、これらの手順に従ってください。
- 各送信側が異なるプロセスにある場合、プロセスごとに 1 つのファクトリのみを使用します。
- プリフェッチ数をファクトリの全受信側の最大処理レートの 20 倍に設定します。 この数の設定によって、Service Bus クライアント プロトコル伝送の数が減ります。
受信側の数が多いキュー
目標: 受信側の数が多いキューまたはサブスクリプションの受信レートを最大にします。 各受信側は中程度のレートでメッセージを受信します。 送信側の数は小です。
Service Bus によって、エンティティに最大 1,000 件コンカレント接続できるようになります。 キューが 1,000 件を超える受信側を必要とする場合は、キューをトピックと複数のサブスクリプションで置き換えます。 各サブスクリプションは最大 1,000 件のコンカレント接続をサポートします。 または、受信側は HTTP プロトコル経由でキューにアクセスできます。
スループットを最大化するには、これらのガイドラインに従ってください。
- 各受信側が異なるプロセスにある場合、プロセスごとに 1 つのファクトリのみを使用します。
- プリフェッチ数を小さい値 (PrefetchCount = 10 など) に設定します。 この数の設定によって、他の受信側が大量のメッセージをキャッシュしている間に受信側がアイドル状態になることを防止できます。
いくつかのサブスクリプションが含まれるトピック
目標: いくつかのサブスクリプションが含まれるトピックのスループットを最大にします。 メッセージは多くのサブスクリプションで受信されます。これはすべてのサブスクリプションの受信レートを合わせると送信レートを超えることを意味します。 送信側の数は小です。 サブスクリプションあたりの受信側の数は小です。
スループットを最大化するには、これらのガイドラインに従ってください。
- トピックへの全体的な送信レートを上げるには、複数のメッセージ ファクトリを使用して送信側を作成します。 送信側ごとに、非同期操作または複数のスレッドを使用します。
- サブスクリプションからの全体的な受信レートを上げるには、複数のメッセージ ファクトリを使用して受信側を作成します。 受信側ごとに、非同期操作または複数のスレッドを使用します。
- プリフェッチ数をファクトリの全受信側の最大処理レートの 20 倍に設定します。 この数の設定によって、Service Bus クライアント プロトコル伝送の数が減ります。
サブスクリプションの数が多いトピック
目標: サブスクリプションの数が多いトピックのスループットを最大にします。 メッセージは多くのサブスクリプションで受信されます。これはすべてのサブスクリプションの受信レートを合わせると送信レートを超えることを意味します。 送信側の数は小です。 サブスクリプションあたりの受信側の数は小です。
すべてのメッセージがすべてのサブスクリプションに送信される場合、通常、多数のサブスクリプションを含むトピックの全体的なスループットは低下します。 その原因は、各メッセージが何度も受信され、トピックとそのすべてのサブスクリプション内のメッセージがすべて同じストアに保存されることにあります。 ここで、サブスクリプションあたりの送信側の数と受信側の数は少ないものとします。 Service Bus はトピックあたり最大 2,000 のサブスクリプションをサポートします。
スループットを最大化するには、次の手順を試します。
- プリフェッチ数を、メッセージが受信される予想レートの 20 倍に設定します。 この数の設定によって、Service Bus クライアント プロトコル伝送の数が減ります。