12. RabbitMQメッセージ確認モード
12.1 確認モードの概要
メッセージの確認確認メカニズムとは、プロデューサーがメッセージを配信し、メッセージ サーバー ブローカーの交換スイッチに到達した後、プロデューサーに応答を返し、プロデューサーはその応答を受信して、メッセージがブローカーに送信されるかどうかを判断することを意味します。通常、交換では、これはメッセージを確実に配信するための重要な保証でもあります。
12.2 特定のコード設定
1 ファイル application.yml を設定して確認モードを有効にします: spring.rabbitmq.publisher-confirm-type=_correlative_2 ACK 結果の成功と失敗を判断するために RabbitTemplate.confirmCallback を実装するクラスを作成します。 ack が false の場合、メッセージは再送信またはログに記録されます。rabbitTemplate 3 の確認コールバック メソッドを設定します。 |
---|
参照コード:
| @Component
public class MessageconfirmCallBackimplements RabbitTemplate.confirmCallback { /** * スイッチがメッセージを受信した後、メソッドをコールバックします * * @param correlationData 関連データ * @param ack には true と false の 2 つの値があり、true は成功を意味します: メッセージはスイッチに正しく到着しました。それ以外の場合、 false はメッセージがスイッチに正しく到着しなかったことを意味します * @param Cause メッセージがスイッチに正しく到着しなかった理由は何ですか */ @Override public voidconfirm(CorrelationData correlationData, boolean ack , String Cause) { System .out.println("correlationData = " + correlationData); System.out.println("ack = " + ack); System.out.println("cause = " + Cause); if (ack ) { //通常 } else {
// 異常です。ログに記録するか再送信する必要があるかもしれません
}
}
} |
---|
送信メッセージ参照コード
| @Service
public class MessageService { @Resource private RabbitTemplate RabbitTemplate; @Resource private MessageconfirmCallBack messageconfirmCallBack; @PostConstruct //Bean が初期化されるとき、このメソッドは 1 回だけ呼び出され、初期化の役割を果たします public void init() { RabbitTemplate.setconfirmCallback(messageconfirmCallBack); } /** * メッセージの送信 */ public void sendMessage() { //相関データ オブジェクト CorrelationData correlationData = new CorrelationData(); correlationData.setId("O159899323"); //たとえば、注文IDを設定すると、確認コールバックの時間が来ると、どの注文が取引所に送信されていないかを知ることができます
RabbitTemplate.convertAndSend(RabbitConfig.EXCHANGE + 123, “info”, “hello”, correlationData);
System.out.println("メッセージは送信されました...");
}
}
|
| — |
2 つの例: メッセージ送信時にインターフェイスを直接実装できる
13. RabbitMQ メッセージリターンモード
Rabbitmq のメッセージ配信全体のパスは次のとおりです:
プロデューサー —> エクスチェンジ —> キュー —> コンシューマー
メッセージがプロデューサーからエクスチェンジに送信されると、confirmCallback が返されます。
メッセージがエクスチェンジ –> キューから配信されなかった場合は、returnCallback が返されます。
これら 2 つのコールバックを使用して、メッセージの信頼性の高い配信を制御できます。 ;
確認モードを有効にする;
RabbitTemplate.setconfirmCallback を使用してコールバック関数を設定し、メッセージが交換機に送信されると、confirm メソッドがコールバックされます。メソッド内で ack を判定し、true の場合は送信成功、false の場合は送信失敗のため処理が必要ですが、
設定ファイルではリターンモードがオンになっていることに注意してください。
spring.rabbitmq.publisher-returns: true |
---|
use RabbitTemplate.setReturnCallback to set the return function. メッセージがエクスチェンジから
キューにルーティングされない場合、メッセージはプロデューサーに返され、コールバック関数 returnsMessage が実行されます。
|
@Component
public class MessageReturnCallBackimplements RabbitTemplate.ReturnsCallback { /** * このメソッドは、メッセージが交換機からキューに正しく到着しない場合にトリガーされます * メッセージが交換機からキューに正しく到着すると、このメソッドはトリガーされません * * @param returns */ @Override public void returnsMessage(ReturnedMessage returns) { System.out.println("Message return mode: " + returns); }
} |
---|
参照送信コード
| @Service
public class MessageService { @Resource private RabbitTemplate RabbitTemplate; @Resource private MessageReturnCallBack messageReturnCallBack; @PostConstruct //Bean が初期化されるとき、このメソッドは 1 回だけ呼び出され、初期化の役割を果たします public void init() { RabbitTemplate.setReturnsCallback(messageReturnCallBack); } /** * メッセージの送信 */ public void sendMessage() { RabbitTemplate.convertAndSend(RabbitConfig.EXCHANGE, “info123”, “hello”); System.out.println("メッセージには送信されました...”); } } | | — |
コード 2、メッセージ送信時に RabbitTemplate.ReturnsCallback を直接実装する
| @Service
public class MessageServiceimplements RabbitTemplate.ReturnsCallback { @Resource private RabbitTemplate RabbitTemplate; @PostConstruct //Bean が初期化されるとき、このメソッドは 1 回だけ呼び出され、初期化の役割を果たします public void init() { RabbitTemplate . setReturnsCallback(this); } /** * メッセージがスイッチからキューに正しく到着しない場合、このメソッドはトリガーされます * メッセージがスイッチからキューに正しく到着する場合、このメソッドはトリガーされません * * @param returns / @ Override public void returnsMessage(ReturnedMessage returns) { System.out.println("Message return mode: " + returns); } / * * メッセージを送信 */
public void sendMessage() { RabbitTemplate.convertAndSend(RabbitConfig.EXCHANGE, “info123”, “hello”); System.out.println("メッセージは送信されました..."); } } | | — |
コードリファレンス 3 RabbitTemplate.confirmCallback と RabbitTemplate.ReturnsCallback を同時に実装する
|
@Service
public class MessageServiceimplements RabbitTemplate.confirmCallback, RabbitTemplate.ReturnsCallback { @Resource private RabbitTemplate RabbitTemplate; @PostConstruct //Bean が初期化されるとき、このメソッドは 1 回だけ呼び出され、初期化の役割を果たします public void init ( ) { RabbitTemplate.setconfirmCallback(this); RabbitTemplate.setReturnsCallback(this); } /** * スイッチがメッセージを受信した後、このメソッドをコールバックします * * @param correlationData 関連データ * @param ack には 2 つの値があります。 true と false、true は成功を意味します: メッセージがスイッチに正しく到着しました。それ以外の場合、false はメッセージがスイッチに正しく到着しなかったことを意味します * @param Cause メッセージがスイッチに正しく到着しなかった理由は何ですか/ @Override
public voidconfirm(CorrelationData correlationData, boolean ack, String Cause) { System.out.println("correlationData = " + correlationData); System.out.println("ack = " + ack); System.out.println("cause = " + Cause); if (ack) { // OK } else { // 異常 } } /
*
* このメソッドは、交換からのメッセージがキューに正しく到着しなかった場合にトリガーされます
* メッセージが交換から正しく到着した場合交換キューの場合、メソッドはトリガーされません
*
* @param returns
/
@Override
public void returnsMessage(ReturnedMessage returns) { System.out.println("Message return mode: " + returns);
}
/ *
* メッセージの送信
*/
public void sendMessage() { //相関データ オブジェクト CorrelationData correlationData = new CorrelationData(); correlationData.setId("O159899323"); //たとえば、注文 ID を設定し、確認メッセージでcallback を使用すると、どの注文 が取引所に送信されなかったのかを知ることができます 。 } } | | — |
14. RabbitMQ スイッチの詳細プロパティ
14.1 特定のパラメータ
1. 名前: スイッチの名前。文字列です。
2. タイプ: スイッチのタイプ、ダイレクト、トピック、ファンアウト、ヘッダー 3.
耐久性: スイッチが耐久性があるかどうかを宣言し、スイッチがまだ動作しているかどうかを示します。サーバーの再起動後に存在します;
4. 自動削除: 自動的に削除するかどうか、キューがスイッチにバインドされ、その後バインドが解除されると、スイッチは自動的に削除されます; 5、内部: 内部的に使用されます。はいの場合、クライアントは直接できません
。このスイッチにメッセージを送信します。スイッチ間のバインディングにのみ使用できます。
6. 引数: 値は 1 つだけあり、alternate-exchange は代替スイッチを意味します。
14.2 コードのデモ
結論 1: メッセージ送信前にスイッチとキューは作成されない
結論 2: メッセージ送信後、スイッチが存在しない場合はスイッチが作成される キューが存在しない場合は新しいキューが作成される結論
3: スイッチまたはキューが作成されます 再作成後、スイッチまたはキューのパラメータを変更すると
、エラー 406 : 'false' を受け取りましたが、現在は 'true'、class-id= 40、method-id=10))
結論 4: 永続性を false に設定し、rabbitmq-server を再起動すると、スイッチが失われます。耐久性パラメータを試してください。 、最初にコンソールを見て、次に Rabbitmq-server を再起動します。
結論 5: 自動削除を true にして実験し、コンソールから手動でバインドを解除すると、自動的に削除されることがわかります。
14.3 スタンバイスイッチ
14.3.1 スタンバイスイッチの使用シナリオ
メッセージがスイッチを介してキューにルーティングされる準備ができたときに、情報を配信するための対応するキューがないことがわかります。rabbitmq では、メッセージはデフォルトで破棄されます。どのメッセージが配信されるかを監視したい場合は、対応しないキューの場合は、バックアップ スイッチを使用してスタンバイ スイッチのメッセージを受信し、ログを記録したり、アラーム情報を送信したりできます。
14.3.2 主なコードと注意事項
バックアップ スイッチの例は次のとおりです:
注意: バックアップ スイッチは通常、ファンアウト スイッチを使用します。
テスト時: 間違ったルートを指定してください
。重要: 通常のスイッチ設定パラメータはバックアップ スイッチにバインドされています。
| Map<String, Object> argument = new HashMap<>();
//現在の通常のスイッチのバックアップ スイッチを指定します
argument.put(“alternate-exchange”, EXCHANGE_ALTERNATE);
//DirectExchange(String name, boolean耐久性、ブール型 autoDelete、Map<String, Object> 引数) は
新しい DirectExchange(EXCHANGE, true, false, argument) を返します。
//return ExchangeBuilder.directExchange(EXCHANGE).withArguments(args).build(); |
---|
14.3.3 参考設定コード
| @Configuration
public class RabbitConfig { //スイッチの名前は文字列です public static Final String EXCHANGE = "exchange"; //キューの名前は文字列です public staticfinal String QUEUE = "queue"; //定義ルーティング キー public static Final String INFO = "info"; //---------------------------------- - -------- //取引所の名前は文字列です public static Final String EXCHANGE_ALTERNATE = “exchange.alternate”; //キューの名前は文字列です public static Final String QUEUE_ALTERNATE = “queue.alternate” "; //定義されたルーティング キー public static Final String ALTERNATE = "alternate"; @Bean public DirectExchange directExchange() {
Map<String, Object> argument = new HashMap<>();
argument.put(“alternate-exchange”, EXCHANGE_ALTERNATE); //現在の通常のスイッチのバックアップ スイッチを指定します
//DirectExchange(String name, boolean resistance , boolean autoDelete, Map<String, Object> argument)
return new DirectExchange(EXCHANGE, true, false, argument);
}
/**
* キューを宣言します
*
* @return
/
@Bean
public Queue queue() { return QueueBuilder.durable ( QUEUE).build(); } /
*
* @Qualifier 修飾された Bean の名前は directExchange の Bean です
*
* @param directExchange
* @return
/
@Bean
public Binding binding(DirectExchange directExchange, Queue queue) { return BindingBuilder.bind(queue).to(directExchange).with(INFO); } //------------------------------------------------------ /
*
* 备用交机必要Fanout交换机;
*
* @return
*/
@Bean
public FanoutExchange alterExchange() { //DirectExchange(String name, boolean resistance, boolean autoDelete, Map<String, Object> argument) return new FanoutExchange(EXCHANGE_ALTERNATE, true, false); @Bean パブリックキューalternateQueue() {
return QueueBuilder.durable(QUEUE_ALTERNATE).build();
@Bean public Binding alterBnding(FanoutExchange alterExchange, Queue alterQueue) { return BindingBuilder.bind(alternateQueue).to(alternateExchange)
; } } | | — |
14.3.4 送信メッセージコードを参照
| @Service
public class MessageService { @Resource private RabbitTemplate RabbitTemplate; /** * メッセージを送信 */ public void sendMessage() { //通常のスイッチにはバックアップ スイッチがあるため、意図的に間違ったルーティング キーを書き込みます。スタンバイ スイッチに入ります//スタンバイ キューに入るには、スタンバイ キューのメッセージを受信するプログラムを作成し、受信後に対応するように関連担当者に通知できます//通常のスイッチにスタンバイがない場合スイッチを切り替えると、メッセージは破棄されます。 RabbitTemplate.convertAndSend(RabbitConfig.EXCHANGE, "info1223", "hello"); System.out.println("メッセージは送信されました..."); } } | | — |
15. RabbitMQ キューの詳細プロパティ
15.1 特定のパラメータ
タイプ: キューのタイプ
名前: キュー名、文字列、任意の文字列が問題ありません;
持続性: キューが永続的であるかどうかを宣言し、サーバーの再起動後にキューがまだ存在するかどうかを示します;
自動削除: true の場合、自動的に削除するかどうか、このキューにコンシューマーが接続されていない場合、キューは自動的に削除されます。排他的:
排他的属性を持つキューは、初めて宣言した接続にのみ表示され、接続が切断されると自動的に削除されます。
基本的には、設定しないで false に設定してください
引数 : DLX の指定 (デッドレター交換など) など、キューのその他の属性;
1. x-expires: 数値
指定された時間内にキュー (キュー) にアクセスしなかった場合、キューは自動的に削除されます;
2. x-message-ttl : Number によって発行されたメッセージがキューに存在してからキャンセルされるまでの時間
(ミリ秒単位);
3. x-overflow: 文字列は
キューのオーバーフロー動作を設定します。キューの最大長に達したときにメッセージはどうなるか、有効な値は Drop Head Or Reject Publish です;
4. x-max-length:
Number キューが収容できるメッセージの最大長。長さを超えると、Redis の LRU アルゴリズムと同様に、新しいメッセージがフロント メッセージを上書きします;
5. x-single -active-consumer: デフォルトは false で、
単一のコンシューマをアクティブ化します。つまり、キューには 1 つのコンシューマのみを含めることができます。メッセージを消費するメッセージャー;
6. x-max-length-bytes: 数値
キューの最大占有スペースを制限し、それを超える場合は Redis と同様の LRU アルゴリズムを使用します;
7. x-dead-letter-exchange:
キューに関連付けられたデッド レター交換を文字列で指定します。メッセージが上限に達した場合、メッセージは削除されませんが、別のキューに保存されます。
8.x-dead-letter-routing-key:
デッド レター スイッチのルーティング キーを文字列で指定します。通常は 6 と一緒に定義されます。 ;
9.x- max-priority: Number
キューに優先度パラメータを追加すると、そのキューは優先キューになります;
(1)、キューに優先度パラメータを追加して優先キューにします
x-max-priority =10【0~255の値の範囲】
(2) メッセージに優先度属性を追加する
優先度機能により、キューをキューに入れて消費することができます。
| MessageProperties messageProperties=new MessageProperties();
messageProperties.setPriority(8); |
---|
10. x-queue-mode: 文字列 (理解できます)
キュー タイプ x-queue-mode=lazy 遅延キュー、RAM 使用量を減らすためにディスク上にできるだけ多くのメッセージを保持します。設定されていない場合、キューはメモリ キャッシュを予約します。できるだけ早くメッセージを配信するため;
11. x-queue-master-locator: 文字列 (言うまでもなく、あまり使用されません)
クラスター モードでキューに割り当てられたマスター ノードの位置情報を設定します;
各キューにはマスター ノードがあります。キュー上のすべての操作は事前にマスター上で完了し、その後、同じ操作がスレーブ上で実行されます。
異なるキューはそれぞれ異なるクラスター ノードに配置でき、これらのキューがミラー キューで構成されている場合、キューは 1 つになります。マスターと複数のスレーブ。
基本的にすべての操作はマスター上で行われるため、これらのキューのマスターが個々のサービス ノード上にあり、他のノードがアイドル状態である場合、負荷分散が達成できず、必然的にパフォーマンスに影響が生じます。マスターについては、キュー ホストに関するいくつかの戦略があります
。キューを宣言するときに x-queue-master-locator パラメータを使用するか、ポリシーで queue-master-locator を設定するか、rabbitmq 構成ファイルで直接 queue_master_locator を定義できます。 3 つのオプションがあります。 代替戦略: (
1 ) min-masters: マスターキューの数が最も少ないサービスノードホストを選択します; (
2) client-local: クライアントに接続されているサービスノードホストを選択します;
(3) randman: ランダムに割り当てます。
15.2 リファレンスコード
|
@Configuration
public class RabbitConfig { public static Final String EXCHANGE = “exchange”; public static Final String QUEUE = “キュー”; public static Final String KEY = “情報”; QueueBuilder ビルダー。 @Bean public DirectExchange directExchange() { return ExchangeBuilder.directExchange(EXCHANGE).build(); } @Bean public Queue queue() { Map<String, Object> 引数 = new HashMap<>(); //arguments.put(“x-expires”, 5000); //arguments.put(“x-max-length”, 5); //arguments.put(“x-overflow”, “reject-publish”);
argument.put(“x-single-active-consumer”, false); //TODO ???
//arguments.put(“x-max-length-bytes”, 20); // 単位はバイトです
// 引数.put("x-max-priority", 10); // 0-255 //現在宣言されているキューが優先キューとして設定されていることを示し、このキューではメッセージをキューに入れることができます //キューを遅延モードに設定し
ます、RAM メモリの使用量を減らすためにディスク上にできるだけ多くのメッセージを保持します。設定されていない場合、キューはメモリ キャッシュを保持してメッセージをできるだけ速く配信します。 // この種のキューを遅延キューと呼ぶこともあります
/
/ argument.put("x-queue-mode", "lazy");
//キューのバージョンを設定します。デフォルトはバージョン 1 です。
// バージョン 1 には、小さなメッセージが埋め込まれたログベースのインデックスがあります。
// バージョン 2 には、多くのシナリオでメモリ使用量とパフォーマンスが向上する異なるインデックスがあり、以前に埋め込まれたメッセージ用のキューごとのストレージが提供されます。
//arguments.put(“x-queue-version”, 2);
// x-queue-master-locator: クラスタモードのミラーキューのマスターノード情報を設定します。
//arguments.put("x-queue-master-locator", QueueBuilder.LeaderLocator.clientLocal.getValue());
//--------------------------
//arguments.put("x-expires", 10000); //自動有効期限、10 秒
/ /arguments.put("x-message-ttl", 10000); //自動有効期限、10 秒、キューは削除されません
//QueueBuilder クラスには定義があり、キューの最大長に達した場合のキューのオーバーフロー動作を設定しますに到達すると、メッセージは次のようになります。有効な値は、drop-head、reject-publish です。
//arguments.put("x-max-length", 5);
//arguments.put("x-overflow", QueueBuilder.Overflow.dropHead.getValue( ));
//キューが単一のアクティブなコンシューマであるかどうかを示します。true の場合、登録されたコンシューマ グループ内のメッセージを 1 つのコンシューマのみが消費し、他のコンシューマは無視されます。false の場合、メッセージは循環されます。すべてのコンシューマに (デフォルトは false) //arguments
. put("x-single-active-consumer", true);
// x-max-length-bytes、キュー メッセージの内容が最大スペースを占有し、メモリ サイズによって制限されます、しきい値を超えた場合、メッセージはキューの先頭から削除されます;
//arguments.put("x-max-length-bytes", 10);
//パラメータは 1 ~ 255 の正の整数で、キューがサポートする最大の優先度を示します。数値が大きいほど、優先度が高くなります。優先度フィールドが設定されていない場合、優先度フィールドの値はデフォルトで 0 になります。 ; 優先キューの priority 属性が x-max-priority より大きく設定されている場合、priority の値は x-max-priority の値に設定されます。
//arguments.put("x-max-priority", 10);
//キューを遅延モードに設定し、できるだけ多くのメッセージをディスク上に保持して RAM の使用量を削減します。設定されていない場合、キューはメモリを予約します。メッセージをできるだけ早く配信します;
//arguments.put("x-queue-mode", "lazy");
argument.put("x-queue-version", 2);
// x-queue-master -locator : クラスタモードのミラーキューのマスターノード情報を設定します。
argument.put(“x-queue-master-locator”, QueueBuilder.LeaderLocator.clientLocal.getValue());
//---------------------- ----------------------
// Queue(文字列名、ブール型永続的、ブール型排他的、ブール型 autoDelete、@Nullable Map<String, Object> 引数)
新しいキューを返します(QUEUE、true、false、false、引数); @Bean public Binding binding(DirectExchange directExchange,
Queue queue) { return BindingBuilder.bind(queue).to(directExchange).with(KEY); } } | | — |
耐久性パラメータを試して、rabbitmq-server を再起動すると、キューが失われます。
自動削除パラメータを試してください: レシーバを追加すると、サービスが停止していることがわかります。非常に長い間コンシューマが存在しない場合、キューは自動的に削除されます
16. メッセージの信頼性の高い配信
メッセージを確実に配信するには、メッセージ配信プロセス内のすべてのリンクが確実に成功するようにする必要があるため、これによりパフォーマンスがある程度犠牲になることは間違いなく、ビジネスのリアルタイム一貫性要件が厳しい場合には、パフォーマンスと信頼性を同時に達成することはできません。それほど高くはありませんが、
パフォーマンスのために信頼性をある程度犠牲にすることもできます。
① メッセージがプロデューサーから Exchange に送信されることを表します。②
メッセージが Exchange からキューにルーティングされることを表します。③
メッセージがキューに格納されることを表します。④
コンシューマーがキューをリッスンして消費することを表します。メッセージ; 1.
メッセージが RabbitMQ サーバーのスイッチに送信されていることを確認します。。 2 つの解決策: 1 つ目は、確認 (確認) モードを有効にすることです; (非同期) 2 つ目は、トランザクション モードを有効にすることです; (パフォーマンスが低く、実際のプロジェクトではほとんど使用されません) 2. メッセージが正しいキューにルーティングされていることを確認します。 . ②の失敗は、ルーティングキーワードが間違っているか、キューが存在しないか、キュー名が間違っている可能性があります。リターン モードを使用すると、メッセージをルーティングできない場合にプロデューサーに戻ることができます。もちろん、実際の運用環境ではこのような問題は発生せず、厳密なテストを行った後にオンラインになります (このような問題が発生することはほとんどありません)。 ;別の 1 つ目の方法は、代替交換を使用することです。ルーティングできないメッセージは、この代替交換に送信されます。 3. メッセージがキューに正しく保存されていることを確認します。システムのダウンタイム、再起動、シャットダウン、 etc. メッセージが失われる、つまり③に問題がある;解決策: (1)、キューの永続化
コード:
キュービルダー。耐久性のある( QUEUE ).build(); |
---|
(2)、スイッチ永続化
コード:
Exchangeビルダー。directExchange ( EXCHANGE ).durable( true ).build(); |
---|
(3)、メッセージ永続性
コード:
デフォルトの永続性
| MessageProperties messageProperties = new MessageProperties();
//メッセージの永続性を設定します。もちろん、デフォルトで永続的であるため、設定する必要はありません。ソース コードを表示できます。
messageProperties.setdeliveryMode(MessagedeliveryMode.PERSISTENT); |
---|
(4) クラスター、ミラーリングされたキュー、高可用性
(5) メッセージがキューからコンシューマーに正しく配信されることを確認します。
メッセージの消費中に手動の ACK 確認メカニズムを使用して、
コンシューマーがメッセージを受信し、時間内にメッセージを処理できない場合に、例外が発生するか、処理中に例外が発生し、④が失敗します。
メッセージがキューからコンシューマに確実に届くようにするために、RabbitMQ はメッセージ確認メカニズム (メッセージ確認) を提供します; #
手動確認メッセージ消費確認を有効にする
spring.rabbitmq.listener.simple.acknowledge-mode=manual
コンシューマがキューにサブスクライブするとき上記の設定は自動的に確認されませんが、手動確認を使用します。RabbitMQ は、キューからメッセージを削除する前に、コンシューマが確認信号に明示的に応答するのを待ちます。メッセージの消費が失敗した場合は、basicReject() を呼び出すこともできます
。または、basicNack() を使用して、確認ではなく現在のメッセージを拒否します。requeue パラメータが true に設定されている場合、このメッセージはキューに再格納され、次のコンシューマに送信されます (もちろん、コンシューマが 1 つしかない場合、このメソッドは無限ループの繰り返し消費を引き起こす可能性があります)。新しいキューに追加するか、例外ログを出力するだけです)。
17. メッセージの冪等性
メッセージ消費時の冪等性(メッセージは繰り返し消費されない)
。同じメッセージを初めて受信すると、業務は正常に処理される。メッセージを2回目に受信すると、業務はそれ以上処理できなくなり、それ以外の場合は処理が中断される。等価性とは: リソースの場合、リクエストが 1 回でも複数回でも、リソース自体への影響は同じである必要があり、リクエストの繰り返しによってリソースが繰り返し影響を受けることはありません。インターフェイス
の冪等性を例に挙げます
。
冪等性とは、ビジネス エラーを引き起こすことなく、同じパラメータを使用してインターフェイスが繰り返し呼び出される場合、このインターフェイスは冪等であることを意味します。登録インターフェイス、
SMS
確認コードの送信インターフェイス、
たとえば、同じ注文に対して 2 回支払いますが、差し引かれるのは 1 回の支払いだけです。 、2 回目の支払いは差し引かれません。これは、この支払いインターフェイスが冪等であることを示しています。
メッセージが繰り返し消費される問題を回避するにはどうすればよいですか? (メッセージ消費中の冪等性)
グローバルに一意な ID +
Redis プロデューサーがメッセージを送信するとき、メッセージごとにグローバルに一意な messageId を設定します。コンシューマーがメッセージを取得した後、setnx コマンドを使用して、redis に messageId をキーとして配置します。 中間: setnx(messageId 、1)、1 が返された場合は、以前に消費されておらず、正常に消費されたことを意味します。0 が返された場合、このメッセージは以前に消費されたことがあり、破棄されたことを意味します。特定のコードは次のことを指します。次のコード; 参照
コード
:
| //1. メッセージの一意の ID を redis に書き込みます
boolean flag = stringRedisTemplate.opsForValue().setIfAbsent(“idempotent:” +orders.getId(), String.valueOf(orders.getId())); // If キーが redis に存在しない場合は設定し、存在する場合は設定しない
if (flag) { //キーは存在せず、true を返します
//最初にこのメッセージを消費するのと同等ですtime
//TODO 処理業務
System.out.println("通常の業務処理..." +orders.getId());
}
| |
— |