简介
延迟队列存储的消息是不希望被消费者立刻拿到的,而是等待特定时间后,消费者才能拿到这个消息进行消费。使用场景比较多,例如订单限时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的简单示例吧.在具体讲解之前,先通过一个 ...
随机推荐
- 【小白学PyTorch】4 构建模型三要素与权重初始化
文章目录: 目录 1 模型三要素 2 参数初始化 3 完整运行代码 4 尺寸计算与参数计算 1 模型三要素 三要素其实很简单 必须要继承nn.Module这个类,要让PyTorch知道这个类是一个Mo ...
- 跟着尚硅谷系统学习Docker-【day05】
day05-20200717 p21.docker容器数据卷容器 就是活动硬盘上面挂载硬盘进行数据的传递. [docker run -it --name dc01 fyr/centos ...
- 烂大街的 Spring 循环依赖问题,你觉得自己会了吗
文章已收录在 GitHub JavaKeeper ,N 线互联网开发.面试必备技能兵器谱,笔记自取. 微信搜「 JavaKeeper 」程序员成长充电站,互联网技术武道场.无套路领取 500+ 本电子 ...
- vue-devtools-4.1.4_0.crx及Vue.js not detected的问题
谷歌-更多工具-扩展程序 Vue.js not detected的问题
- PHP复杂变量
eval($str="${${phpinfo()}}";) → 可以执行phpinfo() ${phpinfo()} = {${phpindo()}} PHP复杂变量 ...
- Conscription(POJ 3723)
原题如下: Conscription Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 16584 Accepted: 57 ...
- pytest测试框架 -- setup和teardown等
一.用例运行级别 1.函数级别(setup.teardown 或 setup_function.teardown_function): 仅对处于同作用域的测试函数有效(该函数定义不在类中,则对非类中测 ...
- oracle之三手工不完全恢复
手工不完全恢复 4.1 不完全恢复的特点: 1)让整个database 回到过去某个时间点,不能避免数据丢失. 2)想跳过坏日志而继续恢复所有其他工作是不可能的,前滚没有这个功能(考点). 3)必须以 ...
- 乔悟空-CTF-i春秋-Misc-爆破3
hehe,第一次用这个,开始CTF刷题之旅 2020.09.02 题目地址 学习 题目分析 下边是题目给的php源码,意思就是进行源码审计,分析出能输出flag的条件. 这东西我是真小白,so,积累经 ...
- [LeetCode]230. 二叉搜索树中第K小的元素(BST)(中序遍历)、530. 二叉搜索树的最小绝对差(BST)(中序遍历)
题目230. 二叉搜索树中第K小的元素 给定一个二叉搜索树,编写一个函数 kthSmallest 来查找其中第 k 个最小的元素. 题解 中序遍历BST,得到有序序列,返回有序序列的k-1号元素. 代 ...