ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【RabbitMQ 笔记】— 死信队列

2022-06-09 13:33:54  阅读:158  来源: 互联网

标签:队列 RabbitMQ 过期 死信 消息 DLX channel


死信交换器,Dead Letter Exchange,下文简称 DLX。当消息在一个队列中变成死信(Dead Letter)之后,它会被发送到另一个交换器中,这个交换器就是 DLX,绑定 DLX 的队列就称为死信队列。

消息变成死信一般由以下几种情况:

  • 消息被拒绝(Basic.Reject / Basic.Nack),并且设置 requeue 参数为 false
  • 消息过期
  • 队列长度达到最大值

那就先聊聊过期时间

过期时间(TTL)

TTL,全称 time to live。RabbitMQ 里分为消息的过期时间和队列的过期时间

消息的 TTL

有两种方式可以设置消息的过期时间

  • 通过队列的属性设置,这样的话队列中所有的消息过期时间一致。设置方法是在 channel.queueDeclare 方法中加入 x-message-ttl 参数实现,单位毫秒。如果不设置 TTL,则表示消息不会过期;如果设置为 0, 除非此时消息可以立即投递给消费者,否则消息会被丢失。
  • 每个消息单独设置,设置方法为在 channel.basicPublish 方法中加入 expiration 属性参数,单位毫秒。
  • 如果上面两种都设置了,那么以小的为准。消息在队列中生存时间超过了 TTL 值时,就会变成死信(Dead Letter)。

其实上面两种设置过期时间的方式判定消息是否过期的逻辑也是不一样的,区别如下

  • 通过队列的方式,队列中消息的过期时间都是一样的,已过期的消息肯定在队列的头部,那么 RabbitMQ 只用定期从队头开始扫描看是否有消息过期即可
  • 消息单独设置,每个消息的过期时间不同,如果要删除所有过期消息势必要扫描整个队列,所以不如等到消息消费时再判定是否过期,如果过期删除即可。

队列的 TTL

可以通过 channel.queueDeclare 方法中 x-expires 参数(单位毫秒,不能设置为 0)可以可控制队列被自动删除前未使用状态的时间。未使用定义如下:

  • 队列上没有任何消费者
  • 队列也没有被重新声明
  • 过期时间段内没有调用过 Basic.Get 命令

死信队列

DLX 也是个普通的交换器,和一般的交换器没有区别。当一个队列存在死信时,RabbitMQ 会把消息发送给 DLX,进而被路由到另一个队列,这个队列就是死信队列。然后可以监听这个队列中的消息进行相应的处理。这个特性与将消息的 TTL 设置为 0 配合使用可以弥补 immediate 参数的功能。

通过 channel.queueDeclare 方法中设置 x-dead-letter-exchange 参数来为队列添加 DLX。也可以为这个 DLX 指定路由键,设置 x-dead-letter-routing-key 参数指定。如果没有指定,则使用原队列的路由键。

具体代码如下

try(Connection connection = ConnectionUtil.getConnection()) {
    Channel channel = connection.createChannel();
    // 创建死信交换器, 死信队列
    channel.exchangeDeclare(DLX, BuiltinExchangeType.FANOUT.getType(), true, false, null);
    channel.queueDeclare(DLX_QUEUE, true, false, false, null);
    channel.queueBind(DLX_QUEUE, DLX, "");
    // 创建 normalExchange
    channel.exchangeDeclare(NORMAL_EXCHANGE, BuiltinExchangeType.DIRECT.getType(), true, false, null);
    Map<String, Object> args = new HashMap<>(2);
    args.put("x-message-ttl", EXPIRE_TIME); // 设置队列消息的过期时间
    args.put("x-dead-letter-exchange", DLX); // 为队列添加死信交换器
    channel.queueDeclare(NORMAL_QUEUE, true, false, false, args);
    channel.queueBind(NORMAL_QUEUE, NORMAL_EXCHANGE, ROUTING_KEY);
    // 发送消息
    byte[] bytes = "dlx message coming!".getBytes();
    channel.basicPublish(NORMAL_EXCHANGE, ROUTING_KEY, MessageProperties.PERSISTENT_TEXT_PLAIN, bytes);
} catch (IOException e) {
    e.printStackTrace();
}

上述代码示意图如下
image

对于 RabbitMQ 来说,DLX 是个很有用的特性,他可以处理异常情况下,消息不能够正常消费(消费者调用了 Basic.Nac 或者 Basic.reject)而被置入死信队列的情况,后续分析程序可以通过消费这个死信队列中的内容来分析当时遇到的异常情况,进而可以进一步优化。另外,DLX 配合 TTL 还可以实现延时队列的功能。

参考

《RabbitMQ实战指南》

标签:队列,RabbitMQ,过期,死信,消息,DLX,channel
来源: https://www.cnblogs.com/tailife/p/16358952.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有