次の方法で共有


メッセージの転送、ロック、および解決

Service Bus などのメッセージ ブローカーの重要な機能は、メッセージを受信し、後で取得できるようにキューまたはトピックに保存することです。 送信という用語は、一般的に、メッセージ ブローカーにメッセージを転送することを指します。 受信という用語は、一般的に、メッセージを取得しているクライアントへメッセージを転送することを指します。

クライアントがメッセージを送信する場合、通常は、メッセージが正常に転送され、ブローカーが受信したか、またはなんらかのエラーが発生したかどうかの確認が求められます。 この肯定または否定応答により、クライアントとブローカーの両方のメッセージの転送状態についての理解が確定します。 そのため、これを "解決" と呼びます。

同様に、ブローカーがメッセージをクライアントに転送する場合、ブローカーとクライアントは、メッセージが正常に送信、処理され、削除できる状態か、またはメッセージの転送や処理が失敗し、メッセージを再送信する必要があるかの確認を求めます。

送信操作の解決

サポートされている Service Bus API クライアントを使用した Service Bus への送信操作では、通常、明示的に解決されます。API 操作は、Service Bus からの受信結果を受け取るまで待機してから送信操作を完了します。

Service Bus によってメッセージが拒否された場合、拒否には、エラーのインジケーターと、追跡 ID が含まれたテキストが含まれます。 拒否には、操作が成功する可能性があり、操作を再試行するかどうかに関する情報も含まれています。 この情報はクライアント内で例外に変換され、送信操作の呼び出し元に報告されます。 メッセージが受け取られた場合、操作は自動的に完了します。

Advanced Messaging Queuing Protocol (AMQP) は、.NET Standard、Java、JavaScript、Python、Go クライアントでサポートされている唯一のプロトコルです。 .NET Framework クライアントの場合は、Service Bus メッセージング プロトコル (SBMP) または AMQP を使用できます。 AMQP プロトコルを使用すると、メッセージの転送と決済がパイプライン化され、非同期になります。 非同期プログラミング モデルの API バリアントを使用することをお勧めします。

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 から公式のサポートと更新プログラムは提供されなくなります。 詳細については、サポート廃止のお知らせに関するページを参照してください。

送信プログラムは、SBMP プロトコルまたは HTTP 1.1 を使用した場合のように、各メッセージの確認を待機する必要がなく、複数のメッセージを短時間に連続的に送信できます。 これらの非同期送信操作は、各メッセージの受け取りや、パーティション分割されたエンティティへのメッセージの格納と同時に、または別のエンティティへの送信と重複して実行できます。 元の送信順序とは異なる順序で完了する場合もあります。

送信操作の結果をどう処理するかを決める戦略は、アプリケーションのパフォーマンスに即時の、かつ重要な影響を与える可能性があります。 このセクションの例は C# で記述されており、Java Future、Java monos、JavaScript Promise、および他の言語の同等の概念に適用されます。

これ例では単純なループを使ってアプリケーションによって大量のメッセージが生成され、各送信操作が完了してから次のメッセージを送信しています。同期および非同期 API では、いずれも、解決するまで順次 10 回完全なラウンドトリップを行ってから 10 メッセージのみ送信されています。

あるオンプレミス サイトから Service Bus までの伝送制御プロトコル (TCP) ラウンドトリップ遅延距離を 70 ミリ秒と想定し、Service Bus が各メッセージを受け取り、保存するまで 10 ミリ秒しかかからないとしても、次のループは 8 秒以上かかり、これには、ペイロードの転送時間やルートの輻輳効果の可能性は考慮に入れられていません。

for (int i = 0; i < 10; i++)
{
    // creating the message omitted for brevity
    await sender.SendMessageAsync(message);
}

アプリケーションが連続的に 10 個の非同期送信操作を開始し、各送信操作の完了を個別に待機した場合、これら 10 個の送信操作のラウンドトリップ時間は重複します。 10 個のメッセージが連続して転送され、この場合 TCP フレームが同じである可能性もあり、転送時間は主に、ブローカーにメッセージを転送するためのネットワーク関係の時間によって決まります。

前述のループでも同様に推定すると、その次のループの重複実行時間の合計は、1 秒をはるかに下回る可能性があります。

var tasks = new List<Task>();
for (int i = 0; i < 10; i++)
{
    tasks.Add(sender.SendMessageAsync(message));
}
await Task.WhenAll(tasks);

すべての非同期プログラミング モデルでは、保留中の操作を保持するため、なんらかの形式のメモリ ベースの隠された作業キューが使用されることに注意してください。 送信 API が返ると、送信タスクは作業キューに入りますが、プロトコル動作は、タスクの実行順序が来るまで開始されません。 信頼性が考慮されるべき状況で、メッセージを連続送信する傾向のあるコードの場合、送信されるまですべての送信メッセージがメモリを使用するため、一度に送信されるメッセージが多くなりすぎないよう注意する必要があります。

次のコード スニペットで示すように、C# のセマフォは、必要な時にアプリケーション レベルを調整できる同期オブジェクトです。 このようにセマフォを使用すると、同時に送信されるメッセージを最大 10 個に制限できます。 使用できる 10 個のセマフォ ロックの 1 つが送信前に取得され、送信が完了すると解放されます。 11 番目のセマフォは、送信前操作の少なくとも 1 つが完了するまでループで待機してから、ロックを使用できるようにします。

var semaphore = new SemaphoreSlim(10);

var tasks = new List<Task>();
for (int i = 0; i < 10; i++)
{
    await semaphore.WaitAsync();

    tasks.Add(sender.SendMessageAsync(message).ContinueWith((t)=>semaphore.Release()));
}
await Task.WhenAll(tasks);

アプリケーションは、操作の結果を取得しない、"送信して放置" 方法で非同期送信する設計には絶対にしない必要があります。 そのような設計では、内部および隠れたタスク キューがメモリを消費し、アプリケーションが送信エラーを検知できなくなります。

for (int i = 0; i < 10; i++)
{
    sender.SendMessageAsync(message); // DON’T DO THIS
}

低レベルの AMQP クライアントの場合、Service Bus では "解決済み" 転送を実行できます。 解決済み転送とは、操作の結果が成功でも失敗でもクライアントに報告されず、メッセージは送信時点で解決したと見なされる、"送信して放置" 操作です。 クライアントへのフィードバックがないため、診断に使用できる行動可能なデータがなく、このモードは Azure のサポートを受ける資格がありません。

受信操作の解決

受信操作を行う Service Bus API クライアントには、受信して削除ピーク ロックの 2 つの明示的なモードがあります。

ReceiveAndDelete

受信して削除モードでは、ブローカーは、ブローカーが受信クライアントに送信するすべてのメッセージを、送信時点で解決済みとみなします。 つまり、ブローカーが送信するとただちにメッセージは消費されたとみなされます。 メッセージの転送が失敗した場合、メッセージは失われます。

このモードのメリットは、受信側メッセージでそれ以上のアクションを実行する必要はなく、解決の結果を待機する遅延も発生しないことです。 各メッセージに含まれるデータの価値が低い、またはデータが意味を持つ時間が非常に短時間の場合は、このモードは妥当な選択です。

PeekLock

ピーク ロックモードでは、受信クライアントが、受信したメッセージの明示的な解決を求めることを、ブローカーに指示します。 受信クライアントが処理できるよう、メッセージに排他的なロックがかけられ、他の競合受信クライアントからは認識できなくなります。 ロックの有効期間は、当初キューまたはサブスクリプション レベルで定義され、ロックを所有しているクライアントによる RenewMessageLockAsync 操作によって延長できます。 ロックの更新の詳細については、この記事の「ロックの更新」セクションを参照してください。

メッセージにロックがかけられると、同じキューまたはサブスクリプションから受信するクライアントがロックを受け取り、アクティブなロックがかけられているメッセージではなく、次に使用可能なメッセージを取得できます。 メッセージのロックが明示的に解放された、またはロックの有効期限が切れた場合は、メッセージは取得順序の前または近くに配置され再送信されます。

受信側によって、メッセージが繰り返し放棄された、または定義されたロック回数 (最大配信回数) の超過が容認された場合、メッセージはキューまたはサブスクリプションから自動的に削除され、関連する配信不能キューに配置されます。

受信側のクライアントは、メッセージに対して Complete API を呼び出すときに、肯定の確認を使用して、受信メッセージの解決を開始します。 それにより、メッセージが正常に処理されたことがブローカーに通知され、メッセージはキューまたはサブスクリプションから削除されます。 ブローカーは、受信側の解決要求に対し、解決が実行できるかを示す返信を返します。

受信クライアントがメッセージの処理に失敗したが、メッセージの再送を求める場合、メッセージに対して Abandon API を呼び出してメッセージの解放とロック解除を即座に行うことを明示的に要求するか、あるいはロックの有効期限が切れるまで待つことができます。

受信クライアントは、メッセージの処理に失敗して、メッセージの再送や操作の再試行が無駄だと判断した場合、メッセージを拒否できます。これによって、メッセージに対して DeadLetter API が呼び出されメッセージは配信不能キューに移動されます。また、それにより、配信不能キューからのメッセージと共に取得できる理由コードを含むカスタム プロパティを設定できるようになります。

Note

キューまたはトピック サブスクリプションの配信不能サブキューは、キューまたはサブスクリプションに対して配信不能機能が有効になっている場合にのみ存在します。

解決の特殊なケースは、別の記事で説明されている遅延です。

CompleteDeadLetter、または RenewLock 操作は、保持されているロックの有効期限が切れた場合、または解決を妨げる他のサービス側の条件が存在する場合、ネットワークの問題で失敗することがあります。 後者の場合、サービスは、API クライアントからは例外と認識される否定応答を送信します。 理由がネットワーク接続の切断の場合、Service Bus は、再接続による既存の AMQP リンクの回復をサポートしていないため、ロックは削除されます。

Complete の失敗は、通常は、メッセージ最終の処理で、または処理作業から数分経ってから発生し、その場合、受信アプリケーションでは、作業の状態を保存して、同じメッセージがもう 1 度送信されたときに無視するか、あるいは作業結果を破棄してメッセージが再送されたときに再試行するかを決定できます。

重複するメッセージの配信を識別するための一般的な方法は、送信側によって一意の値に設定され、元の処理からの ID と紐付けられている場合もある、メッセージ ID を確認することです。 ジョブ スケジューラは、特定の worker に割り当てようとしているジョブの識別子にメッセージ ID を設定することが多く、worker は、ジョブが既に完了している場合は、2 回目のジョブの割り当てを無視します。

重要

PeekLock や SessionLock がメッセージに対して取得するロックは揮発性であり、次のような状況では失われる可能性があることに注意してください

  • サービスの更新
  • OS の更新
  • ロックを保持したままエンティティ (キュー、トピック、サブスクリプション) のプロパティを変更。

ロックが失われると、Azure Service Bus によって MessageLockLostException や SessionLockLostException が生成され、クライアント アプリケーションに表示されます。 この場合、クライアントの既定の再試行ロジックが自動的に開始され、操作が再試行されます。

ロックの更新

ロック期間の既定値は 1 分です。 ロック期間に対して、キューまたはサブスクリプション レベルで別の値を指定できます。 メッセージ ロックが、ロックを所有しているクライアントによって、受信側オブジェクトのメソッドを使用して更新されることがあります。 その代わりに、ロックの自動更新機能を使用できます。この機能では、ロックの更新を続ける期間を指定できます。

ロック期間を通常の処理時間よりも長く設定して、ロックを更新する必要がないようにすることをお勧めします。 最大値は 5 分であるため、この時間を長くする場合はロックを更新する必要があります。 必要以上に長いロック期間を設定すると、いくつかの影響もあります。 たとえば、クライアントが動作を停止すると、ロック期間が経過した後にのみ、メッセージが再び使用できるようになります。

次のステップ