RabbitMQ 之消息的可靠性投递

消息的可靠性投递

默认情况下,消息发送端发送消息给 RabbitMQ 后,RabbitMQ 是不会返回任何信息的。
RabbitMQ 提供了两种确认消息是否投递成功的方法

  • 设置 channel 为 transaction 模式,通过 AMQP 事务机制实现,这也是 AMQP 协议层面提供的解决方案
  • 设置 channel 为 confirm 模式,这是 RabbitMQ 提供的解决方案

https://juejin.im/post/5d6cccd85188251ff57f9e2a

channel 的 transaction 模式

RabbitMQ 中与事务机制有关的方法有三个

  • txSelect:用于将当前 channel 设置成 transaction 模式
  • txCommit:用于提交事务
  • txRollback:用于回滚事务
    在通过 txSelect 开启事务之后,我们便可以发布消息给broker代理服务器了,如果txCommit提交成功了,则消息一定到达了broker了,如果在 txCommit 执行之前 broker 异常崩溃或者由于其他原因抛出异常,这个时候我们便可以捕获异常通过 txRollback 回滚事务了
    事务确实能够解决 producer 与 broker 之间消息确认的问题,只有消息成功被 broker 接收,事务提交才能成功,否则我们便可以在捕获异常进行事务回滚操作,同时进行消息重发,但是使用事务机制的话会降低RabbitMQ的性能。
    RabbitMQ 提供了一个更好的方案,使用 channel 信道的 confirm 模式。

channel 的 confirm 模式

生产者通过调用 channel 的 confirmSelect 方法将 channel 设置为 confirm 模式. 该模式下,所有在该信道上发布的消息都会被分派一个唯一的ID(从1开始),当消息被投递到所有匹配的队列后,broker 就会发送一个(包含消息的唯一 ID 的)确认给发送端,
如果 RabbitMQ 因为自身内部错误导致消息丢失,就会发送一条nack消息,发送端的 Confirm Listener 会去监听应答
在这里插入图片描述
broker回传给发送端的确认消息中 deliver-tag 域包含了确认消息的ID,此外 broker 也可以设置 basic.ack 的 multiple 域,表示到这个ID之前的所有消息都已经得到了处理
confirm模式最大的好处在于他是异步的,生产者可以在等信道返回的同时继续发送下一条消息。

上面说到“当消息被投递到所有匹配的队列后,broker 就会发送一个(包含消息的唯一 ID 的)确认给发送端”,万一发送确认后, rabbitMq 崩溃了,消息队列中的消息就都没了,这时候发送端还以为消息还在队列中。
为了防止这种情况的发送,rabbitMq 需要对队列和消息进行持久化。
当消息和队列开启持久化之后,确认信息会等到消息写入磁盘之后再发出.

Confirm 的三种使用方式
  • 普通确认:每发送一条消息后,调用channel.waitForConfirms()方法,同步等待服务器端confirm。实际上是一种串行confirm了。
  • 批量确认:每发送一批消息后,调用channel.waitForConfirms()方法,同步等待服务器端confirm
  • 异步确认:为channel添加一个监听器,rabbitmq 会回调这个方法,示例代码如下
// 添加一个确认监听
channel.addConfirmListener(new ConfirmListener() {
    //消息失败处理
    @Override
    public void handleNack(long deliveryTag, boolean multiple) throws IOException {
        //deliveryTag;唯一消息标签
        //multiple:是否批量
        System.err.println("-------no ack!-----------");
    }
    //消息成功处理
    @Override
    public void handleAck(long deliveryTag, boolean multiple) throws IOException {
        System.err.println("-------ack!-----------");
    }
});

量 confirm 模式 和 异步confirm模式效率更高些,但是批量confirm模式下,如果 rabbitMq 返回失败,那么需要重新发送这一批消息,建议最好还是选择异步confirm模式.

超时

RabbitMQ 的响应可能会超时,超时可能是消息没有到达 mq ,也有可能是网络延迟导致的。对于响应超时的消息,通常被认定为投递失败。

对于投递失败的消息,需要进行消息补偿

消息补偿

消息补偿由发送端自己设计,常见的设计方案为
在这里插入图片描述

  • step1: 发送业务消息前,先将业务数据和消息状态入库,并将消息状态初始化为发送中
  • step2: 发送业务消息,设置超时时间,同时异步监听 RabbitMQ 响应
  • step3: RabbitMQ 返回响应
  • step4: 根据响应结果,更新消息状态,投递成功则将消息状态设置成成功
  • step5: 定时任务找出状态为发送中,且时间超时的
  • stem6: 重新投递
  • stem7: 经过上述步骤多次(通常是3次)循环后,依然失败的,设置消息状态为失败
  • stem8: 人工去解决状态为失败的消息
重复投递

消息补偿机制可能会导致重复投递,重复投递可能导致消费端重复消费。但重复投递又无法完全避免,因此消费端需要防止重复消费。

总结

要保证 RabbitMQ 的消息可靠性投递,需要做到以下几点

  • 消息发送端开启 channel 的 confirm 模式
  • 消息发送端异步接收 RabbitMQ 响应
  • RabbitMQ 对队列和消息进行持久化
  • 消息发送端建立消息投递失败的补偿机制
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值