简介
延迟队列存储的消息是不希望被消费者立刻拿到的,而是等待特定时间后,消费者才能拿到这个消息进行消费。使用场景比较多,例如订单限时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的简单示例吧.在具体讲解之前,先通过一个 ...
随机推荐
- 查询Linux CPU架构
一.背景 Ubuntu上需要安装测试个软件wkhtmltopdf,但是下载时,需要知道系统架构,故做记录 二.查看linux架构 dpkg 命令 dpkg 的命令可用于查看 Debian/ Ubunt ...
- FJOI2020 游记
Day -1 啥都不会,药丸 看了看统考题,好难,爆零的节奏 文化课OI双爆炸 尽力吧 Day 0 花三个多小时才到考场 福州真的好热 签到 在小礼堂待了一会,顺便给手机充了电 四点试机,今年用了新系 ...
- java里equals和hashCode之间什么关系
如果要比较实际内存中的内容,那就要用equals方法,但是!!! 如果是你自己定义的一个类,比较自定义类用equals和==是一样的,都是比较句柄地址,因为自定义的类是继承于object,而objec ...
- rabbitmq用户权限
none:无法登录控制台 不能访问 management plugin,通常就是普通的生产者和消费者. management:普通管理者. 仅可登陆管理控制台(启用management plugin的 ...
- 为什么 list(range) 比 [i for i in range()] 快?
为什么 list(range) 比 [i for i in range()] 快? t0 = time.time() list(range(100000)) print(time.time()-t0) ...
- The Unique MST(最小生成树的唯一性判断)
Given a connected undirected graph, tell if its minimum spanning tree is unique. Definition 1 (Spann ...
- 小程序开发-block组件的使用
微信小程序中,block不是一个组件,而是一个包装元素,不会在页面中做任何渲染. 使用情况:条件渲染 wx:if 因为 wx:if 是一个控制属性,需要将它添加到一个标签/组件上,用于控制隐藏与显示. ...
- jQuery的那些事儿
jQuery概述 j-JavaScript+Query就是查询js的库,把js中的DOM操作做了封装,实现快速查询使用其中的功能. 优化了DOM操作.事件处理.动画设计和Ajax交互 学习jQuery ...
- 关于非标准json格式转变为json对象
eval('(' + tempData + ')') 只需要这一句
- python基础一(安装、变量、循环、git)
一.开发语言分类 系统的开发语言有java.c++.c#.python.ruby.php等等,开发语言可分为编译型语言和解释型语言. 编译型语言就是写好代码之后就把代码编译成二进制文件,运行的时候运行 ...