rabbitmq实现延迟队列
延迟队列串存储的对象是对应的延迟消息。rabbitmq本身没有支持延迟队列的功能,通过DLX(死信队列)+TTL消息模拟延迟队列
延迟消息是指消息被发送以后,并不想让消费者立刻拿到消息,而是等待特定时间后,消费者才能拿到消息并消费
延迟队列场景
- 订单系统中,如果用户下单30分钟内没有进行支付,就需要自动将这些订单设置为失效
- 支付结果通知,为1分钟,5分钟,10分钟…的通知
示例
场景描述
设置了5s,10s,30s三个等级的通知队列,同时为这些队列设置了DLX各DLX相对应的死信队列。当相应的消息过期时,就会转到相应对的延迟队列(死信队列)
延迟队列实现图
延迟队列示例图:
代码实现
public class DelayedQueueSender {
private static final String EX_NORMAL = "EX_NORMAL";
private static final String EX_DLX_5S = "EX_DLX_5S";
private static final String EX_DLX_10S = "EX_DLX_10S";
private static final String EX_DLX_30S = "EX_DLX_30S";
private static final String Q_NORMAL_5S = "Q_NORMAL_5S";
private static final String Q_NORMAL_10S = "Q_NORMAL_10S";
private static final String Q_NORMAL_30S = "Q_NORMAL_30S";
private static final String Q_DLX_5S = "Q_DLX_5S";
private static final String Q_DLX_10S = "Q_DLX_10S";
private static final String Q_DLX_30S = "Q_DLX_30S";
private static final String RT_NORMAL = "RT_NORMAL";
private static final String RT_DLX_5S = "RT_DLX_5S";
private static final String RT_DLX_10S = "RT_DLX_10S";
private static final String RT_DLX_30S = "RT_DLX_30S";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
factory.setHost("localhost");
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.exchangeDeclare(EX_NORMAL, BuiltinExchangeType.FANOUT);
channel.exchangeDeclare(EX_DLX_5S, BuiltinExchangeType.DIRECT);
channel.exchangeDeclare(EX_DLX_10S, BuiltinExchangeType.DIRECT);
channel.exchangeDeclare(EX_DLX_30S, BuiltinExchangeType.DIRECT);
Map<String, Object> map5s = new HashMap<>();
map5s.put("x-message-ttl", 5000);
map5s.put("x-dead-letter-exchange", EX_DLX_5S);
map5s.put("x-dead-letter-routing-key", RT_DLX_5S);
channel.queueDeclare(Q_NORMAL_5S, true, false, false, map5s);
channel.queueBind(Q_NORMAL_5S, EX_NORMAL, "");
Map<String, Object> map10s = new HashMap<>();
map10s.put("x-message-ttl", 10000);
map10s.put("x-dead-letter-exchange", EX_DLX_10S);
map10s.put("x-dead-letter-routing-key", RT_DLX_10S);
channel.queueDeclare(Q_NORMAL_10S, true, false, false, map10s);
channel.queueBind(Q_NORMAL_10S, EX_NORMAL, "");
Map<String, Object> map30s = new HashMap<>();
map30s.put("x-message-ttl", 30000);
map30s.put("x-dead-letter-exchange", EX_DLX_30S);
map30s.put("x-dead-letter-routing-key", RT_DLX_30S);
channel.queueDeclare(Q_NORMAL_30S, true, false, false, map30s);
channel.queueBind(Q_NORMAL_30S, EX_NORMAL, "");
//死信队列
channel.queueDeclare(Q_DLX_5S, true, false, false, null);
channel.queueBind(Q_DLX_5S, EX_DLX_5S, RT_DLX_5S);
channel.queueDeclare(Q_DLX_10S, true, false, false, null);
channel.queueBind(Q_DLX_10S, EX_DLX_10S, RT_DLX_10S);
channel.queueDeclare(Q_DLX_30S, true, false, false, null);
channel.queueBind(Q_DLX_30S, EX_DLX_30S, RT_DLX_30S);
channel.basicPublish(EX_NORMAL, RT_NORMAL, null, "5s_hello".getBytes());
System.out.println("send msg...");
}
}
从Web管理页面看:
消息示过期前先发送到normal队列:
10s之后:
消息过期后发送到延迟队列: