RabbitMQ 消息可靠性和服务高可用

        消息队列

      消息队列是典型的生产者消费者模型,本质就是一块可供读写消息的缓冲区。

           消息队列可以解耦,异步,削峰。是现代应用开发中不可或缺的技术

       RabbitMQ

          RabbitMQ是一个由erlang开发的消息队列。并发能力很强,性能极其好,延时很低,达到微秒级。

          设计结构如下:

          

    消息可靠性

      RabbitMQ提供了以下方法保证消息的可靠性:

          1.生产者确认机制

            生产者可以通过生产者确认机制来知晓消息是否成功到达broker。

// 消息是否成功发送到Exchange
final RabbitTemplate.ConfirmCallback confirmCallback = (CorrelationData correlationData, boolean ack, String cause) -> {
            log.info("correlationData: " + correlationData);
            log.info("ack: " + ack);
            if(!ack) {
                log.info("异常处理....");
            }
    };
rabbitTemplate.setConfirmCallback(confirmCallback);

          2.消费者手动确认

            消费者可以设置手动确认,在手动返回ack之前,broker会一直保存该消息。

@RabbitListener(queues = RabbitMqConfig.MAIL_QUEUE)
    public void onMessage(Message message, Channel channel) throws IOException {

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long deliveryTag = message.getMessageProperties().getDeliveryTag();
        //手工ack;第二个参数是multiple,设置为true,表示deliveryTag序列号之前(包括自身)的消息都已经收到,设为false则表示收到一条消息
        channel.basicAck(deliveryTag, true);
        System.out.println("mail listener receive: " + new String(message.getBody()));
    }

          3.持久化

            RabbitMQ支持持久化,保证服务重启后消息不丢失。

            一般交换机和队列都是要持久化的。如果消息需要持久化,可以设置delivery mode = 2。

         4.路由不可达处理

           RabbitMQ支持生产者监听回调函数和备份交换机两种处理方式,来保证消息不丢失。

// 回调函数
final RabbitTemplate.ReturnCallback returnCallback = (Message message, int replyCode, String replyText, String exchange, String routingKey) ->
            log.info("return exchange: " + exchange + ", routingKey: "
                    + routingKey + ", replyCode: " + replyCode + ", replyText: " + replyText);
rabbitTemplate.setReturnCallback(returnCallback);

          备份交换机alternate-exchange 是一个普通的exchange,当你发送消息到对应的exchange时,没有匹配到queue,就会自动转移到备份交换机对应的queue,这样消息就不会丢失。

      服务高可用

        镜像队列集群

         当MQ发生故障时,会导致服务不可用。引入RabbitMQ的镜像队列机制,将queue镜像到集群中其他的节点之上。如果集群中的一个节点失效了,自动地切换到镜像中的另一个节点以保证服务的可用性

       

    通常每一个镜像队列都包含一主多从,分别对应于不同的节点。
      发送到镜像队列的所有消息总是被直接发送到master和所有的slave之上。除了publish外所有动作都只会向master发送,然后由master将命令执行的结果广播给slave,从镜像队列中的消费操作实际上是在master上执行的。
           镜像队列解决的是高可用问题,负载均衡需要人工控制,比如将主队列均匀分散在各个节点上
           此时生产者进行当前消息确认的前提是该消息被全部队列接收。

              

          网络分区

     网络设备(比如中继设备、网卡)出现故障也会导致网络分区。因为循环链表形式的设计来保证强一致性,所以为了性能,有网络故障的节点,就需要将他剥离出当前分区。
          网络分区都是由单个节点的网络故障引起的,且通常会形成一个大分区和一个单节点的分区。
          发送网络分区后,需要及时解决。可以人工介入挑选信任分区,或者设置分区自动解决模式。
        

        fedration

          Federation 插件可以让多个交换器或者多个队列进行联邦。一个联邦交换器(federatedexchange)或者一个联邦队列(federated queue)接收上游(upstream)的消息。这里的上游是指位于其他 Broker 上的交换器或者队列。

          

         fed生产同步。避免生产跨机房的延时

       

 

           fed消费同步。有效利用多机房资源

          

           shovel的设计与federation相似,这里不再赘述。

         

        容灾方案

          多集群 + 多机房 + fed link相互备份。

          保证如果单节点/单集群/单机房出现问题,仍然高可用。

          避免了跨机房请求,也可以利用机房资源并行消费。

        

 

posted @ 2023-02-05 13:27  Duikerdd  阅读(107)  评论(0编辑  收藏  举报