设为首页 加入收藏

TOP

RabbitMQ 第4章
2019-05-11 02:32:00 】 浏览:50
Tags:RabbitMQ

mandatory 以及 immediate 是 channel,basicPublish方法中的两个参数

他们具有 当消息不可达MQ时,将消息返回生产者的功能

如未能被交换机路由的消息(无绑定队列 或 无匹配的绑定)存储在备份交换机绑定的队列中。

1mandatory

为false时,如生产者生产的消息无法路由到队列,直接丢弃

为true时,将消息返回给生产者,而生产者通过调用channel.addReturnListener添加ReturnListener监听器实现。

2 immediate

为true时,匹配的队列都无消费者时将该消息返回给生产者。

新版本的兔子MQ去掉了对immediate的支持。可以通过TTL以及DLX进行实现

3 备胎交换机

在声明交换机时,将其中一个交换机声明为备胎交换机。

如不想实现mandatory 的ReturnListener监听器,可以使用 备胎交换机,将无法路由到队列的消息存储在备胎交换机的队列内,需要的时候进行消费备胎交换机中的消息。

备胎交换机一般采用fanout交换机,忽略bindKey,保证所有rountingKey的消息都能存储进来。

当备胎交换机与mandatory同时使用时mandatory参数无效。

TTL: 过期时间

过期时间分为两种:

1 队列中消息的统一过期时间

2 消息的过期时间

如果两者同时存在,则小的值有效。

过期后消息会进入死信队列中。

清除过期消息:

1 对于队列过期消息,即时清除过期消息。因为队列为先进先出队列,即将过期的消息在队列头部。只从头向后遍历一部分头部队列即可,无需全队列遍历。

2 对于消息过期,采用懒过期策略。在消费消息的时候,检查消息是否过期,如过期将其转移到死信队列,而不会发送给消费者。采用懒过期策略对MQ的CPU友好,避免全队列扫描。类似于Redis的过期策略

队列过期TTL:达到TTL后,将队列删除,对于持久化队列,TTL重新计算,不会删除。不能保证实时性。

死信队列:

1 消息被拒绝,且设置requeue参数为false

2 消息过期

3 队列达到最大长度

死信队列与TTL设置为0 进行配合弥补 immediate 的功能

死信队列可用于:

1 恢复异常场景:消费者消费不了,消息被拒绝

2 延迟队列

延迟队列:

消费者只能在t时间后消费到此消息

队列消息ttl设置时间为t。过期后,消息会进入死信队列。消费者接受死信队列的消息推送即可。

优先级队列:

优先级高的消息具有优先被消费到权利。通过设置x-max-priority参数进行实现。

在发送消息的时候对消息的优先级进行设置。

消息的持久化:

防止消息在服务器异常的情况下数据丢失。

分为

1 交换机的持久化

2 队列的持久化

3 消息的持久化

交换机的持久化:声明交换机时,将durable参数设置为true实现

当服务器重启后,如果交换机未能持久化,将会导致消费者不能给交换机发送消息。长期使用的交换机应该进行持久化

队列持久化:声明队列时,将durable参数设置为true实现

服务器重启后,如果队列未进行持久化,会导致队列中的数据丢失,队列也将不会存在

消息的持久化:投递消息时,将投递模式deliveryMode设置为2实现持久化

将消息进行持久化后会很大程度上影响MQ的吞吐量。需要在可靠性与吞吐量上进行权衡

如何保证消息不会丢失:

1 消费者: 当消息消费成功后进行手动ack,确保消息不会在消费者方丢失

2 设置为需持久化的消息存入兔子MQ后,不可能立即持久化到硬盘,(持久化应该是基于 时间及数目 批量写磁盘的 来保证服务器的吞吐量)如此时兔子MQ出现宕机,则消息会在服务端丢失。

解决问题2:

方法一:此时可以使用镜像队列解决此问题。从服务器保存主服务器队列的副本,主服务器宕机,从服务数据起作用

方法二:实现生产者确认机制

生产者确认机制:

1 事物机制,如发送失败回滚,吞吐量极其低,不建议使用

a设置 b提交 c确认/回滚

生产者线程会阻塞直到返回结果

2 发送方确认机制

生产者将信道设置为confirm模式

1 持久化消息,消息在写入磁盘之后 将消息id以及ack发送给生产者

2 非持久化消息,消息在写入队列后发送ack给生产者

同步阻塞:等到MQ返回结果后才执行之后的逻辑,性能差

优化:

1 批量确认机制:发送一批消息后,调用获取处理结果的方法

缺点:在出错(返回nack或超时)率较高时,性能会反而更差,批量再重发

2 异步回调机制:使用回调机制,将返回的结果(发送成功or失败)交给回调函数进行处理。性能大幅度提高

优点:性能极好

缺点:实现复杂度高

调用channel的 addConfirmListener方法 添加 ConfirmListener这个回调接口

ConfirmListener接口由两个方法:

handleAck: 处理消息确认成功逻辑

handleNack: 处理消息确认失败逻辑

消费者需要维护一个unconfirm集合(SortedSet数据结构)。

调用一次handleAck 删除对应的一条记录

消费者端要点:

手动ack取代自动ack

如果程序无法处理消息,将消息reject

消息消费负载均衡采用round-robin算法实现。当消息堆积时,增加消费者数目即可。

问题:有些消息消费的快,有些消费的慢。

消费者A: 消费一条 10ms

消费者B: 消费一条 10min

采用round-Robin将会给消费者b造成很大压力。

此时我们需要设置消费者所持有的最大的消息数目来解决此问题。限制消费者同一时刻未确认的消息的数目。

Rabbit会保存消费者列表,并记录发送给消费者但未ack的消息的数目。

建议只对单个消费者设置其可持有的未消费的消息上线。不建议将其与所有消费者之和消息个数上线一期使用,会降低MQ吞吐量。

兔子MQ 无法保证顺序性

1 生产者消息发送失败补偿发送导致消息错序

2 优先队列打破顺序性

3 多消费者消费同一队列打破顺序性

使用mq尽量避免有序 如需要有序必然带来吞吐量大幅度降低

消息堆积问题:

服务端消息堆积:采用增加消费者进行解决

消费端消息堆积:消费者用LinkedBlockingQueue保存未来得及消费的消息,当消息过多 导致out of memory

所以必须限制服务端发送给消费者还未ack的消息的数目。

消息传输保障:

消息类型可分为以下三中类型:

1 最多消费一次 :最简单,对三端无限制

2 最少消费一次 :

生产者进行异步确认,保证消息传入到MQ中

MQ 使用mandatory参数或者备胎交换机,确保路由不到队列时消息不丢失

MQ 对消息和队列进行持久化,保证重启后消息不丢失

消费端使用手动ack进行确认

3 仅可消费一次

除2外 业务层还要增加全局唯一id,保证消息幂等

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇浅析Java中的final关键字 下一篇docker入门命令教程

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目