一、简述

二、示例demo

一、简述

延时消息在日常随处可见:

1、订单创建10min之后不发起支付,自动取消。

2、30min定时推送一次邮件信息。

最常用到方式为定时任务轮训,数据量小的时候使用没什么问题 而当有千万甚至上亿的数据量时就会出现数据读取的瓶颈,此时全表扫面进行处理一定是下下策。但是也有比较讨巧的方式,分享公司内部订单拆分的例子:

由于线上每天订单量50万+的增长量,单表早已无法吃撑这个增长的速度。采取的方式为订单归档:线上热数据保留2-3天的数据,其余都归档进入历史订单表中,这样热数据在200万以内。
订单超过10min不支付即取消的功能,可以采取简单的扫表形式而不会出现数据读取性能的问题。

这样的方式很简单,但需要跟业务进行沟通妥协,本文会讲另一种方式即RabbitMQ延迟队列。RabbitMQ实际并没有直接实现延时队列,但可利用RabbitMQ提供的属性来模拟延时队列,甚至已经有的配套的插件rabbitmq_delayed_message_exchange 下面先介绍使用到的RabbitMQ的属性。

1、消息的Time To Live (TTL)

x-message-ttl:消息过期时间,超过过期时间之后即变为死信(Dead-letter)不会再被消费者消费。

设置消息TTL有两种方式:

  • 创建队列时指定x-message-ttl,此时队列所有的消息具有统一过期时间。
  • 发送消息为每个消息设置 expiration,此时消息之间过期时间不同。

如果两者都设置,过期时间取两者最小。如果设置TTL为0即表示除非立马能发送到队列,否则直接丢弃该消息。利用TTL为0的特性再结合死信转发器可以替代RabbitMQ 3.0的immediate参数。

2、队列的TTL

x-expires: RabbitMQ会确保时间达到后将队列删除,但是并不保障这个动作有多及时。队列过期代表着处于未使用状态,即

  • 队列无任何消费者
  • 队列没有被重新声明
  • 队列在过期未调用Basic.Get命令获取消息

3、x-dead-letter-exchange(RabbitMQ文档):死信转发器(转发器类型)当消息达到过期时间未被消费则会由该exchange按照配置的x-dead-letter-routing-key转发到指定队列,最后被消费者消费,如果未配置x-dead-letter-routing-key则会按照原队列的key进行转发。

4、队列的消息在以下几种情况会变成死信(Dead-letter)

  • 设置的x-message-ttl或者expiration到期,即消息过期
  • 消息被消费者拒绝(调用Basic.Reject / Basic.Nack)且 requeue参数设置为false
  • 队列达到最大长度

二、示例demo

  • 单个延迟队列

RabbitMQ延时队列逻辑:

1、exchange_delay_begin:缓冲队列exchange交换器,用于将消息转发至缓存消息队列 queue_delay_begin 。

2、exchange_delay_done:死信(dead-letter)队列exchange交换器,用于将队列 queue_delay_begin 转发到死信队列。

3、queue_delay_begin:缓冲消息队列,等待消息过期。

4、queue_delay_done:死信消息队列,消费者能够真正消费信息。

spring-rabbitmq.xml :

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit-1.6.xsd">
<!--配置connection-factory,指定连接rabbit server参数 -->
<rabbit:connection-factory id="connectionFactory" username="guest" password="guest" host="127.0.0.1" port="5672" publisher-confirms="true"/>
<!-- 延时队列 -->
<rabbit:direct-exchange id="exchange_delay_begin" name="exchange_delay_begin" durable="false" auto-delete="false" >
<rabbit:bindings>
<rabbit:binding queue="queue_delay_begin" key="delay" />
</rabbit:bindings>
</rabbit:direct-exchange> <rabbit:queue name="queue_delay_begin" durable="false">
<rabbit:queue-arguments>
<!-- 队列过期时间 -->
<entry key="x-message-ttl" value="30000" value-type="java.lang.Long" />
<entry key="x-dead-letter-exchange" value="exchange_delay_done" />
<entry key="x-dead-letter-routing-key" value="delay" />

</rabbit:queue-arguments>
</rabbit:queue> <rabbit:direct-exchange id="exchange_delay_done" name="exchange_delay_done" durable="false" auto-delete="false" >
<rabbit:bindings>
<rabbit:binding queue="queue_delay_done" key="delay" />
<!-- binding key 相同为 【delay】exchange转发消息到多个队列 -->
<!--<rabbit:binding queue="queue_delay_done_two" key="delay" />-->
</rabbit:bindings>
</rabbit:direct-exchange> <rabbit:queue name="queue_delay_done" durable="false"/>
<rabbit:template id="delayMsgTwoTemplate" connection-factory="connectionFactory" />
<bean id="messageConsumer" class="com.nancy.rabbitmq.demo.MessageConsumer"></bean> <!-- 消息接收者 -->
<rabbit:listener-container connection-factory="connectionFactory" channel-transacted="false" >
<rabbit:listener queues="queue_delay_done" ref="messageConsumer" />
</rabbit:listener-container>
</beans>

DelayMessageProducer.java

@Service
public class DelayMessageProducer {
@Resource(name="delayMsgTwoTemplate")
private AmqpTemplate delayMsgTwoTemplate;
public void delayMsgTwo(String exchange, String routingKey, Object msg) {
delayMsgTwoTemplate.convertAndSend(exchange, routingKey, msg, new MessagePostProcessor() {
@Override
public Message postProcessMessage(Message message) throws AmqpException {
message.getMessageProperties().setExpiration(String.valueOf(10000));
return message;
}
});
}
}

MessageConsumer.java

public class MessageConsumer implements MessageListener {
@Override
public void onMessage(Message message) {
System.out.println("consumer receive message 22------->:{}"+ message);
}
}

application.xml 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<import resource="spring-rabbitmq.xml" />
<!-- 扫描指定package注释的注册为Spring Beans -->
<context:component-scan base-package="com.nancy.rabbitmq" />
<!-- 激活annotation功能 -->
<context:annotation-config />
<!-- 激活annotation功能 -->
<context:spring-configured />
</beans>

DelayQueueTest.java

public class DelayQueueTest {
private ApplicationContext context = null;
@org.junit.Before
public void setUp() throws Exception {
context = new ClassPathXmlApplicationContext("rabbitmq/application.xml");
}
@Test
public void delayQueueTest() throws Exception {
DelayMessageProducer messageProducer = context.getBean(DelayMessageProducer.class);
int a = 10;
while (a > 0) {
System.out.println("send "+ a);
messageProducer.delayMsgTwo("exchange_delay_begin","delay", "hello world delay2 :" + a--);
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("sended ");
Thread.sleep(1000*60);
}
}

运行结果: 发送消息 10s之后, 消费监听到消息 消费。

send 10
send 9
send 8
send 7
send 6
send 5
send 4
send 3
send 2
send 1
sended
consumer receive message 22------->:{}(Body:'hello world delay2 :10' MessageProperties [headers={x-first-death-exchange=exchange_delay_begin, x-death=[{reason=expired, original-expiration=10000, count=1, exchange=exchange_delay_begin, time=Sun Jul 01 18:33:19 CST 2018, routing-keys=[delay], queue=queue_delay_begin}], x-first-death-reason=expired, x-first-death-queue=queue_delay_begin}, timestamp=null, messageId=null, userId=null, receivedUserId=null, appId=null, clusterId=null, type=null, correlationId=null, correlationIdString=null, replyTo=null, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, deliveryMode=null, receivedDeliveryMode=PERSISTENT, expiration=null, priority=0, redelivered=false, receivedExchange=exchange_delay_done, receivedRoutingKey=delay, receivedDelay=1000, deliveryTag=1, messageCount=0, consumerTag=amq.ctag-oOJzeYHEJYrLFL4HbHWZcA, consumerQueue=queue_delay_done])
consumer receive message 22------->:{}(Body:'hello world delay2 :9' MessageProperties [headers={x-first-death-exchange=exchange_delay_begin, x-death=[{reason=expired, original-expiration=10000, count=1, exchange=exchange_delay_begin, time=Sun Jul 01 18:33:19 CST 2018, routing-keys=[delay], queue=queue_delay_begin}], x-first-death-reason=expired, x-first-death-queue=queue_delay_begin}, timestamp=null, messageId=null, userId=null, receivedUserId=null, appId=null, clusterId=null, type=null, correlationId=null, correlationIdString=null, replyTo=null, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, deliveryMode=null, receivedDeliveryMode=PERSISTENT, expiration=null, priority=0, redelivered=false, receivedExchange=exchange_delay_done, receivedRoutingKey=delay, receivedDelay=1000, deliveryTag=2, messageCount=0, consumerTag=amq.ctag-oOJzeYHEJYrLFL4HbHWZcA, consumerQueue=queue_delay_done])
consumer receive message 22------->:{}(Body:'hello world delay2 :8' MessageProperties [headers={x-first-death-exchange=exchange_delay_begin, x-death=[{reason=expired, original-expiration=10000, count=1, exchange=exchange_delay_begin, time=Sun Jul 01 18:33:19 CST 2018, routing-keys=[delay], queue=queue_delay_begin}], x-first-death-reason=expired, x-first-death-queue=queue_delay_begin}, timestamp=null, messageId=null, userId=null, receivedUserId=null, appId=null, clusterId=null, type=null, correlationId=null, correlationIdString=null, replyTo=null, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, deliveryMode=null, receivedDeliveryMode=PERSISTENT, expiration=null, priority=0, redelivered=false, receivedExchange=exchange_delay_done, receivedRoutingKey=delay, receivedDelay=1000, deliveryTag=3, messageCount=0, consumerTag=amq.ctag-oOJzeYHEJYrLFL4HbHWZcA, consumerQueue=queue_delay_done])
consumer receive message 22------->:{}(Body:'hello world delay2 :7' MessageProperties [headers={x-first-death-exchange=exchange_delay_begin, x-death=[{reason=expired, original-expiration=10000, count=1, exchange=exchange_delay_begin, time=Sun Jul 01 18:33:19 CST 2018, routing-keys=[delay], queue=queue_delay_begin}], x-first-death-reason=expired, x-first-death-queue=queue_delay_begin}, timestamp=null, messageId=null, userId=null, receivedUserId=null, appId=null, clusterId=null, type=null, correlationId=null, correlationIdString=null, replyTo=null, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, deliveryMode=null, receivedDeliveryMode=PERSISTENT, expiration=null, priority=0, redelivered=false, receivedExchange=exchange_delay_done, receivedRoutingKey=delay, receivedDelay=1000, deliveryTag=4, messageCount=0, consumerTag=amq.ctag-oOJzeYHEJYrLFL4HbHWZcA, consumerQueue=queue_delay_done])
consumer receive message 22------->:{}(Body:'hello world delay2 :6' MessageProperties [headers={x-first-death-exchange=exchange_delay_begin, x-death=[{reason=expired, original-expiration=10000, count=1, exchange=exchange_delay_begin, time=Sun Jul 01 18:33:19 CST 2018, routing-keys=[delay], queue=queue_delay_begin}], x-first-death-reason=expired, x-first-death-queue=queue_delay_begin}, timestamp=null, messageId=null, userId=null, receivedUserId=null, appId=null, clusterId=null, type=null, correlationId=null, correlationIdString=null, replyTo=null, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, deliveryMode=null, receivedDeliveryMode=PERSISTENT, expiration=null, priority=0, redelivered=false, receivedExchange=exchange_delay_done, receivedRoutingKey=delay, receivedDelay=1000, deliveryTag=5, messageCount=0, consumerTag=amq.ctag-oOJzeYHEJYrLFL4HbHWZcA, consumerQueue=queue_delay_done])
consumer receive message 22------->:{}(Body:'hello world delay2 :5' MessageProperties [headers={x-first-death-exchange=exchange_delay_begin, x-death=[{reason=expired, original-expiration=10000, count=1, exchange=exchange_delay_begin, time=Sun Jul 01 18:33:19 CST 2018, routing-keys=[delay], queue=queue_delay_begin}], x-first-death-reason=expired, x-first-death-queue=queue_delay_begin}, timestamp=null, messageId=null, userId=null, receivedUserId=null, appId=null, clusterId=null, type=null, correlationId=null, correlationIdString=null, replyTo=null, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, deliveryMode=null, receivedDeliveryMode=PERSISTENT, expiration=null, priority=0, redelivered=false, receivedExchange=exchange_delay_done, receivedRoutingKey=delay, receivedDelay=1000, deliveryTag=6, messageCount=0, consumerTag=amq.ctag-oOJzeYHEJYrLFL4HbHWZcA, consumerQueue=queue_delay_done])
consumer receive message 22------->:{}(Body:'hello world delay2 :4' MessageProperties [headers={x-first-death-exchange=exchange_delay_begin, x-death=[{reason=expired, original-expiration=10000, count=1, exchange=exchange_delay_begin, time=Sun Jul 01 18:33:19 CST 2018, routing-keys=[delay], queue=queue_delay_begin}], x-first-death-reason=expired, x-first-death-queue=queue_delay_begin}, timestamp=null, messageId=null, userId=null, receivedUserId=null, appId=null, clusterId=null, type=null, correlationId=null, correlationIdString=null, replyTo=null, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, deliveryMode=null, receivedDeliveryMode=PERSISTENT, expiration=null, priority=0, redelivered=false, receivedExchange=exchange_delay_done, receivedRoutingKey=delay, receivedDelay=1000, deliveryTag=7, messageCount=0, consumerTag=amq.ctag-oOJzeYHEJYrLFL4HbHWZcA, consumerQueue=queue_delay_done])
consumer receive message 22------->:{}(Body:'hello world delay2 :3' MessageProperties [headers={x-first-death-exchange=exchange_delay_begin, x-death=[{reason=expired, original-expiration=10000, count=1, exchange=exchange_delay_begin, time=Sun Jul 01 18:33:19 CST 2018, routing-keys=[delay], queue=queue_delay_begin}], x-first-death-reason=expired, x-first-death-queue=queue_delay_begin}, timestamp=null, messageId=null, userId=null, receivedUserId=null, appId=null, clusterId=null, type=null, correlationId=null, correlationIdString=null, replyTo=null, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, deliveryMode=null, receivedDeliveryMode=PERSISTENT, expiration=null, priority=0, redelivered=false, receivedExchange=exchange_delay_done, receivedRoutingKey=delay, receivedDelay=1000, deliveryTag=8, messageCount=0, consumerTag=amq.ctag-oOJzeYHEJYrLFL4HbHWZcA, consumerQueue=queue_delay_done])
consumer receive message 22------->:{}(Body:'hello world delay2 :2' MessageProperties [headers={x-first-death-exchange=exchange_delay_begin, x-death=[{reason=expired, original-expiration=10000, count=1, exchange=exchange_delay_begin, time=Sun Jul 01 18:33:19 CST 2018, routing-keys=[delay], queue=queue_delay_begin}], x-first-death-reason=expired, x-first-death-queue=queue_delay_begin}, timestamp=null, messageId=null, userId=null, receivedUserId=null, appId=null, clusterId=null, type=null, correlationId=null, correlationIdString=null, replyTo=null, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, deliveryMode=null, receivedDeliveryMode=PERSISTENT, expiration=null, priority=0, redelivered=false, receivedExchange=exchange_delay_done, receivedRoutingKey=delay, receivedDelay=1000, deliveryTag=9, messageCount=0, consumerTag=amq.ctag-oOJzeYHEJYrLFL4HbHWZcA, consumerQueue=queue_delay_done])
consumer receive message 22------->:{}(Body:'hello world delay2 :1' MessageProperties [headers={x-first-death-exchange=exchange_delay_begin, x-death=[{reason=expired, original-expiration=10000, count=1, exchange=exchange_delay_begin, time=Sun Jul 01 18:33:19 CST 2018, routing-keys=[delay], queue=queue_delay_begin}], x-first-death-reason=expired, x-first-death-queue=queue_delay_begin}, timestamp=null, messageId=null, userId=null, receivedUserId=null, appId=null, clusterId=null, type=null, correlationId=null, correlationIdString=null, replyTo=null, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, deliveryMode=null, receivedDeliveryMode=PERSISTENT, expiration=null, priority=0, redelivered=false, receivedExchange=exchange_delay_done, receivedRoutingKey=delay, receivedDelay=1000, deliveryTag=10, messageCount=0, consumerTag=amq.ctag-oOJzeYHEJYrLFL4HbHWZcA, consumerQueue=queue_delay_done])
  • 多个延迟队列

实际的业务需求中会出现不同的时间延迟,此时可设置多个队列以达到不同的延迟效果。例如5个队列 common-queue_5s、common-queue_15s、common-queue_30s、common-queue_45s、common-queue_50s达到不同的延迟效果,整体的结构如下:

上述bindingKey的值有所简化,但对路由结构图无影响。这里使用一个死信转发器(转发器类型)通过绑定不同的key路由到不同的死信队列。也可以死信转发器和死信队列一对一绑定 即 成对出现(dlx_exchange_5s 和 dead-letter-queue_5s)

这里贴出部分xml部分配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/rabbit
http://www.springframework.org/schema/rabbit/spring-rabbit-1.4.xsd"> <rabbit:connection-factory
id="connectionFactory"
host="${rabbit.host}"
port="${rabbit.port}"
username="${rabbit.username}"
password="${rabbit.password}"
publisher-confirms="true"
/> <rabbit:admin connection-factory="connectionFactory" ignore-declaration-exceptions="true" /> <!-- 正常队列 -->
<!-- 5s过期 -->
<rabbit:queue name="common-queue_5s">
<rabbit:queue-arguments>
<entry key="x-message-ttl" value="5000" value-type="java.lang.Long" />
<entry key="x-dead-letter-exchange" value="dlx-exchange" />
<entry key="x-dead-letter-routing-key" value="dead-letter-queue_5s" />
</rabbit:queue-arguments>
</rabbit:queue>
<!-- 15s过期 -->
<rabbit:queue name="common-queue_15s">
<rabbit:queue-arguments>
<entry key="x-message-ttl" value="15000" value-type="java.lang.Long" />
<entry key="x-dead-letter-exchange" value="dlx-exchange" />
<entry key="x-dead-letter-routing-key" value="dead-letter-queue_15s" />
</rabbit:queue-arguments>
</rabbit:queue>
<!-- 30s过期 -->
<rabbit:queue name="common-queue_30s">
<rabbit:queue-arguments>
<entry key="x-message-ttl" value="30000" value-type="java.lang.Long" />
<entry key="x-dead-letter-exchange" value="dlx-exchange" />
<entry key="x-dead-letter-routing-key" value="dead-letter-queue_30s" />
</rabbit:queue-arguments>
</rabbit:queue>
<!-- 45s过期 -->
<rabbit:queue name="common-queue_45s">
<rabbit:queue-arguments>
<entry key="x-message-ttl" value="45000" value-type="java.lang.Long" />
<entry key="x-dead-letter-exchange" value="dlx-exchange" />
<entry key="x-dead-letter-routing-key" value="dead-letter-queue_45s" />
</rabbit:queue-arguments>
</rabbit:queue>
<!-- 50s过期 -->
<rabbit:queue name="common-queue_50s">
<rabbit:queue-arguments>
<entry key="x-message-ttl" value="50000" value-type="java.lang.Long" />
<entry key="x-dead-letter-exchange" value="dlx-exchange" />
<entry key="x-dead-letter-routing-key" value="dead-letter-queue_50s" />
</rabbit:queue-arguments>
</rabbit:queue>
<!-- 正常路由 -->
<rabbit:direct-exchange name="common-exchange" durable="false" id="common-exchange">
<rabbit:bindings>
<rabbit:binding queue="common-queue_5s" />
<rabbit:binding queue="common-queue_15s" />
<rabbit:binding queue="common-queue_30s" />
<rabbit:binding queue="common-queue_45s" />
<rabbit:binding queue="common-queue_50s" />
</rabbit:bindings>
</rabbit:direct-exchange> <!-- 死信队列 -->
<rabbit:queue name="dead-letter-queue_5s" />
<rabbit:queue name="dead-letter-queue_15s" />
<rabbit:queue name="dead-letter-queue_30s" />
<rabbit:queue name="dead-letter-queue_45s" />
<rabbit:queue name="dead-letter-queue_50s" />
<rabbit:direct-exchange name="dlx-exchange" durable="false" id="dlx-exchange">
<rabbit:bindings>
<rabbit:binding queue="dead-letter-queue_5s" />
<rabbit:binding queue="dead-letter-queue_15s" />
<rabbit:binding queue="dead-letter-queue_30s" />
<rabbit:binding queue="dead-letter-queue_45s" />
<rabbit:binding queue="dead-letter-queue_50s" />
</rabbit:bindings>
</rabbit:direct-exchange> <!-- 配置consumer, 监听的类和queue的对应关系 -->
<rabbit:listener-container
connection-factory="connectionFactory" acknowledge="manual" >
<rabbit:listener queues="dead-letter-queue_5s" ref="receiveConfirmTestListener" />
<rabbit:listener queues="dead-letter-queue_15s" ref="receiveConfirmTestListener" />
<rabbit:listener queues="dead-letter-queue_30s" ref="receiveConfirmTestListener" />
<rabbit:listener queues="dead-letter-queue_45s" ref="receiveConfirmTestListener" />
<rabbit:listener queues="dead-letter-queue_50s" ref="receiveConfirmTestListener" />
</rabbit:listener-container> </beans>

junit测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:application-context.xml"})
public class TestDeadLetter {
@Autowired
private DeadLetterPublishService publishService; @Test
public void testALL() throws InterruptedException{
String message = "currentTime:" + System.currentTimeMillis();
System.out.println("test1---message: "+ message);
publishService.send("common-exchange","common-queue_5s", message);
publishService.send("common-exchange","common-queue_15s", message);
publishService.send("common-exchange","common-queue_30s", message);
publishService.send("common-exchange","common-queue_45s", message);
publishService.send("common-exchange","common-queue_50s", message);
Thread.sleep(100000);
} }

TestDeadLetter.java

最后运行结果:消息实际发送时间点 和 消息被延迟消费时间点无限接近 五个消息分别延迟大约 5s 15s 30s 45s 50s  但做不到精确一致。

test1---message: currentTime:
// 。。。。
- consumer--:MessageProperties [headers={spring_return_correlation=1ac8ee8e-6d61-4bbf-bac1-f21523a0d759, x-first-death-exchange=common-exchange, x-death=[{reason=expired, count=1, exchange=common-exchange, time=Tue Aug 27 23:34:18 CST 2019, routing-keys=[common-queue_5s], queue=common-queue_5s}], x-first-death-reason=expired, x-first-death-queue=common-queue_5s}, timestamp=null, messageId=null, userId=null, appId=null, clusterId=null, type=null, correlationId=null, replyTo=null, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, deliveryMode=PERSISTENT, expiration=null, priority=0, redelivered=false, receivedExchange=dlx-exchange, receivedRoutingKey=dead-letter-queue_5s, deliveryTag=1, messageCount=0]:currentTime:1566920053524
1566920068578 - consumer--:MessageProperties [headers={spring_return_correlation=1ac8ee8e-6d61-4bbf-bac1-f21523a0d759, x-first-death-exchange=common-exchange, x-death=[{reason=expired, count=1, exchange=common-exchange, time=Tue Aug 27 23:34:28 CST 2019, routing-keys=[common-queue_15s], queue=common-queue_15s}], x-first-death-reason=expired, x-first-death-queue=common-queue_15s}, timestamp=null, messageId=null, userId=null, appId=null, clusterId=null, type=null, correlationId=null, replyTo=null, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, deliveryMode=PERSISTENT, expiration=null, priority=0, redelivered=false, receivedExchange=dlx-exchange, receivedRoutingKey=dead-letter-queue_15s, deliveryTag=1, messageCount=0]:currentTime:1566920053524
1566920083550 - consumer--:MessageProperties [headers={spring_return_correlation=1ac8ee8e-6d61-4bbf-bac1-f21523a0d759, x-first-death-exchange=common-exchange, x-death=[{reason=expired, count=1, exchange=common-exchange, time=Tue Aug 27 23:34:43 CST 2019, routing-keys=[common-queue_30s], queue=common-queue_30s}], x-first-death-reason=expired, x-first-death-queue=common-queue_30s}, timestamp=null, messageId=null, userId=null, appId=null, clusterId=null, type=null, correlationId=null, replyTo=null, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, deliveryMode=PERSISTENT, expiration=null, priority=0, redelivered=false, receivedExchange=dlx-exchange, receivedRoutingKey=dead-letter-queue_30s, deliveryTag=1, messageCount=0]:currentTime:1566920053524
1566920098549 - consumer--:MessageProperties [headers={spring_return_correlation=1ac8ee8e-6d61-4bbf-bac1-f21523a0d759, x-first-death-exchange=common-exchange, x-death=[{reason=expired, count=1, exchange=common-exchange, time=Tue Aug 27 23:34:58 CST 2019, routing-keys=[common-queue_45s], queue=common-queue_45s}], x-first-death-reason=expired, x-first-death-queue=common-queue_45s}, timestamp=null, messageId=null, userId=null, appId=null, clusterId=null, type=null, correlationId=null, replyTo=null, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, deliveryMode=PERSISTENT, expiration=null, priority=0, redelivered=false, receivedExchange=dlx-exchange, receivedRoutingKey=dead-letter-queue_45s, deliveryTag=1, messageCount=0]:currentTime:1566920053524
1566920103551 - consumer--:MessageProperties [headers={spring_return_correlation=1ac8ee8e-6d61-4bbf-bac1-f21523a0d759, x-first-death-exchange=common-exchange, x-death=[{reason=expired, count=1, exchange=common-exchange, time=Tue Aug 27 23:35:03 CST 2019, routing-keys=[common-queue_50s], queue=common-queue_50s}], x-first-death-reason=expired, x-first-death-queue=common-queue_50s}, timestamp=null, messageId=null, userId=null, appId=null, clusterId=null, type=null, correlationId=null, replyTo=null, contentType=text/plain, contentEncoding=UTF-8, contentLength=0, deliveryMode=PERSISTENT, expiration=null, priority=0, redelivered=false, receivedExchange=dlx-exchange, receivedRoutingKey=dead-letter-queue_50s, deliveryTag=1, messageCount=0]:currentTime:1566920053524

参考资料:

DLX:https://www.rabbitmq.com/dlx.html

RabbitMQ如何实现延迟队列?:https://blog.csdn.net/u013256816/article/details/55106401

消息队列之 RabbitMQ :https://www.jianshu.com/p/79ca08116d57

使用RabbitMQ实现延迟任务 : https://www.cnblogs.com/haoxinyue/p/6613706.html

RabbitMQ 延时消息队列的更多相关文章

  1. spring boot Rabbitmq集成,延时消息队列实现

    本篇主要记录Spring boot 集成Rabbitmq,分为两部分, 第一部分为创建普通消息队列, 第二部分为延时消息队列实现: spring boot提供对mq消息队列支持amqp相关包,引入即可 ...

  2. RabbitMQ分布式消息队列服务器(一、Windows下安装和部署)

    RabbitMQ消息队列服务器在Windows下的安装和部署-> 一.Erlang语言环境的搭建 RabbitMQ开源消息队列服务是使用Erlang语言开发的,因此我们要使用他就必须先进行Erl ...

  3. rabbitmq学习(二):rabbitmq(消息队列)的作用以及rabbitmq之直连交换机

    前言 上篇介绍了AMQP的基本概念,组成及其与rabbitmq的关系.了解了这些东西后,下面我们开始学习rabbitmq(消息队列)的作用以及用java代码和rabbitmq通讯进行消息发布和接收.因 ...

  4. C#调用RabbitMQ实现消息队列

    前言 我在刚接触使用中间件的时候,发现,中间件的使用并不是最难的,反而是中间件的下载,安装,配置才是最难的. 所以,这篇文章我们从头开始学习RabbitMq,真正的从头开始. 关于消息队列 其实消息队 ...

  5. RabbitMQ 延时消息设计

    问题背景 所谓"延时消息"是指当消息被发送以后,并不想让消费者立即拿到消息,而是等待指定时间后,消费者才拿到这个消息进行消费. 场景一:客户A在十二点下了一个订单,我想半个小时后来 ...

  6. rabbitMq延时消息分级别

    做支付平台的时候.需要实现接受上游支付消息,通知给下游渠道. 针对下游渠道:要实现 按通知次数 递进 延时通知 下游渠道的支付/签约/代扣的状态 可参考微信按照 15/15/30/180/1800/1 ...

  7. rabbitmq高级消息队列

    rabbitmq使用 什么是消息队列 消息(Message)是指在应用间传送的数据.消息可以非常简单,比如只包含文本字符串,也可以很复杂,可以包含嵌入对象. 消息队列是一种应用间的通信方式,消息发送后 ...

  8. Redis与RabbitMQ作为消息队列的比较

    简要介绍 RabbitMQ RabbitMQ是实现AMQP(高级消息队列协议)的消息中间件的一种,最初起源于金融系统,用于在分布式系统中存储转发消息,在易用性.扩展性.高可用性等方面表现不俗.消息中间 ...

  9. RabbitMQ .NET消息队列使用入门(一)【简单示例】

    首先下载安装包,我都环境是win7 64位: 去官网下载 otp_win64_19.0.exe 和rabbitmq-server-3.6.3.exe安装好 然后开始编程了: (1)创建生产者类: cl ...

随机推荐

  1. 浏览器存储:cookie

    Cookie是什么:cookie是指存储在用户本地终端上的数据,同时它是与具体的web页面或者站点相关的.Cookie数据会自动在web浏览器和web服务器之间传输,也就是说HTTP请求发送时,会把保 ...

  2. HDU 4508 湫湫系列故事——减肥记I (完全背包)

    题意:有n种食物,每种食物可以给湫湫带来一个幸福感a,同时也会给她带来b的卡路里的摄入,然后规定她一天摄入的卡路里的量不能超过m,一共有n种食物,问可以得到的 最大的幸福感是多少? 解题报告:一开始以 ...

  3. zabbix user parameters和Loadable modules的使用方法介绍

    目录 需求 实现 原理 前端配置 后端配置 shell实现 python实现 C实现 需求: 采集主机的-/+ buffers/cache  free的数据 实现: 采集/proc/meminfo中的 ...

  4. 第9月第16天 tolua++ cocos2dx cocos2d-lua

    1. http://www.jianshu.com/p/1cdfc60da04f 2.lua c++ Lua访问C++类 现在,我们在Lua里面操作这个Student类.注意,我们绑定的每一个函数都需 ...

  5. 01 uni-app框架学习:项目创建及底部导航栏tabBar配置

    1.创建一个项目类型选择uniapp 2. pages里新建3个页面如下 3.在pages.json中配置底部导航tabBar 效果展示:

  6. pytorch之LSTM

    from:http://pytorch-cn.readthedocs.io/zh/latest/package_references/torch-nn/#recurrent-layers class ...

  7. 利用VBS下载EXE文件手法记录

    1.信息来源 疑似朝鲜通过鱼叉攻击韩国统一部记者的APT事件整理 https://mp.weixin.qq.com/s/4IFV31MBNbANnCVaJj7ZPQ https://twitter.c ...

  8. MySQL多源复制【转】

    什么是多源复制? 首先,我们需要清楚 multi-master 与multi-source 复制不是一样的. Multi-Master 复制通常是环形复制, 你可以在任意主机上将数据复制给其他主机. ...

  9. 002_更新Nginx证书

    全球可信并且唯一免费的HTTPS(SSL)证书颁发机构:StartSSL 1.自行颁发不受浏览器信任的SSL证书: HTTPS的SSL证书可以自行颁发,Linux下的颁发步骤如下: openssl g ...

  10. mysql ON DUPLICATE KEY UPDATE重复插入时更新

    mysql当插入重复时更新的方法: 第一种方法: 示例一:插入多条记录 假设有一个主键为 client_id 的 clients 表,可以使用下面的语句: INSERT INTO clients (c ...