この記事は、ttl+デッドレターキューを利用したRabbitMQを動作させるためにSpring Cloud Steamを利用して実装した遅延キューについての記事です。
序文
会社のプロジェクトでは、遅延キューの必要性が発生しました。将来の保守性とスケーラビリティの要件のために、mq の操作には Springcloud Stream コンポーネントを使用する必要があり、会社のウサギでは遅延プラグインのインストールが許可されておらず、ほとんどのプラグインのみがインストールされています。オリジナルの ttl+dead Letter を実現するために、構築の過程で多くの問題に遭遇し、最終的に正常に実装されました。以下のコードは、Spring Cloud Steam3.1 以降の関数型プログラミングを使用しています。
まず原理を広めましょう: プロデューサは通常のスイッチにメッセージを送信し、TTL 時間設定でキューをバインドします。このキューはデッドレター スイッチにバインドされており、誰もそれを消費しません。メッセージの有効期限が切れると、メッセージが送信されます。消費者はこのデッドレター キューを聞くだけで、遅延キューの効果が得られます。
yaml設定ファイル
function での定義は、関数名 (後で送受信メソッドの名前) を定義することです。
バインディングの xxx-in/out-0 は 3 つの部分に分かれています。最初の部分はメソッド名、2 番目の部分はプロデューサー出力またはコンシューマー入力を表す入力または出力の意味です。0 の 3 番目の部分は Rabbitmq で固定されており、kafkaf との互換性のために提供されています。0 と書きます。大丈夫。スイッチの名前は宛先に設定され、後ろの変数は環境の意味であり、その時点で dev、test、uat などになります。グループ group を設定する必要がありますが、ここではモジュールの名前とします。
キーポイント:次のプロデューサー: required-groups を構成する必要があります。これはグループ名です。
バインドされたスイッチが一番下でプロデューサー用に設定されたデッドレター スイッチである場合は、グループ名を忘れずに入力してください。入力しないと、グループ名は使用されません。
次の content-type はタイプです、指定できません、デフォルトはこれです
下は Rabbit の設定で、bingdings でプロデューサーの Bondi にデッドレター スイッチを設定し、プロデューサーが消費していない時間のデッドレターの ttl を設定しました。Dead-letter-exchange は指定されたスイッチの名前です。指定のために元のスイッチ名 _DLXに設定してから、デッド レター キューの名前を設定します。つまり、スイッチの背後にグループを追加します。これは上記のグループと一致している必要があります。
ここでのデッドレター キューからのメッセージはダイレクトであるため、コンシューマーはデッドレター キュー内で期限切れになったメッセージをリッスンすることになるため、スイッチ タイプも direct に設定する必要があります。そうしないと、ダイレクト メッセージ変換トピック例外が報告されます。例外は最初の A ニュース レポートでのみ発生し、次のニュースは聞こえません。springcloud ストリームの最下層がこれに対処するのに役立っている可能性がありますが、最初のエラー レポートを回避するには、次のことをお勧めします。スイッチの種類を設定します。
cloud:
function:
definition: memberAccountUpdateTaskDelayed;handleTaskDelayed;
stream:
bindings:
memberAccountUpdateTaskDelayed-out-0:
destination: MEMBER_TOPIC_${spring.profiles.active} #延迟exchange,交换模式是topic
content-type: application/json #设置消息的类型为json
group: ${spring.application.name}
producer:
required-groups: ${spring.application.name} #必须要制定生产者分组,不然发不过去
handleTaskDelayed-in-0:
destination: MEMBER_TOPIC_DLX_${spring.profiles.active}
content-type: application/json
group: ${spring.application.name}
rabbit:
bindings:
memberAccountUpdateTaskDelayed-out-0:
producer:
ttl: 10000 #延时队列的延时时间,单位毫秒
auto-bind-dlq: true #开启死信队列
dead-letter-exchange: MEMBER_TOPIC_DLX_${spring.profiles.active} #死信交换机
dead-letter-queueName: MEMBER_TOPIC_DLX_${spring.profiles.active}.${spring.application.name} #死信队列名称
handleTaskDelayed-in-0:
consumer:
exchange-type: direct #死信交换机必须是direct类型的才能接受
プロデューサーがメッセージを送る
ここでは、TaskDelayMessage で送信されるオブジェクトを送信しています。エンティティ クラスの属性に JSON 逆シリアル化アノテーションを忘れずに追加してください。追加しないと、コンシューマーはリッスン時に逆シリアル化エラーを報告します。
メソッド名は、構成ファイルで構成したメソッド名と同じである必要があります。
@Repository
@Slf4j
public class MemberAccountUpdateTaskHandleTimeoutTaskRepositoryImpl implements MemberAccountUpdateTaskHandleTimeoutTaskRepository {
private final Sinks.Many<Message<TaskDelayMessage>> sinks =
Sinks.many().multicast().onBackpressureBuffer();
@Bean
public Supplier<Flux<Message<TaskDelayMessage>>> memberAccountUpdateTaskDelayed(){
return sinks::asFlux;
}
@Override
public void sendDelayMessage(TaskDelayMessage message) {
log.info("生产者准备发送消息:{}", message+" -"+System.currentTimeMillis());
Message<TaskDelayMessage> msg = MessageBuilder.withPayload(message).build();
while (sinks.tryEmitNext(msg).isFailure()) {
LockSupport.parkNanos(10);
}
log.info("生产者成功发送消息:{}", message+" -"+System.currentTimeMillis());
}
}
消費者がメッセージを聞く
メソッド名は、構成ファイルで構成したメソッド名と同じである必要があります。
@Bean
Consumer<TaskDelayMessage> handleTaskDelayed() {
return message-> {
log.info("消费者监听到了消息:{}", message);
memberAccountUpdateTaskService.handleTimeOutTasks(message);
};
}
要約する
要約: 実は設定が面倒です。中国では springcloud steam に関するチュートリアルやブログが本当に少ないです。構築の過程で csdn とステーション b で多くの問題が発生し、解決策が見つかりませんでした。最後に、YouTube と springcloud の公式ドキュメントを読み、ソースコードを確認して解決しました。ストリームコンポーネントを学習したい場合は、YouTube にアクセスしてチュートリアルを読むか、springcloud 公式 Web サイトのドキュメントに直接アクセスすることをお勧めします。