简介
延迟队列存储的消息是不希望被消费者立刻拿到的,而是等待特定时间后,消费者才能拿到这个消息进行消费。使用场景比较多,例如订单限时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的简单示例吧.在具体讲解之前,先通过一个 ...
随机推荐
- Lombok插件有望被Intellij IDEA收编以改善兼容性问题
1. 前言 最近两个版本的Intellij IDEA没有办法使用lombok插件了,这种问题已经出现了多次,导致胖哥依然使用2020.1的旧版本.其实很多人和我一样也回滚到了旧版本.我一直认为是lom ...
- ent orm笔记2---schema使用(下)
Indexes 索引 在前两篇的文章中,其实对于索引也有一些使用, 这里来详细看一下关于索引的使用 Indexes方法可以在一个或者多个字段上设置索引,以提高数据检索的速度或者定义数据的唯一性 在下面 ...
- “大地主”IPv6的地址实验配置
上一篇文章,我们简单的介绍了一下IPv6协议的邻居发现BD和简单的基础配置,这里我们通过实验观察一下 IPv6邻居发现中会发送的报文,顺便熟悉一下,新的地址配置 根据拓扑图配置地址 这里原理和IPv4 ...
- 【java学习笔记】LongAdder
目录 1.背景 2.LongAdder 3.Striped64内部结构 4.LongAdder的add方法解析 5.Striped64的longAccumulate方法解析 6.总结 LongAdde ...
- Qt QDialog添加最大化和最小化按钮
Qt QDialog添加最大化和最小化按钮(转载) QDialog窗体右上角默认是没有最小化和最大化按钮的. 1.效果 2.上代码 1 // 设置窗体最大化和最小化 2 Qt::WindowFlags ...
- 学习一下 JVM (三) -- 了解一下 垃圾回收
一.简单了解几个概念 1.什么是垃圾(Garbage)?什么是垃圾回收(Garbage Collection,简称 GC)? (1)什么是垃圾(Garbage)? 这里的垃圾 指的是 在程序运行过程中 ...
- vs2015创建项目没法选择.net2.0的问题
今天要修护一个net2.0开发的程序bug,只修改了一行代码,发布到测试系统,结果程序奔溃了,吓出一身汗. 因为是直接崩溃,所以第一个想到的就是.net版本错了.一查看,果实是,项目属性里目标框架是4 ...
- Apache Pulsar 2.6.1 版本正式发布:2.6.0 功能增强版,新增 OAuth2 支持
在 Apache Pulsar 2.6.0 版本发布后的 2 个月,2020 年 8 月 21 日,Apache Pulsar 2.6.1 版本正式发布! Apache Pulsar 2.6.1 修复 ...
- 目标识别AI资料
朋友推荐的, 还有自己搜的. 入门可以看看. 网上资料应该不少, 一搜一大把, 简单记下地址. Review of Deep Learning Algorithms for Object Detect ...
- 在Fragment 中拦截返回键
代码如下: class XXXFrgmt : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ...