RabbitMQ - DLX (Dead Letter Exchanges)实现延迟队列

一、延迟队列设计
队列中的消息成为死信(Dead Letter)的几种情况:
1) The message is rejected (basic.reject or basic.nack) with requeue=false,
2) The TTL for the message expires; or
3) The queue length limit is exceeded.
而通过配置队列的x-dead-letter-exchange及x-dead-letter-routing-key键值,Dead Letter就会被重新发送到指定的DLX中。
 
如上图所示,注意延迟队列并没有消费者,并且设置参数:
x-dead-letter-exchange:DLX
x-dead-letter-routing-key:DLK
x-max-length:1000000 // length = 1million
x-message-ttl:30000 // TTL = 30s
生产者发布的消息路由到该延迟队列,30秒后消息成为死信并被重新发送到死信交换器DLX中;消费者订阅死信队列DLQ,消费消息。
二、 延迟队列实现
  1. @Configuration
  2. @PropertySource( "classpath:rabbitmq-cfg.properties")
  3. public class RabbitConfig {
  4. /**
  5. * 配置RabbitMQ连接工厂
  6. *
  7. * @param host
  8. * @param port
  9. * @param username
  10. * @param password
  11. * @param virtualHost
  12. * @param connectionTimeout
  13. * @return
  14. */
  15. @Bean
  16. public ConnectionFactory connectionFactory(@Value("${spring.rabbitmq.host}") String host,
  17. @Value("${spring.rabbitmq.port}") String port, @Value("${spring.rabbitmq.username}") String username,
  18. @Value("${spring.rabbitmq.password}") String password,
  19. @Value("${spring.rabbitmq.virtual-host}") String virtualHost,
  20. @Value("${spring.rabbitmq.connection-timeout}") String connectionTimeout) {
  21. CachingConnectionFactory ret = new CachingConnectionFactory();
  22. ret.setHost(host);
  23. ret.setPort(Integer.parseInt(port));
  24. ret.setUsername(username);
  25. ret.setPassword(password);
  26. ret.setVirtualHost(virtualHost);
  27. ret.setConnectionTimeout(Integer.parseInt(connectionTimeout));
  28. return ret;
  29. }

  30. /**
  31. * 声明30s延迟队列
  32. *
  33. * @param name
  34. * @return
  35. */
  36. @Bean
  37. public Queue queueDelay30s(@Value("${atf.queue.delay.30s}") String name) {
  38. Map<String, Object> arguments = new HashMap<String, Object>();
  39. arguments.put( "x-message-ttl", 30 * 1000); // Message TTL = 30s
  40. arguments.put( "x-max-length", 1000000); // Max length = 1million
  41. // 死信路由到死信交换器DLX
  42. arguments.put( "x-dead-letter-exchange", "atf.exchange.delay.dlx");
  43. arguments.put( "x-dead-letter-routing-key", "atf.routingkey.delay.dlk");
  44. return new Queue(name, true, false, false, arguments);
  45. }

  46. /**
  47. * 声明死信队列DLQ
  48. *
  49. * @param name
  50. * @return
  51. */
  52. @Bean
  53. public Queue queueDelayDlq(@Value("${atf.queue.delay.dlq}") String name) {
  54. return new Queue(name, true, false, false);
  55. }

  56. /**
  57. * 声明延迟交换器
  58. *
  59. * @param name
  60. * @return
  61. */
  62. @Bean
  63. public DirectExchange exchangeDelay(@Value("${atf.exchange.delay}") String name) {
  64. DirectExchange ret = new DirectExchange(name, true, false);
  65. ret.setInternal( false);
  66. return ret;
  67. }

  68. /**
  69. * 声明死信交换器DLX
  70. *
  71. * @param name
  72. * @return
  73. */
  74. @Bean
  75. public DirectExchange exchangeDelayDlx(@Value("${atf.exchange.delay.dlx}") String name) {
  76. return new DirectExchange(name, true, false);
  77. }

  78. /**
  79. * 绑定延迟交换器和30s延迟队列
  80. *
  81. * @param queue
  82. * @param exchange
  83. * @param routingKey
  84. * @return
  85. */
  86. @Bean
  87. public Binding bindingDelay(@Qualifier("queueDelay30s") Queue queue,
  88. @Qualifier("exchangeDelay") DirectExchange exchange,
  89. @Value("${atf.routingkey.delay.30s}") String routingKey) {
  90. return BindingBuilder.bind(queue).to(exchange).with(routingKey);
  91. }

  92. /**
  93. * 绑定死信交换器DLX和死信队列DLQ
  94. *
  95. * @param queue
  96. * @param exchange
  97. * @param routingKey
  98. * @return
  99. */
  100. @Bean
  101. public Binding bindingDelayConsume(@Qualifier("queueDelayDlq") Queue queue,
  102. @Qualifier("exchangeDelayDlx") DirectExchange exchange,
  103. @Value("${atf.routingkey.delay.dlk}") String routingKey) {
  104. return BindingBuilder.bind(queue).to(exchange).with(routingKey);
  105. }
  106. }
  1. public void sendDelay(AtfEventPayload payload) {
  2. rabbitTemplate.convertAndSend( "atf.exchange.delay", "atf.routingkey.delay.30s", payload);
  3. }
  1. @RabbitListener(queues = "atf.queue.delay.dlq", containerFactory = "rabbitListenerContainerFactory")
  2. public void consumeDelay(AtfEventPayload payload) {
  3. try {
  4. AtWorkflow workflow = workflowSvs.find(payload.getWorkflowName());
  5. workflowSvs.execute(workflow, null);
  6. } catch (Exception e) {
  7. e.printStackTrace();
  8. }
  9. }

像支付宝,微信支付后的回调机制,可以使用延迟队列实现。可是创建延时不同时间的队列,死信后被消费,消费异常后,消息进入不同的队列。

/**
 * 默认及时消息交换机
 * @return
 */
@Bean()
public DirectExchange defaultDirectExchange() {
    return new DirectExchange(MessageQueueConstants.DEFAULT_DIRECT_EXCHANGE_NAME, true, false);
}

/**
 * 默认延迟消息死信队列
 * @return
 */
@Bean
public Queue defaultDeadLetterQueue10() {
    Map<String, Object> arguments = new HashMap<>();
    arguments.put("x-dead-letter-exchange",MessageQueueConstants.DEFAULT_DIRECT_EXCHANGE_NAME);//设置交换机路由
    arguments.put("x-dead-letter-routing-key", MessageQueueConstants.DEFAULT_REPEAT_TRADE_QUEUE_NAME);//设置转发队列名称
    arguments.put("x-message-ttl", 10 * 1000); // Message TTL = 10s
    Queue queue = new Queue(MessageQueueConstants.DEFAULT_DEAD_LETTER_QUEUE_NAME10,true,false,false,arguments);
    return queue;
}

/**
 * 默认延迟消息死信队列
 * @return
 */
@Bean
public Queue defaultDeadLetterQueue30() {
    Map<String, Object> arguments = new HashMap<>();
    arguments.put("x-dead-letter-exchange",MessageQueueConstants.DEFAULT_DIRECT_EXCHANGE_NAME);//设置交换机路由
    arguments.put("x-dead-letter-routing-key", MessageQueueConstants.DEFAULT_REPEAT_TRADE_QUEUE_NAME);//设置转发队列名称
    arguments.put("x-message-ttl", 30 * 1000); // Message TTL = 30s
    Queue queue = new Queue(MessageQueueConstants.DEFAULT_DEAD_LETTER_QUEUE_NAME30,true,false,false,arguments);
    return queue;
}

/**
 * 默认延迟消息死信队列
 * @return
 */
@Bean
public Queue defaultDeadLetterQueue180() {
    Map<String, Object> arguments = new HashMap<>();
    arguments.put("x-dead-letter-exchange",MessageQueueConstants.DEFAULT_DIRECT_EXCHANGE_NAME);//设置交换机路由
    arguments.put("x-dead-letter-routing-key", MessageQueueConstants.DEFAULT_REPEAT_TRADE_QUEUE_NAME);//设置转发队列名称
    arguments.put("x-message-ttl", 1000*60*3); // Message TTL = 180s
    Queue queue = new Queue(MessageQueueConstants.DEFAULT_DEAD_LETTER_QUEUE_NAME180,true,false,false,arguments);
    return queue;
}

/**
 * 默认延迟消息死信队列
 * @return
 */
@Bean
public Queue defaultDeadLetterQueue1200() {
    Map<String, Object> arguments = new HashMap<>();
    arguments.put("x-dead-letter-exchange",MessageQueueConstants.DEFAULT_DIRECT_EXCHANGE_NAME);//设置交换机路由
    arguments.put("x-dead-letter-routing-key", MessageQueueConstants.DEFAULT_REPEAT_TRADE_QUEUE_NAME);//设置转发队列名称
    arguments.put("x-message-ttl", 1000*60*20); // Message TTL = 1200s
    Queue queue = new Queue(MessageQueueConstants.DEFAULT_DEAD_LETTER_QUEUE_NAME1200,true,false,false,arguments);
    return queue;
}

/**
 * 默认延迟消息死信队列
 * @return
 */
@Bean
public Queue defaultDeadLetterQueue3600() {
    Map<String, Object> arguments = new HashMap<>();
    arguments.put("x-dead-letter-exchange",MessageQueueConstants.DEFAULT_DIRECT_EXCHANGE_NAME);//设置交换机路由
    arguments.put("x-dead-letter-routing-key", MessageQueueConstants.DEFAULT_REPEAT_TRADE_QUEUE_NAME);//设置转发队列名称
    arguments.put("x-message-ttl", 1000*60*60); // Message TTL = 3600s
    Queue queue = new Queue(MessageQueueConstants.DEFAULT_DEAD_LETTER_QUEUE_NAME3600,true,false,false,arguments);
    return queue;
}

@Bean
public Binding  defaultDeadLetterBinding10() {
    Binding bind = BindingBuilder.bind(defaultDeadLetterQueue10()).to(defaultDirectExchange()).with(MessageQueueConstants.DEFAULT_DEAD_LETTER_QUEUE_NAME10);
    return bind;
}
@Bean
public Binding  defaultDeadLetterBinding30() {
    Binding bind = BindingBuilder.bind(defaultDeadLetterQueue30()).to(defaultDirectExchange()).with(MessageQueueConstants.DEFAULT_DEAD_LETTER_QUEUE_NAME30);
    return bind;
}
@Bean
public Binding  defaultDeadLetterBinding180() {
    Binding bind = BindingBuilder.bind(defaultDeadLetterQueue180()).to(defaultDirectExchange()).with(MessageQueueConstants.DEFAULT_DEAD_LETTER_QUEUE_NAME180);
    return bind;
}
@Bean
public Binding  defaultDeadLetterBinding1200() {
    Binding bind = BindingBuilder.bind(defaultDeadLetterQueue1200()).to(defaultDirectExchange()).with(MessageQueueConstants.DEFAULT_DEAD_LETTER_QUEUE_NAME1200);
    return bind;
}
@Bean
public Binding  defaultDeadLetterBinding3600() {
    Binding bind = BindingBuilder.bind(defaultDeadLetterQueue3600()).to(defaultDirectExchange()).with(MessageQueueConstants.DEFAULT_DEAD_LETTER_QUEUE_NAME3600);
    return bind;
}


/**
 * 默认延迟消息死信接受转发消息队列
 * @return
 */
@Bean
public Queue defaultRepeatTradeQueue() {
    Queue queue = new Queue(MessageQueueConstants.DEFAULT_REPEAT_TRADE_QUEUE_NAME,true,false,false);
    return queue;
}


@Bean
public Binding  defaultRepeatTradeBinding() {
    return BindingBuilder.bind(defaultRepeatTradeQueue()).to(defaultDirectExchange()).with(MessageQueueConstants.DEFAULT_REPEAT_TRADE_QUEUE_NAME);
}


猜你喜欢

转载自blog.csdn.net/qq_29663071/article/details/80893342