オープンソース RabbitMQ クライアント SDK は ApsaraMQ for RabbitMQ と互換性がありますが、プラットフォーム固有の動作には注意が必要です。本ページでは、接続管理、メッセージの送信、メッセージの消費に関するベストプラクティスについて説明します。
接続管理
自動接続復旧の有効化
com.rabbitmq.client.ConnectionFactory で自動接続復旧を有効にします。有効にしない場合、ブローカーのアップグレード時にメッセージの読み書きが中断され、クライアントが自動的に再接続できなくなります。
// 自動接続復旧を有効にします
factory.setAutomaticRecoveryEnabled(true);
// 復旧試行間隔を設定します (ミリ秒)
factory.setNetworkRecoveryInterval(5000);永続的な接続の使用
パブリッシュ操作や消費操作のたびに接続を開閉しないでください。頻繁な再接続は、ネットワークリソースとブローカーリソースを浪費し、SYN フラッド保護をトリガーする可能性があります。
詳細については、「接続とチャネル」をご参照ください。
アプリケーションコード内でのメタデータ操作の回避
queueDeclare や exchangeDeclare などのメタデータ操作は、スロットリングの対象となります。スロットリングがトリガーされると、ブローカーが接続を閉じる可能性があります。
キューとエクスチェンジは、メッセージ送信時の実行時に宣言するのではなく、ApsaraMQ for RabbitMQ コンソールを通じて作成してください。スロットリング制限の詳細については、「制限」をご参照ください。
メッセージの送信
パブリッシャー確認の設定
パブリッシャー確認を使用すると、ブローカーが各メッセージをディスクに書き込んだ後に確認応答を返すため、クライアントは配信の失敗を検出して再試行できます。この確認ステップにより、メッセージが永続化されたことを保証できますが、ブローカーからの応答を待つため、レイテンシが増加する可能性があります。
チャネルでパブリッシャー確認を有効にするには、次の手順に従います:
チャネル作成時に
confirmSelect()を呼び出します。// 接続とチャネルを作成します Connection connection = createConnection(hostName, userName, passWord, virtualHost); Channel channel = connection.createChannel(); // パブリッシャー確認を有効にします channel.confirmSelect();basicPublishの呼び出し後、ブローカーの応答を待機し、結果を処理します。// メッセージをパブリッシュします (既存のチャネルを再利用) channel.basicPublish(exchangeName, bindingKey, true, props, ("example body").getBytes(StandardCharsets.UTF_8)); // 最大 3 秒間確認を待機します if (channel.waitForConfirms(3000)) { // メッセージがディスクへ正常に永続化されました } else { // 確認に失敗しました -- メッセージを再送信します }
メッセージが確認されるのは、クライアントがブローカーから publishAck を受信した場合のみです。クライアントがメッセージの送信に失敗した場合、または publishAck を受信しなかった場合は、メッセージの損失を防ぐために送信を再試行してください。
mandatory フラグによるルーティングできないメッセージの処理
mandatory パラメータを true に設定すると、メッセージがどのキューにもルーティングできない場合に、ブローカーが ReturnListener コールバックを呼び出します。
// ルーティングできないメッセージ用のコールバックを登録します
channel.addReturnListener(returnMessage ->
System.out.println("return msgId=" + returnMessage.getProperties().getMessageId()));
// mandatory=true でパブリッシュします (第 3 パラメータ)
channel.basicPublish(exchangeName, routingKey, true, props,
content.getBytes(StandardCharsets.UTF_8));すべてのメッセージへのメッセージ ID の割り当て
各メッセージにカスタム ID を割り当てることで、トレースをクエリし、配信の問題をトラブルシューティングできます。詳細については、「メッセージ ID を指定するにはどうすればよいですか?」をご参照ください。
パブリッシュエラーの処理
basicPublish が返すエラータイプに基づいて、エラー処理戦略を決定してください。
ビジネス例外 (
ExchangeNotExistなど): 直ちに例外をスローします。スロットリングまたはチャネルクローズ: 既存の接続を閉じ、新しいチャネルを作成して初期化し、送信を再試行します。
例:
private void doSend(String content) throws Exception {
try {
// 一意のメッセージ ID を割り当てます
String msgId = UUID.randomUUID().toString();
AMQP.BasicProperties props = new AMQP.BasicProperties.Builder().messageId(msgId).build();
channel.basicPublish(exchangeName, routingKey, true, props, content.getBytes(StandardCharsets.UTF_8));
// 最大 3 秒間確認を待機します
if (channel.waitForConfirms(3000)) {
// メッセージがディスクへ正常に永続化されました
} else {
// 確認に失敗しました -- メッセージを再送信します
}
} catch (Exception e) {
String message = e.getMessage();
System.out.println(message);
if (channelClosedByServer(message)) {
// 復旧: 古いチャネルを閉じ、新しいチャネルを作成して再初期化し、再試行します
factory.closeCon(channel);
channel = factory.createChannel();
this.initChannel();
doSend(content);
} else {
// ブローカー以外のエラー -- 例外を伝播します
throw e;
}
}
}
private boolean channelClosedByServer(String errorMsg) {
if (errorMsg != null && errorMsg.contains("channel.close")) {
return true;
} else {
return false;
}
}完全なサンプルコードについては、「メッセージの送信」をご参照ください。
Spring Boot クライアントの接続モードの設定
Spring Boot クライアントを使用する場合、接続キャッシュモードをデフォルトの channel モードではなく、connection に明示的に設定する必要があります。接続キャッシングをサポートする他のクライアントライブラリについても同じ原則が適用されます。常に接続モードを明示的に設定してください。
たとえば、application.properties または application.yml で次のプロパティを設定します:
spring.rabbitmq.cache.connection.mode=connectionたとえば、application.properties または application.yml に次のプロパティを設定します:
spring.rabbitmq.cache.connection.mode=connectionプロデューサーごとの複数接続の確立
メッセージを送信する際、各プロデューサークライアントは複数の接続を確立して、複数のバックエンドサービスノードに接続する必要があります。これにより、単一の接続における突発的なトラフィックスパイクによるリソースのボトルネックを回避できます。
推奨事項:
各プロデューサークライアントは、バックエンドに 50 接続を確立する必要があります。
これらの接続は、複数のバックエンドサービスノードに分散させる必要があります。
メッセージの消費
消費の偏りの防止
メッセージがコンシューマー間で均等に分散されるようにしてください。消費の偏りが発生すると、一部のコンシューマーが過負荷になり、他のコンシューマーがアイドル状態になります。設定の詳細については、「接続とチャネル」の「使用上の注意」セクションをご参照ください。
ブローカー生成のコンシューマータグの使用
手動でコンシューマータグを指定するのではなく、ブローカーにグローバルに一意なコンシューマータグを生成させてください。カスタムコンシューマータグを指定する場合は、すべてのコンシューマー間で一意であることを確認してください。
QoS (プリフェッチ) の設定
basicQos を呼び出して、ブローカーがコンシューマーにプッシュする未確認のメッセージ数を制限します。この制限に達すると、コンシューマーが未処理のメッセージを確認するまで、ブローカーは配信を一時停止します。
スコープオプション:
呼び出し | スコープ |
| チャネル上のすべてのコンシューマーが、未確認のメッセージ 100 件という合計制限を共有します |
| チャネル上の各コンシューマーが、未確認のメッセージ 100 件という独自の制限を持ちます |
プラットフォームの制約:
デフォルトの QoS 値は、コンシューマーあたり 100 で、
channel.basicQos(100, false)と同等です。カスタム QoS 値は 100 を超えることはできません。100 を超える値は無視され、代わりにデフォルト値が使用されます。
basicQosは、自動 ACK モードでは効果がありません。
QoS 値の選択:
シナリオ | 推奨 QoS | 根拠 |
少数のコンシューマー、高速処理 | より高い値 (最大 100) | コンシューマーが安定したメッセージフローで稼働し続けます |
多数のコンシューマー、低速処理 | より低い値 (たとえば、1~10) | メッセージを均等に分散し、単一のコンシューマーが過負荷にならないようにします |
蓄積されたメッセージが断続的な配信を引き起こす | QoS を増やさないでください | 代わりにコンシューマーのスループットを改善してください -- 根本原因はメッセージ処理の遅さです |
ブローカー上の蓄積された未確認のメッセージが QoS 制限に達すると、ブローカーはメッセージのプッシュを停止し、配信が断続的になることがあります。コンシューマーを再起動すると一時的に配信が復旧しますが、根本的な修正はコンシューマーの処理速度を向上させることです。
ACK タイムアウトとリトライ動作
コンシューマーが設定されたタイムアウト内にメッセージを確認しない場合、ブローカーはメッセージを再配信します。
各メッセージは、設定された最大回数まで再試行できます。最大再試行回数に達した後、メッセージは破棄されるか、デッドレターエクスチェンジにルーティングされます。
タイムアウトと再試行制限は、インスタンスタイプとエディションによって異なります。
パラメータ | Serverless (共有) | Serverless (専用) | Subscription (Enterprise Edition) | Subscription (Platinum Edition) |
消費タイムアウト | 最大: 3 時間、デフォルト: 5 分 | 最大: 12 時間、デフォルト: 30 分 | 最大: 3 時間、デフォルト: 5 分 | 最大: 12 時間、デフォルト: 30 分 |
最大配信試行回数 | 最大: 16、デフォルト: 16 | 最大: 16、デフォルト: 16 | 最大: 16、デフォルト: 16 | 最大: 64、デフォルト: 16 |
basicGet ではなく basicConsume の使用
basicGet は個別のメッセージをポーリングし、basicConsume と比較してスループットとトランザクション/秒 (TPS) の制限が低くなります。メッセージ量が多い本番環境では、プッシュベースの配信を行うには、長時間稼働するコンシューマーで basicConsume を使用してください。