rabbitmq怎样确认是否已经消费了消息_RabbitMQ最佳实践

点击上方“Java知音”,选择“置顶公众号”

技术文章第一时间送达!

作者:无知者云

https://www.cnblogs.com/davenkin

(点击即可跳转阅读)

1. SpringBoot内容聚合

2. 面试题内容聚合

3. 设计模式内容聚合

4. 排序算法内容聚合

5. 多线程内容聚合

在使用消息机制时,我们通常需要考虑以下几个问题:

  • 消息不能丢失

  • 保证消息一定能投递到目的地

  • 保证业务处理和消息发送/消费的一致性

本文以RabbitMQ为例,讨论如何解决以上问题。

消息持久化

如果希望RabbitMQ重启之后消息不丢失,那么需要对以下3种实体均配置持久化:

  • exchange

  • queue

  • message

声明exchange时设置持久化(durable = true)并且不自动删除(autoDelete = false):

boolean durable = true;
boolean autoDelete = false;
channel.exchangeDeclare("dlx", TOPIC, durable, autoDelete, null)

声明queue时设置持久化(durable = true)并且不自动删除(autoDelete = false):

boolean durable = true;
boolean autoDelete = false;
channel.queueDeclare("order-summary-queue", durable, false, autoDelete, queueArguments);

发送消息时通过设置deliveryMode=2持久化消息:

AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
                    .contentType("application/json")
                    .deliveryMode(2)
                    .priority(0)
                    .build();
channel.basicPublish("order", "order.created", false, properties, "sample-data".getBytes())

发送确认

有时,业务处理成功,消息也发了,但是我们并不知道消息是否成功到达了rabbitmq,如果由于网络等原因导致业务成功而消息发送失败,那么发送方将出现不一致的问题,此时可以使用rabbitmq的发送确认功能,即要求rabbitmq显式告知我们消息是否已成功发送。

首先需要在channel上设置ConfirmListener:

channel.addConfirmListener(new ConfirmListener() {
    
                public void handleAck(long seqNo, boolean multiple) {
                    if (multiple) {
                        logger.info(seqNo + "号及其以前的所有消息发送成功,当消息发送成功后执行相应逻辑,比如标记事件为已发送或者删除原来事件");
                    } else {
                        logger.info(seqNo + "号发送成功,当消息发送成功后执行相应逻辑,比如标记事件为已发送或者删除原来事件");
                    }
                }

                public void handleNack(long seqNo, boolean multiple) {
                    if (multiple) {
                        logger.info(seqNo + "号及其以前的所有消息发送失败,当消息发送失败后执行相应逻辑,比如重试或者标记事件发送失败");
                    } else {
                        logger.info(seqNo + "号发送失败,当消息发送失败后执行相应逻辑,比如重试或者标记事件发送失败");

                    }
                }
            });

然后在发送消息直线需要开启发送确认模式:

//开启发送者确认
channel.confirmSelect();

然后发送消息:

channel.basicPublish("order", "order.created", false, properties, "sample-data".getBytes());

当消息正常投递时,rabbitmq客户端将异步调用handleAck()表示消息已经成功投递,此时程序可以自行处理投递成功之后的逻辑,比如在数据库中将消息设置为已发送。当消息投递出现异常时,handleNack()将被调用。

通常来讲,发送端只需要保证消息能够发送到exchange即可,而无需关注消息是否被正确地投递到了某个queue,这个是rabbitmq和消息的接收方需要考虑的事情。基于此,如果rabbitmq找不到任何需要投递的queue,那么rabbitmq依然会ack给发送方,此时发送方可以认为消息已经正确投递,而不好用关系消息没有queue接收的问题。

但是,对于rabbitmq而言,这种消息是需要记录下来的,否则rabbitmq将直接丢弃该消息。此时可以为exchange设置alternate-exchange,即表示rabbitmq将把无法投递到任何queue的消息发送到alternate-exchange指定的exchange中,通常来说可以设置一个死信交换(DLX)。

事实上,对于exchange存在但是却找不到任何接收queue时,如果发送是设置了mandatory=true,那么在消息被ack前将return给客户端,此时客户端可以创建一个ReturnListener用于接收返回的消息:<

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值