Résumé de deux méthodes de mise en œuvre de la file d'attente rabbitmq

ps: Delay queue dans l'article = Delay queue

Qu'est-ce qu'une file d'attente à retard

L’objet stocké dans la file d’attente de retard doit être le message retardé correspondant. Le «message retardé» signifie que lorsque le message est envoyé, le consommateur ne souhaite pas recevoir le message immédiatement, mais attend pendant un certain temps avant que le consommateur ne l’obtienne. Le message est consommé.

Scénario 1: dans le système de commande, un utilisateur dispose généralement de 30 minutes pour payer après avoir passé une commande. Si le paiement échoue dans les 30 minutes, la commande sera traitée. Cela permet d'utiliser la file d'attente différée pour envoyer des informations de commande à la file d'attente différée.

Scénario 2: l'utilisateur souhaite contrôler à distance le périphérique intelligent à la maison via un téléphone mobile pour qu'il fonctionne à une heure spécifiée. À ce moment, l'instruction utilisateur peut être envoyée à la file d'attente de retard, et l'instruction sera poussée vers le dispositif intelligent lorsque le temps défini par l'instruction est écoulé.


Comment RabbitMQ implémente la file d'attente tardive

première méthode

Le protocole AMQP et la file d'attente RabbitMQ elle-même ne prennent pas directement en charge la fonction de file d'attente de retard, mais la fonction de la file d'attente de retard peut être simulée par les fonctionnalités suivantes.
Mais nous pouvons utiliser les deux caractéristiques de RabbitMQ pour courber la file d'attente de retard:

RabbitMQ peut définir x-expires pour Queue ou x-message-ttl pour Message pour contrôler la durée de vie du message. 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)

RabbitMQ dispose de deux méthodes pour définir le délai d'expiration des messages dans la file d'attente.

  • R: Grâce au paramètre de propriété de file d'attente, tous les messages de la file d'attente ont le même délai d'expiration.
  • B: Réglez le message individuellement, le TTL de chaque message peut être différent.

S'il est utilisé en même temps, le délai d'expiration du message est basé sur le plus petit TTL entre les deux. Une fois que la durée de vie d'un message dans la file d'attente dépasse la valeur TTL définie, il devient une lettre morte

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 transmise à celle spécifiée 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 une autre clé d'échange ou de routage à l'aide de la fonctionnalité DLX, et le message peut être à nouveau consommé.

Méthode de réglage:

Étape 1: définissez TTL pour générer des lettres mortes. Il existe deux méthodes: TTL par message et TTL de file d'attente. La première peut définir une heure d'expiration pour chaque message, qui est utilisée dans la plupart des scénarios, et la seconde définit l'heure d'expiration des files d'attente et s'applique. Pour les tâches différées ponctuelles

Il existe d'autres moyens de générer des lettres mortes, comme les consommateurs qui refusent de consommer basic.reject ou basic.nack (à condition que l'attribut du consommateur requeue = false)

  • TTL par message (définir une heure d'expiration pour chaque message) ( document officiel )

Le client java envoie un message à la file d'attente qui ne peut rester que 60 secondes:

byte[] messageBodyBytes = "Hello, world!".getBytes();
AMQP.BasicProperties properties = new AMQP.BasicProperties();
properties.setExpiration("60000");//设置消息的过期时间为60秒
channel.basicPublish("my-exchange", "routing-key", properties, messageBodyBytes);
//这条消息发送到相应的队列之后,如果60秒内没有被消费,则变为死信
  • Queue TTL (définir une heure d'expiration pour toute la file d'attente)

Créer une file d'attente, le délai d'expiration du message de la file d'attente est de 30 minutes (la file d'attente sera supprimée s'il n'y a pas de message de consommation consommateur dans les 30 minutes, et le message dans la file d'attente deviendra lettre morte après suppression)

java client方式:

Map<String, Object> args = new HashMap<String, Object>();
args.put("x-expires", 1800000);
channel.queueDeclare("myqueue", false, false, false, args);

rabbitmqctl命令方式(.* 为所有队列, 可以替换为指定队列):
rabbitmqctl set_policy expiry ".*" '{"expires":1800000}' --apply-to queues

rabbitmqctl (Windows):
rabbitmqctl set_policy expiry ".*" "{""expires"":1800000}" --apply-to queues

Étape 2: Définissez les règles de transfert pour les lettres mortes (s'il n'y a pas de règles, supprimez directement les lettres mortes)

Java Client方式:
//声明一个直连模式的exchange
channel.exchangeDeclare("some.exchange.name", "direct");
//声明一个队列,当myqueue队列中有死信产生时,会转发到交换器some.exchange.name
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-dead-letter-exchange", "some.exchange.name");

//如果设置死信会以路由键some-routing-key转发到some.exchange.name,如果没设默认为消息发送到本队列时用的routing key
//args.put("x-dead-letter-routing-key", "some-routing-key");
channel.queueDeclare("myqueue", false, false, false, args);

命令行方式(.* 为所有队列, 可以替换为指定队列):
设置 "dead-letter-exchange"
rabbitmqctl:
rabbitmqctl set_policy DLX ".*" '{"dead-letter-exchange":"my-dlx"}' --apply-to queues
rabbitmqctl (Windows):
rabbitmqctl set_policy DLX ".*" "{""dead-letter-exchange"":""my-dlx""}" --apply-to queues
设置 "dead-letter-routing-key"
rabbitmqctl:
rabbitmqctl set_policy DLX ".*" '{ "dead-letter-routing-key":"my-routing-key"}' --apply-to queues
rabbitmqctl (Windows):
rabbitmqctl set_policy DLX ".*" "{""dead-letter-routing-key"":""my-routing-key""}" --apply-to queues

Deuxième méthode

Dans rabbitmq 3.5.7 et supérieur, un plug-in (rabbitmq-delay-message-exchange) est fourni pour implémenter 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 du code source du plug-in:
https://github.com/rabbitmq/rabbitmq-delayed-message-exchange

Lien de téléchargement du plug-in:
https://bintray.com/rabbitmq/community-plugins/rabbitmq_delayed_message_exchange

installation:

Entrez dans le répertoire d'installation du plug-in
{rabbitmq-server} / plugins / (vous pouvez vérifier les plug-ins existants) pour
télécharger le plug-in
rabbitmq_delayed_message_exchange

wget https://bintray.com/rabbitmq/community-plugins/download_file?file_path=rabbitmq_delayed_message_exchange-0.0.1.ez
  • 1

(Si le nom du fichier téléchargé est irrégulier, renommez-le manuellement, par exemple
rabbitmq_delayed_message_exchange-0.0.1.ez)

Activer le plugin

rabbitmq-plugins enable rabbitmq_delayed_message_exchange

(关闭插件)
rabbitmq-plugins disable rabbitmq_delayed_message_exchange

 Utilisation du plug-in

Utilisez la fonction de messagerie retardée en déclarant un échange de type
x-message-retardé. X-message-retardé est un type fourni par le plugin, pas rabbitmq lui-même

// ... elided code ...
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-delayed-type", "direct");
channel.exchangeDeclare("my-exchange", "x-delayed-message", true, false, args);
// ... more code ...

Lors de l'envoi d'un message, ajoutez le paramètre "x-delay" à l'en-tête pour contrôler le temps de retard du message

// ... elided code ...
byte[] messageBodyBytes = "delayed payload".getBytes("UTF-8");
Map<String, Object> headers = new HashMap<String, Object>();
headers.put("x-delay", 5000);
AMQP.BasicProperties.Builder props = new AMQP.BasicProperties.Builder().headers(headers);
channel.basicPublish("my-exchange", "", props.build(), messageBodyBytes);
// ... more code ...

Exemple d'utilisation:

Expéditeur du message:

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

public class Send {
	// 队列名称
	private final static String EXCHANGE_NAME="delay_exchange";
	private final static String ROUTING_KEY="key_delay";

	@SuppressWarnings("deprecation")
	public static void main(String[] argv) throws Exception {
		/**
		 * 创建连接连接到MabbitMQ
		 */
		ConnectionFactory factory = new ConnectionFactory();
		factory.setHost("192.168.12.190");
		factory.setUsername("admin");
		factory.setPassword("admin");
		Connection connection = factory.newConnection();
		Channel channel = connection.createChannel();

		SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

		// 声明x-delayed-type类型的exchange
		Map<String, Object> args = new HashMap<String, Object>();
		args.put("x-delayed-type", "direct");
		channel.exchangeDeclare(EXCHANGE_NAME, "x-delayed-message", true,
				false, args);


		Map<String, Object> headers = new HashMap<String, Object>();
		//设置在2016/11/04,16:45:12向消费端推送本条消息
		Date now = new Date();
		Date timeToPublish = new Date("2016/11/04,16:45:12");

		String readyToPushContent = "publish at " + sf.format(now)
				+ " \t deliver at " + sf.format(timeToPublish);

		headers.put("x-delay", timeToPublish.getTime() - now.getTime());

		AMQP.BasicProperties.Builder props = new AMQP.BasicProperties.Builder()
				.headers(headers);
		channel.basicPublish(EXCHANGE_NAME, ROUTING_KEY, props.build(),
				readyToPushContent.getBytes());

		// 关闭频道和连接
		channel.close();
		connection.close();
	}
}

Destinataire du message:

import java.text.SimpleDateFormat;
import java.util.Date;

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.QueueingConsumer;

public class Recv {

	// 队列名称
	private final static String QUEUE_NAME = "delay_queue";
	private final static String EXCHANGE_NAME="delay_exchange";

	public static void main(String[] argv) throws Exception,
			java.lang.InterruptedException {
		ConnectionFactory factory = new ConnectionFactory();
		factory.setHost("192.168.12.190");
		factory.setUsername("admin");
		factory.setPassword("admin");
		Connection connection = factory.newConnection();
		Channel channel = connection.createChannel();

		QueueingConsumer queueingConsumer = new QueueingConsumer(channel);

		channel.queueDeclare(QUEUE_NAME, true,false,false,null);
		channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, "");
		channel.basicConsume(QUEUE_NAME, true, queueingConsumer);
		SimpleDateFormat sf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
		try {
			System.out.println("****************WAIT***************");
			while(true){
				QueueingConsumer.Delivery delivery = queueingConsumer
						.nextDelivery(); //

				String message = (new String(delivery.getBody()));
				System.out.println("message:"+message);
				System.out.println("now:\t"+sf.format(new Date()));
			}

		} catch (Exception exception) {
			exception.printStackTrace();

		}

	}
}

Démarrez la fin de la réception et démarrez la fin de l'envoi.
Résultat de l'opération:

****************WAIT***************
message:publish at 2016-11-04 16:44:16.887 	 deliver at 2016-11-04 16:45:12.000
now:	2016-11-04 16:45:12.023

 Le résultat montre que nous avons reçu le message le 2016-11-04 16: 45: 12.023, et qu'il y a un délai de 23 millisecondes à partir du moment où nous avons défini 2016-11-04 16: 45: 12.023

Remarque: 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.

Remarque: Lors de l'utilisation, il a été découvert que lorsqu'un nœud de RAM avec le plug-in rabbitmq-delay-message-exchange est activé, il ne peut pas être démarré lorsqu'il est redémarré. En vérifiant le journal, une exception Timeout a été trouvée. Le développeur a expliqué qu'il s'agissait du nœud pendant le processus de démarrage. La synchronisation des données liées au cluster entraîne l'expiration du délai de démarrage et il est recommandé de ne pas utiliser de nœuds Ram

插件 开发 者: les
nœuds de RAM commencent vides et ont besoin d'un nœud de disque pour synchroniser les tables. Dans ce cas, il expire.

Plus important encore, vous n'avez pas besoin de nœuds RAM. Si vous n'êtes pas sûr de le faire, vous ne le faites certainement pas, pas plus que 99% des utilisateurs.

 

Je suppose que tu aimes

Origine blog.csdn.net/zhangkaixuan456/article/details/109100281
conseillé
Classement