队列

死信

1、无法被消费的消息

(1)producer 将消息投递到 broker 或直接到 queue,consumer 从 queue 取出消息进行消费,但由于特定的原因导致 queue 中的某些消息

(2)死信队列:没有被及时消费的消息存放的队列

2、应用场景:当消息消费发生异常时,将消息投入死信队列中,保证消息数据不丢失

3、来源

(1)消息 TTL 过期

(2)队列达到最大长度,队列已满,无法再添加数据到 MQ 中

(3)消息被拒绝,basic.reject 或 basic.nack 并且 requeue=false

4、正常队列绑定死信队列信息

(1)设置 queueDeclare 中的 Map<String,Object> arguments

key(String) value(Object)
x-dead-letter-exchange 死信交换机的名称
x-dead-letter-routing-key 死信交换机的 routingKey

(2)正常队列产生的死信,转入到配置的死信队列

5、消息 TTL

(1)在推送消息时设置

(2)basicPublish 中的 AMQP.BasicProperties props

public BasicProperties()
public AMQP.BasicProperties.Builder builder()
public AMQP.BasicProperties.Builder expiration(String expiration)
public AMQP.BasicProperties build()

(3)单位:毫秒

(4)例

byte[] messageBodyBytes = "Hello, world!".getBytes();
AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
    .expiration("60000")
    .build();
channel.basicPublish("my-exchange", "routing-key", properties, messageBodyBytes);

6、队列最大长度

(1)在声明队列时设置

(2)queueDeclare 中的 Map<String,Object> arguments

key(String) value(Object)
max-length-bytes 队列最大字节长度
max-length 队列最大消息个数

 

延迟队列

1、队列内部有序

2、队列中的元素希望到达指定时间,以后或之前取出和处理

3、队列用来存放,需要在指定时间被处理的元素

4、应用场景:需要在某个事件发生之后,或之前的指定时间点,完成某一项任务

 

TTL

1、TTL 是 RabbitMQ 中一个消息或队列的属性,表明一条消息或该队列中的所有消息的最大存活时间

2、单位:毫秒

3、如果一条消息设置 TTL 属性,或进入设置 TTL 属性的队列,在 TTL 设置的时间内,没有被消费,则会成为死信

4、如果同时配置队列的 TTL、消息的 TTL,则较小值将会被使用,有两种方式设置 TTL

5、单个消息 TTL

(1)在推送消息时设置

(2)basicPublish 中的 AMQP.BasicProperties props

public BasicProperties()
public AMQP.BasicProperties.Builder builder()
public AMQP.BasicProperties.Builder expiration(String expiration)
public AMQP.BasicProperties build()

(3)单位:毫秒

(4)例

byte[] messageBodyBytes = "Hello, world!".getBytes();
AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
    .expiration("60000")
    .build();
channel.basicPublish("my-exchange", "routing-key", properties, messageBodyBytes);

6、队列消息 TTL

(1)在声明队列时设置

(2)queueDeclare 中的 Map<String,Object> arguments

key(String) value(Object)
x-message-ttl 单位:毫秒

(3)注意:x-expires 设置队列 TTL,到期队列自动删除,单位为毫秒

7、事项

(1)如果设置 TTL 属性,一旦消息过期,就会被队列丢弃

(2)如果配置死信队列,则被丢弃到死信队列中

(3)单个消息 TTL:消息即使过期,不一定会被马上丢弃

(4)判断消息是否过期的时机:在即将投递到消费者之前,即只判断最顶端消息

(5)如果当前队列有严重的消息积压情况,则已过期的消息可能存活较长时间

(6)如果不设置 TTL,表示消息永远不会过期

(7)如果将 TTL 设置为 0,则表示除非此时可以直接投递该消息到消费者,否则该消息将会被丢弃

 

延迟队列实现

1、思路:TTL + 死信队列

2、实现一:SpringBoot 整合 RabbitMQ

(1)队列消息 TTL:因为消息都为固定的过期时间,不存在 TTL 到期,但不丢弃过期消息的问题

(2)单个消息 TTL:因为只检查队列第一个消息的 TTL,若在同一队列,不同 TTL 消息过期,可能不丢弃过期消息

3、实现二:rabbitmq_delayed_message_exchange

(1)一个向 RabbitMQ 添加延迟消息(或预定消息)的插件

(2)第三方插件需要额外安装,将 .ez 文件拷贝到安装的插件目录(默认:/usr/lib/rabbitmq/lib/rabbitmq_server-{version}/plugins)

(3)开启插件

rabbitmq-plugins enable rabbitmq_delayed_message_exchange

(4)重启 RabbitMQ

(5)新增交换机类型:x-delayed-message

(6)该类型消息支持延迟投递机制,消息传递后并不会立即投递到目标队列中,而是存储在 mnesia 表(一个分布式数据系统)中,当达到投递时间时,才投递到目标队列中

4、优点

(1)消息可靠发送、消息可靠投递、死信队列,保障消息至少被消费一次,以及未被正确处理的消息不会被丢弃

(2)通过 RabbitMQ 集群,解决单点故障问题,不会因为单个节点挂掉,导致延时队列不可用或消息丢失

5、其他实现

(1)Java 的 DelayQueue

(2)Redis 的 zset

(3)Quartz

(4)Kafka 时间轮

 

优先级队列

1、概述

(1)从 3.5.0 开始,RabbitMQ 在核心中实现优先级队列

(1)任何队列都可以使用客户端提供的可选参数变成优先级队列,但与使用可选参数的其他功能不同,不能使用策略

(3)该实现支持有限数量的优先级:255,建议使用 1 到 10 之间的值

2、使用客户端提供的可选参数

(1)设置队列优先级,queueDeclare 中的 Map<String,Object> arguments

key(String) value(Object)
x-max-priority 队列支持的最大优先级:1 ~ 255

(2)生产者使用 basic.properties 的 properties 字段,推送经过优先级处理的消息,数字越大,优先级越高

(3)设计上不支持使用策略来声明优先级

3、行为

(1)RabbitMQ 队列默认不支持优先级

(2)每个队列的每个优先级都有一些内存和磁盘上的成本,还有一个额外的 CPU 成本

(3)消息的优先级字段被定义为一个无符号 byte,所以在开发中优先级应该在 0 到 255 之间

(4)没有优先级属性的消息,会被视为其优先级为 0

(5)优先级高于队列最大值的消息,会被视为以最大优先级发布

4、优先权的最大数量和资源使用

(1)如果需要优先级队列,建议使用 1 到 10 个

(2)目前使用更多的优先级将,通过使用更多的 Erlang 进程,消耗更多的 CPU 资源,运行时的调度也会受到影响

5、与消费者的互动

(1)默认情况下,消费者在确认任何消息之前可能会被发送大量的消息,只受网络背压(Backpressurr)限制

(2)如果一个饥饿的消费者连接到一个空的队列,随后消息被发布到该队列,消息可能根本不会在队列中花费任何时间等待,在这种情况下,优先级队列将没有任何机会对消息进行优先排序

(3)在大多数情况下,需要在消费者上使用手动确认模式的 basic.qos 方法,在任何时候限制交付消息的数量,从而允许消息被优先处理

6、与其他功能的相互作用

(1)一般来说,优先级队列具有标准 RabbitMQ 队列的所有功能:持久性、分页、镜像等

(2)应该过期的消息仍将只从队列的头部过期,每个队列的 TTL 也会导致过期的低优先级消息,被卡在未过期的高优先级消息后面,这些消息永远不会被送达,但它们会出现在队列统计中

(3)设置最大长度的队列,从队列的头部丢弃消息以执行限制,这意味着较高优先级的消息可能被丢弃,为较低优先级的消息让路

7、为什么不支持策略定义

(1)为队列定义可选参数的最方便方式是通过策略,策略是配置 TTL、队列长度限制、其他可选的队列参数的推荐方式

(2)但是,策略不能用于配置优先级,因为策略是动态的,可以在队列声明后改变

(3)优先级队列在队列声明后,永远不能改变它们支持的优先级数量,所以策略不会是一个安全的选择

8、实现优先级所需

(1)队列需要设置为优先级队列

(2)消息需要设置消息的优先级

(3)消息需要发送到队列中进行排序,消费者才能消费消息

 

惰性队列

1、概述

(1)RabbitMQ 从 3.6.0 版本开始引入惰性队列

(2)经典队列可在懒惰模式下运行:尽可能早地将其内容移至磁盘,并仅在消费者要求时,才将其加载到 RAM 中

(3)主要目标之一:能够支持很长的队列(数百万条消息),即支持更多的消息存储

(4)产生长队列原因:消费者脱机 / 崩溃 / 停机维护;突然出现消息高峰,生产者超过消费者;消费者的速度比平时慢

(5)默认情况下,当生产者发送消息到 RabbitMQ 时,队列中的消息会尽可能的存储在内存之中,这样可以更加快速地将消息发送给消费者

(6)注意:持久化消息可以在进入 RabbitMQ 时被写入磁盘,并同时保存在 RAM 中

(7)当 RabbitMQ 需要释放内存时,会将内存中的消息换页至磁盘中,这个操作会耗费较长的时间,也会阻塞队列的操作,进而无法接收新的消息

(8)尽管 RabbitMQ 的最新版本改进分页算法,但对于队列中有数百万条可能需要分页的消息的情况来说,这种情况仍然不理想

(9)懒惰队列试图尽可能早地将消息转移到磁盘,这意味着在大多数情况下,在正常操作下,保留在 RAM 中的消息明显减少,这是以增加磁盘 I/O 为代价的

2、在声明时使用参数

(1)queueDeclare 中的 Map<String,Object> arguments

key(String) value(Object)
x-queue-mode default / lazy

(2)如果在声明时没有指定模式,那么就假定为 default,default 在 3.6.0 以前版本的 Broker 中的行为

(3)当策略、队列参数,同时指定队列模式时,队列参数的优先级高于策略值

(4)如果在声明时通过一个可选的参数设置了队列模式,那么只能通过删除队列,并在以后用不同的参数重新声明来改变它

posted @   半条咸鱼  阅读(84)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示