Préface
Par exemple, lorsque nous utilisons mq, nous ne voulons pas recevoir le message immédiatement. Par exemple, nous pouvons interroger la commande après 3 minutes. À ce stade, nous devons utiliser le message différé pour envoyer.
Comment RabbitMQ implémente-t-il les files d'attente tardives?
Le protocole AMQP et la file d'attente RabbitMQ elle-même ne prennent pas directement en charge la fonction de file d'attente à retard. Mais nous pouvons utiliser les deux caractéristiques de RabbitMQ pour courber la file d'attente de retard:
特性 1 、Durée de vie (TTL)
1.RabbitMQ peut définir x-expires pour la file d'attente
2. Définissez x-message-ttl pour Message
Grâce à ces deux façons de contrôler la durée de vie du message
- S'il est défini par les propriétés de la file d'attente, tous les messages de la file d'attente ont le même délai d'expiration.
- Si les messages sont définis individuellement, le TTL de chaque message peut être différent.
- S'il expire (les deux sont définis en même temps, le premier délai d'expiration prévaudra), le message devient lettre morte (lettre morte)
特性 2 、Échanges de lettres mortes (DLX)
La file d'attente de RabbitMQ peut être configurée avec les deux paramètres x-dead-letter-exchange et x-dead-letter-routing-key (facultatif). Si une lettre morte apparaît dans la file d'attente, elle sera réacheminée et transférée vers le spécifié en fonction de ces deux paramètres. queue.
- x-dead-letter-exchange: renvoyer la lettre morte à l'échange désigné après l'apparition de la lettre morte
- x-dead-letter-routing-key: après l'apparition de la lettre morte, la lettre morte sera à nouveau envoyée selon la clé de routage spécifiée
La lettre morte dans la file d'attente comprend:
- Le TTL du message ou de la file d'attente a expiré
- La file d'attente atteint la longueur maximale
- Le message a été rejeté par le consommateur (basic.reject ou basic.nack) et requeue = false
En combinant les deux fonctionnalités ci-dessus, après avoir défini la règle TTL, lorsqu'un message devient lettre morte dans une file d'attente, il peut être retransmis vers un autre échange ou clé de routage à l'aide de la fonctionnalité DLX, et le message peut être à nouveau consommé.
première méthode:
/死信队列的应用//
/**
* DLX测试队列
*/
@Bean
public Queue DLXTestQueue() {
Map<String, Object> args = new HashMap<>(2);
args.put("x-dead-letter-exchange", "DL_exchange");
args.put("x-dead-letter-routing-key", "DL_queue");
return QueueBuilder.nonDurable("DLX-test-queue").withArguments(args).build();
}
@Bean
public Exchange DLXTestExchange() {
return ExchangeBuilder.directExchange("DLX-test-exchange").durable(true).build();
}
@Bean
public Binding DLXTestBinding() {
return new Binding("DLX-test-queue", Binding.DestinationType.QUEUE, "DLX-test-exchange", "DLX-test-queue", null);
}
///声明一个死信队列,交换机,绑定//
@Bean
public Queue dlQueue() {
return QueueBuilder.nonDurable("DL_queue").build();
}
@Bean
public Exchange dlExchange() {
return ExchangeBuilder.directExchange("DL_exchange").durable(true).build();
}
/**
* 死信路由通过 DL_queue 绑定键绑定到死信队列上.
*/
@Bean
public Binding deadLetterBinding() {
return new Binding("DL_queue", Binding.DestinationType.QUEUE, "DL_exchange", "DL_queue", null);
}
envoyer:
/**
* 测试死信队列
*/
@GetMapping("ttl")
public Resp testTTL() {
rabbitTemplate.convertAndSend("DLX-test-exchange", "DLX-test-queue", "去私信队列", messagePostProcessor -> {
messagePostProcessor.getMessageProperties().setExpiration("10000");
return messagePostProcessor;
});
return Resp.success("ok", null);
}
consommateur:
@RabbitListener(queues = {"DL_queue"})
public void DLXTestQueue(Message message, Channel channel) throws IOException {
log.info("死信队列 10s 后 消费消息 {}", new String(message.getBody()));
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
}
Méthode 2: Rabbitmq 3.5.7 et supérieur fournit un plug-in (rabbitmq-delay-message-exchange) pour réaliser la fonction de file d'attente retardée. Dans le même temps, le plugin dépend d'Erlang / OPT 18.0 et supérieur.
Adresse de téléchargement du plug-in: https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases , veuillez vous référer à mon dernier article pour plus de détails .
Configuration:
package com.zoo.mq.config;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;
/**
* @author: 谢飞
*/
@Configuration
public class RabbitMqConfig {
/**
* 定义延迟消息发送的队列.
*/
@Bean
public Queue delayQueue() {
return QueueBuilder.nonDurable("delay_queue").build();
}
/交换机/
/**
* 定义一个用于延迟消息发送的交换机
* 延时队列交换机 注意这里的交换机类型:CustomExchange
*/
@Bean
public CustomExchange delayExchange() {
Map<String, Object> args = new HashMap<>();
args.put("x-delayed-type", "direct");
return new CustomExchange("delay_exchange", "x-delayed-message", true, false, args);
}
绑定/
/**
* 给延时队列绑定交换机
*/
@Bean
public Binding redirectBinding() {
return BindingBuilder.bind(delayQueue()).to(delayExchange()).with("delay_key").noargs();
}
}
Producteur:
@GetMapping("sendTTL")
public Resp sendTTL() {
rabbitTemplate.convertAndSend("delay_exchange", "delay_key", "hello", messagePostProcessor -> {
messagePostProcessor.getMessageProperties().setDelay(10000);
return messagePostProcessor;
});
return Resp.success("ok", null);
}
consommateur:
@RabbitListener(queues = {"delay_queue"})
public void delayQueue(Message message, Channel channel) throws IOException {
log.info("delay_queue 10s 后 消费消息 {}", new String(message.getBody()));
}
Tester ok.
Le nombre de messages envoyés à la file d'attente lors de l'utilisation du plug-in rabbitmq-delay-message-exchange peut ne pas être visible dans l'interface de gestion Web et n'affecte pas l'utilisation normale des fonctions