RabbitMQ如何保证可靠性

在RabbitMQ中可以将消息传递的链路简化成如下图:

从上图可以发现,主要分为三个角色:Producer、Consumer、RabbitMQ Broker

正常情况下,Producer生产消息,安全的到打Broker的Exchange,然后根据转发规则,存储在Queue上,最后再推送给订阅的Consumer。

因此可以将链路分成三个部分:

1.消息从Producer到RabbitMQ的Exchange

2.消息从Exchange到Queue

3.消息从Queue到Consumer

当然还有一种情况,就是消息已经到达服务器了,但服务器挂了,因此还需要有持久化来恢复消息。

综上,要想保证RabbitMQ的可靠性,可以从这四个方面去入手:

1.保证消息从Producer到达Broker的Exchange

2.保证消息从Exchange转发到对应的Queue上

3.保证消息的持久化

4.保证消息正确被消费者消费

发布确认机制

发布确认主要分为两种模式:confirm模式和return模式

confirm模式是针对消息从Producer到Exchange

return模式是针对消息从Exchange到Queue

Confirm模式

Spring中yml配置:

XML 复制代码
spring:
  rabbitmq:
    port: 5672
    host: xxx
    username: admin
    password: admin
    virtual-host: demo
    #消息发送确认
    publisher-confirm-type: correlated

因为这个机制是在发送方这边,因此在创建RabbitTemplate时配置。

代码:

java 复制代码
    @Bean("confirmRabbitTemplate")
    public RabbitTemplate confirmRabbitTemplate(ConnectionFactory
                                                        connectionFactory){
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            @Override
            public void confirm(CorrelationData correlationData, boolean ack,
                                String cause) {
                System.out.printf("");
                if (ack){
                    System.out.printf("消息接收成功, id:%s \n",
                            correlationData.getId());
                }else {
                    System.out.printf("消息接收失败, id:%s, cause: %s",
                            correlationData.getId(), cause);
                }
            }
        });
        return rabbitTemplate;
    }

RabbitMQ无法去区分要确认的是哪条消息,因此在发送消息的时候还要添加一个标识。

代码:

java 复制代码
    public String fanout(){
        for (int i = 0; i < 10; i++) {
            CorrelationData correlationData = new CorrelationData("" + i);
            rabbitTemplate.convertAndSend(Constants.FANOUT_EXCHANGE, "", "hello------" + i, correlationData);
        }
        return "发送成功~";
    }

Return模式

消息到达Exchange后,会根据路由规则进行转发到队列中,但可能存在队列与路由键不匹配或者没有绑定的队列等,消息无法转发到队列中,我们可以设置对这种情况的队列回退到Producer。

yml配置同上

代码:

java 复制代码
    @Bean("confirmRabbitmqTemplate2")
    //回退模式
    public RabbitTemplate confirmRabbitTemplate2(ConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setMandatory(true);
        rabbitTemplate.setReturnsCallback(new RabbitTemplate.ReturnsCallback() {
            @Override
            public void returnedMessage(ReturnedMessage returned) {
                System.out.println("消息被退回");
            }
        });
        return rabbitTemplate;
    }

生产者代码同上

持久化机制

持久化主要针对的是交换机、队列、消息。

代码:

java 复制代码
//交换机持久化
ExchangeBuilder.topicExchange(Constant.ACK_EXCHANGE_NAME).durable(true).build();

//队列持久化
QueueBuilder.durable(Constants.WORK_QUEUE).build();

//消息持久化
Message message = new Message("nihao".getBytes(), new MessageProperties());
          message.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
            User user = new User(i, "test--" + i, 10 + i);
            rabbitTemplate.convertAndSend("", Constants.WORK_QUEUE, user);

消息确认机制

消息确认机制主要是用在消费者这边,当消费这从Broker获取了消息,处理完后需要发送一个Ack告诉Broker,然后Broker就可以将消息删除了。

在RabbitMQ中可以设置两种模式:手动确认和自动确认

但在Spring-AMQP中提供了三种机制:NONE、MANUAL、AUTO

NONE:表示不做任何处理,消息一旦发出去就会被确认删除。

AUTO:与NONE不同的是,如果消费者在处理消息的时候发生异常了,并不会确认消息。

MANUAL:手动确认,消费者需要显示调用ACK。

xml配置:

java 复制代码
spring:
  rabbitmq:
    port: 5672
    host: xxx
    username: admin
    password: admin
    virtual-host: demo
    listener:
      simple:
#        acknowledge-mode: none
#        acknowledge-mode: auto
        acknowledge-mode: manual

代码:

java 复制代码
    @RabbitListener(queues = Constants.WORK_QUEUE)
    public void listenerQueue1(Message message, Channel channel) throws IOException {
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        try{
            System.out.println("listener1 : " + message);
            int a = 3 / 0;
            channel.basicAck(deliveryTag, false);
        } catch (Exception e) {
            channel.basicNack(deliveryTag, false, true);
        }
    }

总结:

保证消息的可靠性的方式总共分为四个方式:

1.保证消息从Producer到达Broker的Exchange -> Confirm模式

2.保证消息从Exchange转发到对应的Queue上 -> Return模式

3.保证消息的持久化 -> 设置durable参数

4.保证消息正确被消费者消费 -> 手动应答

相关推荐
未若君雅裁17 小时前
RabbitMQ 高可用机制:普通集群、镜像队列与仲裁队列
java·微服务·rabbitmq·java-rabbitmq
zycoder.17 小时前
rabbitmq学习demo,包含普通消息,TTL+死信队列,topic交换机三种情况,以项目形式讲解
分布式·学习·rabbitmq
贺国亚18 小时前
分布式并发
分布式·wpf
未若君雅裁19 小时前
RabbitMQ 消息堆积怎么处理:消费者扩容、线程池与惰性队列
分布式·微服务·rabbitmq
这个DBA有点耶19 小时前
分布式数据库的“分片键”设计:选错可能让性能倒退10倍
数据库·分布式
国科安芯19 小时前
AS32S601芯片抗辐照性能试验验证与空间环境适应性分析
前端·分布式·单片机·嵌入式硬件·架构·risc-v·安全性测试
或与且与或非19 小时前
postgresql+rabbitmq集群搭建方案
数据库·postgresql·rabbitmq
phltxy20 小时前
RabbitMQ TTL与死信队列详解
分布式·rabbitmq·ruby
深蓝电商API20 小时前
反向海淘系统微服务拆分:从单体到分布式演进实战经验
分布式·微服务·架构·反向海淘
woniu_buhui_fei21 小时前
常用分布式中间件一览
分布式·中间件