rabbitmq遅延キューの2つの実装方法の要約

ps:記事の遅延キュー=遅延キュー

遅延キューとは

遅延キューに格納されているオブジェクトは、対応する遅延メッセージである必要があります。いわゆる「遅延メッセージ」とは、メッセージが送信されたときに、消費者がメッセージをすぐに取得したくないが、指定された時間待機してから、これを取得することを意味します。メッセージは消費されます。

シナリオ1:注文システムでは、ユーザーは通常、注文後30分以内に支払う必要があります。30分以内に支払いが成功しなかった場合、注文は処理されます。これは、遅延キューを使用して注文情報を遅延キューに送信するためのものです。

シナリオ2:ユーザーは、自宅のスマートデバイスを携帯電話でリモート制御して、指定した時間に作業したいと考えています。このとき、ユーザー命令を遅延キューに送信することができ、命令で設定された時間が経過すると、命令はスマートデバイスにプッシュされます。


RabbitMQがレイトキューを実装する方法

方法1

AMQPプロトコルとRabbitMQキュー自体は、遅延キュー機能を直接サポートしていませんが、遅延キューの機能は、次の機能によってシミュレートできます。
ただし、RabbitMQの2つの特性を使用して、遅延キューをカーブさせることができます。

RabbitMQは、キューのx-expiresまたはメッセージのx-message-ttlを設定して、メッセージの存続期間を制御できます。タイムアウトすると(2つが同時に設定され、最初の有効期限が優先されます)、メッセージはデッドレターになります(デッドレター)

RabbitMQには、キュー内のメッセージの有効期限を設定する2つの方法があります。

  • A:キューのプロパティ設定により、キュー内のすべてのメッセージの有効期限は同じになります。
  • B:メッセージを個別に設定します。各メッセージのTTLは異なる場合があります。

同時に使用する場合、メッセージの有効期限は、2つの間の小さいTTLに基づきます。キュー内のメッセージの有効期間が設定されたTTL値を超えると、デッドレターになります

RabbitMQのキューは、x-dead-letter-exchangeとx-dead-letter-routing-key(オプション)の2つのパラメーターを使用して構成できます。デッドレターがキューに表示されると、これら2つのパラメーターに従って再ルーティングされ、指定されたものに転送されます。キュー。

  • x-dead-letter-exchange:デッドレターが表示された後、指定されたエクスチェンジにデッドレターを再送信します
  • x-dead-letter-routing-key:デッドレターが表示された後、指定されたルーティングキーに従ってデッドレターが再送信されます

キュー内のデッドレターには次のものが含まれます。

  • メッセージまたはキューのTTLが期限切れになりました
  • キューが最大長に達する
  • メッセージはコンシューマー(basic.rejectまたはbasic.nack)によって拒否され、requeue = false

上記の2つの機能を組み合わせて、TTLルールを設定した後、メッセージがキュー内のデッドレターになった場合、DLX機能を使用して別のExchangeまたはルーティングキーに再転送し、メッセージを再度使用できます。

設定方法:

ステップ1:デッドレターを生成するようにTTLを設定します。メッセージごとのTTLとキューTTLの2つの方法があります。1つ目は各メッセージの有効期限を設定でき、ほとんどのシナリオで使用できます。2つ目は、キューの有効期限を設定して適用する方法です。 1回限りの遅延タスクの場合

basic.rejectまたはbasic.nackの消費を拒否する消費者など、デッドレターを生成する方法は他にもあります(消費者の属性requeue = falseの場合)

Javaクライアントは、60秒間しか留まらないメッセージをキューに送信します。

byte[] messageBodyBytes = "Hello, world!".getBytes();
AMQP.BasicProperties properties = new AMQP.BasicProperties();
properties.setExpiration("60000");//设置消息的过期时间为60秒
channel.basicPublish("my-exchange", "routing-key", properties, messageBodyBytes);
//这条消息发送到相应的队列之后,如果60秒内没有被消费,则变为死信
  • キューTTL(キュー全体の有効期限を設定)

キューを作成します。キューのメッセージ有効期限は30分です(30分以内に消費者消費メッセージがない場合、キューは削除され、キュー内のメッセージは削除後にデッドレターになります)

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

ステップ2:デッドレターの転送ルールを設定します(ルールがない場合は、デッドレターを直接破棄します)

  • デッドレターエクスチェンジの設定方法(公式文書
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

方法2

Rabbitmq 3.5.7以降は、遅延キュー機能を実装するためのプラグイン(rabbitmq-delayed-message-exchange)を提供します。同時に、プラグインはErlang / OPT18.0以降に依存しています。

プラグインのソースコードアドレス:https
//github.com/rabbitmq/rabbitmq-delayed-message-exchange

プラグインのダウンロードリンク:https
//bintray.com/rabbitmq/community-plugins/rabbitmq_delayed_message_exchange

インストール:

プラグインのインストールディレクトリ
{rabbitmq-server} / plugins /(既存のプラグインを確認できます)を入力して
、プラグインダウンロードます
rabbitmq_delayed_message_exchange

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

(ダウンロードしたファイル名が不規則な場合は、
rabbitmq_delayed_message_exchange-0.0.1.ezのように手動で名前を変更します)

プラグインを有効にする

rabbitmq-plugins enable rabbitmq_delayed_message_exchange

(关闭插件)
rabbitmq-plugins disable rabbitmq_delayed_message_exchange

 プラグインの使用

タイプ
x-delayed-messageの交換を宣言して、遅延メッセージング機能を使用します。x-delayed-messageは、rabbitmq自体ではなく、プラグインによって提供されるタイプです。

// ... 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 ...

メッセージを送信するときは、ヘッダーに「x-delay」パラメーターを追加して、メッセージの遅延時間を制御します

// ... 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 ...

使用例:

メッセージ送信者:

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();
	}
}

メッセージ受信者:

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();

		}

	}
}

受信側を開始し、送信側を開始します。
操作結果:

****************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

 結果は、2016-11-04 16:45:12.023にメッセージを受信し、2016-11-04 16:45:12.023を設定した時間から23ミリ秒の遅延があることを示しています。

注:rabbitmq-delayed-message-exchangeプラグインを使用しているときにキューに送信されるメッセージの数は、Web管理インターフェイスに表示されない場合があり、通常の機能の使用には影響しません。

注:使用中に、rabbitmq-delayed-message-exchangeプラグインを備えたRAMノードを有効にすると、再起動時に起動できないことが発見されました。ログを確認すると、タイムアウト例外が見つかりました。開発者は、これが起動プロセス中のノードであると説明しました。クラスタ関連のデータを同期すると起動タイムアウトが発生するため、Ramノードを使用しないことをお勧めします

插件開プラグイン:
RAMノードは空白で始まり、テーブルを同期するためのディスクノードが必要です。この場合、タイムアウトになります。

さらに重要なことに、RAMノードは必要ありません。99%のユーザーがそうではないので、そうするかどうかわからない場合は、確かにそうしません。

 

おすすめ

転載: blog.csdn.net/zhangkaixuan456/article/details/109100281
おすすめ