简介
延迟队列存储的消息是不希望被消费者立刻拿到的,而是等待特定时间后,消费者才能拿到这个消息进行消费。使用场景比较多,例如订单限时30分钟内支付,否则取消,再如分布式环境中每隔一段时间重复执行某操作。
下面举一个简单的例子,例子大概意思是分别在首次发送消息后的10秒、40秒、100秒后重新读取到消息。为了直观,不使用RabbitMQ其他多余的特性。
准备工作
在Centos7下安装RabbitMQ,版本为3.6.12单机版本(非集群),IP是127.0.0.1,端口是15672,使用web管理页面或者rabbitmqctl提前准备好相关的用户、exchange和queue。
用户有producer(密码同用户名)、consumer(密码同用户名)。
Default exchange是RabbitMQ预定义的,名称为空字符串,自动绑定到每个queue,类型为direct,routingKey等于queue的名称。
三个死信交换器(队列中的消息过期后会被发送到该队列的死信交换器)10sDeadLetterExchange、30sDeadLetterExchange、60sDeadLetterExchange。
三个死信队列,10sDeadLetterQueue、30sDeadLetterQueue、60sDeadLetterQueue分别与三个死信交换器绑定。
三个队列,10sDelayQueue、30sDelayQueue、60sDelayQueue,分别设置过期时间为10秒、30秒、60秒,并设置对应的死信交换器。
示例
使用java代码创建一个生产者和三个消费者。生产者往Default exchange发送消息,routingKey为10sDelayQueue。三个消费者分别订阅三个死信队列。先启动三个消费者,再启动生产者。消费者会持续订阅死信队列,需要手动关闭连接。
RabbitMQ10sDeadLetterQueueConsumer消费者代码如下:
import com.rabbitmq.client.*;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeoutException;
public class RabbitMQ10sDeadLetterQueueConsumer {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setVirtualHost("/");
connectionFactory.setUsername("consumer");
connectionFactory.setPassword("consumer");
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(15672);
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
channel.basicQos(64);
channel.basicConsume("10sDeadLetterQueue", false, UUID.randomUUID().toString(),
new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("第一次重试时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
System.out.println("consumerTag:" + consumerTag);
System.out.println("envelope:" + envelope.toString());
System.out.println("basicProperties:" + properties.toString());
System.out.println("message:" + new String(body, "utf-8"));
channel.basicAck(envelope.getDeliveryTag(), false);
channel.basicPublish("", "30sDelayQueue",
new AMQP.BasicProperties().builder().deliveryMode(2).build(),
body);
}
});
}
}
RabbitMQ30sDeadLetterQueueConsumer消费者代码如下:
import com.rabbitmq.client.*;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeoutException;
public class RabbitMQ30sDeadLetterQueueConsumer {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setVirtualHost("/");
connectionFactory.setUsername("consumer");
connectionFactory.setPassword("consumer");
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(15672);
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
channel.basicQos(64);
channel.basicConsume("30sDeadLetterQueue", false, UUID.randomUUID().toString(),
new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("第二次重试时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
System.out.println("consumerTag:" + consumerTag);
System.out.println("envelope:" + envelope.toString());
System.out.println("basicProperties:" + properties.toString());
System.out.println("message:" + new String(body, "utf-8"));
channel.basicAck(envelope.getDeliveryTag(), false);
channel.basicPublish("", "60sDelayQueue",
new AMQP.BasicProperties().builder().deliveryMode(2).build(),
body);
}
});
}
}
RabbitMQ60sDeadLetterQueueConsumer消费者代码如下:
import com.rabbitmq.client.*;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeoutException;
public class RabbitMQ60sDeadLetterQueueConsumer {
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setVirtualHost("/");
connectionFactory.setUsername("consumer");
connectionFactory.setPassword("consumer");
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(15672);
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
channel.basicQos(64);
channel.basicConsume("60sDeadLetterQueue", false, UUID.randomUUID().toString(),
new DefaultConsumer(channel) {
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println("第三次重试时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
System.out.println("consumerTag:" + consumerTag);
System.out.println("envelope:" + envelope.toString());
System.out.println("basicProperties:" + properties.toString());
System.out.println("message:" + new String(body, "utf-8"));
channel.basicAck(envelope.getDeliveryTag(), false);
System.out.println("执行完成");
}
});
}
}
生产者代码如下:
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
import java.util.concurrent.TimeoutException;
public class RabbitMQDelayQueueProducer {
public static void main(String[] args) throws IOException, TimeoutException {
Connection connection = null;
Channel channel = null;
try {
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setVirtualHost("/");
connectionFactory.setUsername("producer");
connectionFactory.setPassword("producer");
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(15672);
connection = connectionFactory.newConnection();
channel = connection.createChannel();
channel.basicPublish("", "10sDelayQueue",
new AMQP.BasicProperties().builder().deliveryMode(2).build(),
("测试延迟队列" + UUID.randomUUID().toString()).getBytes("utf-8"));
System.out.println("发送时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
} finally {
if (channel != null) {
channel.close();
}
if (connection != null) {
connection.close();
}
}
}
}
生产者打印:
发送时间:2019-08-25 10:08:29
RabbitMQ10sDeadLetterQueueConsumer消费者打印:
第一次重试时间:2019-08-25 10:08:39
consumerTag:83787685-28a9-4ae8-b2bc-b89b90f14b68
envelope:Envelope(deliveryTag=1, redeliver=false, exchange=10sDeadLetterExchange, routingKey=10sDelayQueue)
basicProperties:#contentHeader<basic>(content-type=null, content-encoding=null, headers={x-death=[{reason=expired, count=1, exchange=, time=Sun Aug 25 10:08:37 CST 2019, routing-keys=[10sDelayQueue], queue=10sDelayQueue}]}, delivery-mode=2, priority=null, correlation-id=null, reply-to=null, expiration=null, message-id=null, timestamp=null, type=null, user-id=null, app-id=null, cluster-id=null)
message:测试延迟队列f862c616-a99a-4b65-9482-d74d5aee0814
RabbitMQ30sDeadLetterQueueConsumer消费者打印:
第二次重试时间:2019-08-25 10:09:09
consumerTag:27bb0e0e-07fe-49b6-8c0f-06fbc32cd784
envelope:Envelope(deliveryTag=1, redeliver=false, exchange=30sDeadLetterExchange, routingKey=30sDelayQueue)
basicProperties:#contentHeader<basic>(content-type=null, content-encoding=null, headers={x-death=[{reason=expired, count=1, exchange=, time=Sun Aug 25 10:09:07 CST 2019, routing-keys=[30sDelayQueue], queue=30sDelayQueue}]}, delivery-mode=2, priority=null, correlation-id=null, reply-to=null, expiration=null, message-id=null, timestamp=null, type=null, user-id=null, app-id=null, cluster-id=null)
message:测试延迟队列f862c616-a99a-4b65-9482-d74d5aee0814
RabbitMQ60sDeadLetterQueueConsumer消费者打印:
第三次重试时间:2019-08-25 10:10:09
consumerTag:8bfdc795-443d-4940-bf88-1e6f14e7b530
envelope:Envelope(deliveryTag=1, redeliver=false, exchange=60sDeadLetterExchange, routingKey=60sDelayQueue)
basicProperties:#contentHeader<basic>(content-type=null, content-encoding=null, headers={x-death=[{reason=expired, count=1, exchange=, time=Sun Aug 25 10:10:07 CST 2019, routing-keys=[60sDelayQueue], queue=60sDelayQueue}]}, delivery-mode=2, priority=null, correlation-id=null, reply-to=null, expiration=null, message-id=null, timestamp=null, type=null, user-id=null, app-id=null, cluster-id=null)
message:测试延迟队列f862c616-a99a-4b65-9482-d74d5aee0814
执行完成
- 基于RabbltMQ延迟插件实现延迟队列代码示例
上一篇文章写了docker安装RabbitMQ及延迟插件的安装,这篇的话是基于RabbitMQ延迟插件实现延迟队列的示例 那么废话不多说 直接上代码!! 首先创建延迟队列配置类 DelayedQueu ...
- 【转】MSMQ 微软消息队列 简单 示例
MSMQ它的实现原理是:消息的发送者把自己想要发送的信息放入一个容器中(我们称之为Message),然后把它保存至一个系统公用空间的消息队列(Message Queue)中:本地或者是异地的消息接收程 ...
- PHP静态延迟绑定简单示例
没怎么用过这个新特性,其实也不算新啦,试试吧,现在静态类的继承很方便了 <?php class A { protected static $def = '123456'; public stat ...
- 消息队列-一篇读懂rabbitmq(生命周期,confirm模式,延迟队列,集群)
什么是消息队列? 就是生产者生产一条消息,发送到这个rabbitmq,消费者连接rabbitmq并且进行消费,生产者和消费者并需要知道对方是如何工作的,从而实现程序之间的解耦,异步和削峰,这也就是消息 ...
- RabbitMQ 入门教程(PHP版) 延迟队列,延迟任务
延迟任务应用场景 场景一:物联网系统经常会遇到向终端下发命令,如果命令一段时间没有应答,就需要设置成超时. 场景二:订单下单之后30分钟后,如果用户没有付钱,则系统自动取消订单. 场景三:过1分钟给新 ...
- 如何用RabbitMQ实现延迟队列
前言 在 jdk 的 juc 工具包中,提供了一种延迟队列 DelayQueue.延迟队列用处非常广泛,比如我们最常见的场景就是在网购或者外卖平台中发起一个订单,如果不付款,一般 15 分钟后就会被关 ...
- RabbitMQ 延迟队列,消息延迟推送
目录 应用场景 消息延迟推送的实现 测试结果 应用场景 目前常见的应用软件都有消息的延迟推送的影子,应用也极为广泛,例如: 淘宝七天自动确认收货.在我们签收商品后,物流系统会在七天后延时发送一个消息给 ...
- Linux字符设备简单示例
1. Linux字符设备是一种按字节来访问的设备,字符驱动则负责驱动字符设备,这样的驱动通常实现open.close.read和write系统调用.例如:串口.Led.按键等. 2. 通过字符设备文件 ...
- AMQP消息队列之RabbitMQ简单示例
前面一篇文章讲了如何快速搭建一个ActiveMQ的示例程序,ActiveMQ是JMS的实现,那这篇文章就再看下另外一种消息队列AMQP的代表实现RabbitMQ的简单示例吧.在具体讲解之前,先通过一个 ...
随机推荐
- 国内几大seo高手(夫唯,王通,久久)的技术分析
http://www.wocaoseo.com/thread-146-1-1.html 目前学习seo的人越来越多了,这种技术的普及和推广也在不断的扩大,先进的好的培训机构不断涌现,很多高水平老师都在 ...
- 焦大:seo思维进化论(番外)
http://www.wocaoseo.com/thread-54-1-1.html 我已经在博客说了学seo研究算法是愚蠢的行为,但是很多人仍旧来问se的算法问题,其中最多的就是问TF-IDF算法, ...
- CentOS7系统使用rpm方式安装MySQL5.7
参考:https://blog.csdn.net/wudinaniya/article/details/81094578 1.首先去mysql官网下载rpm包,一个是server包一个是client包 ...
- source insight4提示结尾不一致。关闭
source insight4提示结尾不一致.关闭.世界清静了. Options -> Preferences ->Files 最后的Ask to fix inconsistent li ...
- Labview学习之路(五)按钮的机械动作
布尔类型中有一个按钮是非常重要的控件,他不是只是表示一个确定,输出0或1,下边我们共同探讨一下他的机械动作 单击时转换 释放时转换 保持转换直到释放 单击时触发 释放时触发 保持触发直到释放 单击时转 ...
- ES6--Array.prototype.fill 替换数组
Array.prototype.fill
- 使用Telnet服务测试端口时,提示没有Telnet服务
1.win7系统是默认不开启Telnet服务的,所以我们第一次使用时要手动开启Telnet服务 1)打开 控制面板 > 程序 > 程序功能 > 打开或关闭Windows功能,勾选上T ...
- 你不知道的JavaScript笔记----对象
对象: 1.定义对象属性 属性描述符(也称为:数据描述符) Object.defineProperty(Object,PropertyName,{ value: 6, writable: true, ...
- 12_进程,线程,协程,IO多路复用的区别
1.进程 1.进程可以使用计算机多核 2.进程是资源分配的单位 3.进程的创建要比线程消耗更多的资源效率很低 4.进程空间独立,数据安全性跟好操作有专门的进程间通信方式 5.一个进程可以包含多个线程, ...
- 15_Python的模块module
1.模块的概述 1.模块是Python程序架构的一个核心概念,每一个以.py结尾的Python源代码文件都是一个模块 2.模块名和标识符的命名规则一样,由数字字母下划线组成且不能以数字开头,也不要和系 ...