2-RabbitMQ(2)

消息队列在进行消息的发接时,会面临很多问题,比如

  ● 消息的可靠性:如何保证消息至少被消费一次

  ● 延迟消息:消息的延迟投递

  ● 高可用问题:如何避免单点MQ故障导致不可用

  ● 消息堆积问题:消息的发送速率远大于消息的消费速率,造成消息在队列中堆积

 

1、消息的可靠性

  消息在发送的过程中可能会造成丢失,

    ● 消息未送达交换机  消息未送达队列

       /生产者确认机制 :给消息指定唯一ID,消息发送到MQ以后返回ack/nack

                消息成功到交换机,返回ack

                消息未到交换机,返回nack

                消息到交换机但没到队列,返回ack,并返回失败的原因

    ● MQ接收到消息后宕机,消息丢失

       /MQ持久化:RabbitMQ默认是非持久化的,SpringAMQP默认是持久化的

        交换机持久化、队列持久化、消息持久化

        SpringAMQP:是基于RabbitMQ封装的一套模板,并且利用SpringBoot对其实现了自动装配

      

    ● 消费者接收到消息后未来得及消费就宕机

       /消费者确认机制

        manual:手动回复ack给队列,在代码执行结束后在返回ack

        auto:自动返回ack给队列:由Spring监测,当代码抛出异常时返回nack正常执行完毕时返回ack

        yml配置:Spring:rabbitmq:listener:simple:acknowledge-mode:manual #手动返回ack

       /失败重试机制

        消费者出现异常,消息不断入队列重新发送,无限循环,队列的消息处理飙升

        解决上面问题:开启本地重试

          在yml进行配置:开启重试机制、初始等待时长、每次失败等待时长曾倍数增长、重试最大次数

        1、在开启本地重试后,消费者出现异常没有成功接收到消息,这时消息不会在重新加入队列而是在消费者本地重试,重试次数达到设定的最大次数仍没有成功时,Spring返回ack,消息会被丢弃

        2、在1中丢弃的消息,如果是重要的数据可能造成损失,给队列绑定一个存放失败消息的交换机,失败交换机后面在绑定一个队列用于存放失败的消息,后交由人工处理

 

2、延时消息

 

  ● 可以通过死信交换机来实现消息的延时发送  

  死信:被消费者决绝接收的消息、存放在队列中超时未消费的消息、队列已满在进来新的消息最开始入队列的消息会成为死信

  死信交换机:与队列进行绑定,队列中有死信后,死信会存放到死信队列中,然后该死信交换机后面会绑定一个队列用于存放死信

  用代码声明死信交换机:deadLetterExchange(“死信交换机名称”);

    @Bean //声明一个普通队列与死信交换机的绑定关系

     public Queue simpleQueue2(){

      return QueueBuilder.durable("simple.queue")

      .deadLetterExchange("死信交换机名称")

      .builder();

      }

    @Bean //声明死信交换机

    public DirectExchange dlQueue(){

      return new DirectExchange("死信交换机名称",true,false);

     }

    

  我们在发送消息时会给消息设置一个超时时间,也可以在声明队列时给队列设置一个消息存放的超时时间,超过时间未消费的消息就会变为死信,通过死信交换机存放到死信队列中,通过这种方式,来实现消息的延时发送;

 

  ● 也可以通过声明DelayExchange交换机来实现延时消息  //使用延迟队列插件的方式

    1、消息的监听

      @RabbitListener(

        bindings = @QueueBinding(value=@Queue(name="队列名",durable="true")), //durable:开启持久化

        exchange =  @Exchange(name="交换机名称",delayed=”true”), //delayed:开启delayed属性,就是用delayed属性来实现消息的延时

        key = "bingdingKey的值"

      )

    2、消息的发送

      @Autoworad

      Private RabbitTemplate rabbitTemplate;

      MessageBuilder.withBody("消息内容".getBytes(StandardCharsets.UTF_8))

      .setHeader("x-delay",10000) //携带x-delay属性,指定延时时间

      .builder();

      rabbitlTemplate.convertAndSend("交换机名称","routingKey值","携带x-delay属性和延时时间的消息内容",唯一id)

 

3、惰性队列 Lazy Queues

  当生产者发送消息的速度大于消费者接收消息的速度,就导致队列中消息堆积问题,直到队列中的消息存放达到上限后,消息成为死信

  解决消息堆积的两种思路:

    ● 增加消费者数量,提高消费速度

    ● 扩大队列容积,提高消息堆积的上限

      接收到消息后直接存放的磁盘而非内存,消费者要消费消息时才会从磁盘中读取并加载到内存,支持数百万条的消息存储

      基于@Bean来声明惰性队列

       @Bean

        public Queue lazyQueue(){

          return QueueBuilder

            .durable("惰性队列名称")

            .lazy() //表示该队列为惰性队列

            .builder();

        } 

       基于@RabbitListener注解来声明惰性队列

        

 

  

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  

  

posted @ 2022-10-29 12:06  焦茶  阅读(38)  评论(0编辑  收藏  举报