发布确认

处理无法投递的消息

1、假设:RabbitMQ 集群不可用

2、RabbitMQ 重启期间,生产者消息投递失败,导致消息丢失,需要手动处理和恢复

 

消息的可靠投递

1、在使用 RabbitMQ 时,作为消息发送方,希望杜绝任何消息丢失,或者投递失败场景

2、RabbitMQ 提供两种方式,控制消息的投递可靠性模式

(1)confirm:确认模式

(2)return:退回模式

3、RabbitMQ 整个消息投递的路径:producer -> rabbitmq broker -> exchange -> queue -> consumer

(1)消息从 producer -> exchange,则会返回一个 confirmCallback

(2)消息从 exchange -> queue 投递失败则会返回一个 returnCallback

4、设置 ConnectionFactory 的 publisher-confirms=true,开启确认模式

(1)使用 rabbitTemplate.setConfirmCallback 设置回调函数

(2)当消息发送到 exchange 后,回调 confirm 方法:在方法中判断 ack,如果为 true,则发送成功,如果为 false,则发送失败,需要处理

5、设置 ConnectionFactory 的 publisher-returns=true,开启退回模式

(1)使用 rabbitTemplate.setReturnCallback 设置退回函数

(2)当消息从 exchange 路由到 queue 失败后,如果设置 rabbitTemplate.setMandatory(true),则会将消息退回到 producer,并执行回调函数 returnedMessage

6、在 RabbitMQ 中提供事务机制,但是性能较差

 

原理

1、生产者将 Channel 设置成 confirm 模式

(1)所有在该信道上发布的消息,都将会被指派一个唯一的 ID(从 1 开始)

(2)消息被投递到所有匹配的队列之后,Broker 就会发送一个确认给生产者(包含消息的唯一 ID),使得生产者知道消息已经正确到达目的队列

(3)如果消息、队列是可持久化的,那么确认消息会在将消息写入磁盘之后发出

(4)Broker 回传给生产者的确认消息中,delivery-tag 域包含确认消息的序列号

(5)Broker 可以设置 basic.ack 的 multiple 域,表示到这个序列号之前的所有消息都已经得到了处理

2、confirm 模式最大优点:异步

(1)一旦发布一条消息,生产者就可以在等信道返回确认的同时,继续发送下一条消息

(2)当消息最终得到确认之后,生产者便可以通过回调方法来处理该确认消息

 

策略

1、发布确认默认不开启

2、启用该 Channel 上的发布确认

AMQP.Confirm.SelectOk confirmSelect() throws IOException

(1)每当要想使用发布确认,都需要在 Channel 上调用该方法

3、单个确认发布

(1)一种同步确认发布的方式

(2)发布一个消息之后,只有它被确认发布,后续的消息才能继续发布

(3)缺点:发布速度最慢,最多提供每秒不超过数百条发布消息的吞吐量

4、等待,直到自上次调用以来发布的所有消息,都被 Broker ack 或 nack

void waitForConfirmsOrDie() throws IOException, InterruptedException

(1)如果任何消息被拒绝,将抛出一个 IOException

(2)当在一个非确认通道上调用时,将抛出一个 IllegalStateException

5、等待,直到自上次调用以来发布的所有消息,都被 Broker ack 或 nack,或直到超时结束

void waitForConfirmsOrDie(long timeout) throws IOException, InterruptedException, TimeoutException

(1)如果超时后,会抛出一个 TimeoutException

(2)如果有任何消息被 nack,将抛出一个 IOException

(3)当在一个非确认通道上调用时,将抛出一个 IllegalStateException

6、批量确认发布

(1)同步确认,阻塞消息的发布

(2)先发布一批消息,然后一起确认

(3)缺点:当发生故障导致发布出现问题时,不能确定哪个消息出现问题,必须将整个批处理保存在内存中,以记录重要的信息然后重新发布消息

7、异步确认发布 

(1)编程逻辑复杂,可靠性、效率都最高

(2)利用回调函数,传递消息可靠性

(3)实现:未确认的消息存放到一个基于内存的、能被发布线程访问的队列,如:ConcurrentLinkedQueue,在 Broker 回调、发布线程之间传递消息

 

交换机确认回调

1、生产者设置 RabbitTemplate.ConfirmCallback(回调接口)实现类

public void setConfirmCallback(RabbitTemplate.ConfirmCallback confirmCallback)

2、 一个用于对生产者确认的回调接口

@FunctionalInterface
public static interface RabbitTemplate.ConfirmCallback

3、交换机对生产者的确认回调

void confirm​(@Nullable
    CorrelationData correlationData,
    boolean ack,
    @Nullable
    String cause)

(1)correlationData:回调的相关数据

(2)ack:ack为 true,nack 为 false

(3)cause:nack 的原因(可选),否则为 null

(4)不管交换机是否收到消息,都会回调

4、配置文件需要添加:spring.rabbitmq.publisher-confirm-type

(1)(none):不添加,禁用发布确认模式,默认值

(2)correlated:发布消息,成功到达交换器后,触发回调方法

(3)simple:发布消息,成功到达交换器后,触发回调方法,并使用 RabbitTemplate 调用 waitForConfirms 或 waitForConfirmsOrDie,等待 Broker 节点返回发送结果,根据返回结果来判定下一步逻辑,即同步确认

(4)注意:waitForConfirmsOrDie 如果返回 false,则会关闭 Channel,则接下来无法发送消息到 Broker

 

队列回退消息

1、Mandatory

(1)仅开启生产者确认机制的情况下,交换机接收到消息后,会直接给消息生产者发送确认消息,如果发现该消息不可路由,那么消息会被直接丢弃,此时生产者不能获知该消息被丢弃

(2)设置 mandatory 参数,可以在当消息传递过程中,不可达目的地时,将消息返回给生产者

2、在发送消息时设置强制标志

public void setMandatory(boolean mandatory)

(1)mandatory:是否开启消息退回

(2)只适用于提供 returnCallback 的情况

3、生产者设置一个回调,以接收返回的信息

public void setReturnsCallback(RabbitTemplate.ReturnsCallback returnCallback)

(1)设置 RabbitTemplate.ReturnsCallback(回调函数)实现类

4、返回消息的回调接口

@FunctionalInterface
public static interface RabbitTemplate.ReturnsCallback extends RabbitTemplate.ReturnCallback

5、交换机无法路由时,返回消息到生产者的回调

void returnedMessage​(ReturnedMessage returned)

6、mandatory 为 true 时

(1)回退消息,在生产者的消息无法被投递时,发现并处理

(2)处理:打印日志,触发报警,手动处理

(3)缺点:当生产者所在的服务有多台机器时,手动复制日志更加麻烦且容易出错;设置 mandatory 参数会增加生产者的复杂性,需要添加处理这些被退回的消息的逻辑

7、当已发布的消息无法路由到任何队列(例如,因为没有为交换机绑定任何东西),并且生产者将 mandatory 设置为 false(默认值)时,该消息将被丢弃或重新发布到备用交换机(如果有)

8、当已发布的消息无法路由到任何队列,且生产者将 mandatory 设置为 true 时,消息将被返回给生产者。生产者必须设置一个返回消息处理程序,以便处理返回消息(例如,记录错误或使用不同的交换机重试)

 

备份交换机

1、当交换机接收到一条不可路由消息时,将会把这条消息转发到备份交换机中,由备份交换机来进行转发、处理

2、通常备份交换机的类型为 Fanout ,这样就能把所有消息都投递到与其绑定的队列中

3、在备份交换机下绑定一个队列,接收所有原交换机无法被路由的消息,

4、报警队列,使用独立的消费者进行监测、报警

5、设置 exchangeDeclare 中的 Map<String,Object> arguments

key(String) value(Object)
alternate-exchange 备份交换机的名称

6、mandatory 参数、备份交换机,如果两者同时开启,则备份交换机优先级更高

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