开发中使用RabbitMQ的注意事项

  1. 使用消息队列处理消息的时候,我们可能会遇到以下问题:
    1. 消息处理失败
    2. 消息体本身有误
    3. 消息重复处理
    4. 消息丢失
  2. 对于消息处理失败,有可能有由于网络波动导致的数据处理异常,待网络稳定时消息就会正常处理,对于这种处理失败,我们应该继续尝试去处理消息。
  3. 消息体本身有误,这会导致消息连续处理失败,占用较多的资源,写大量的无用日志,这种错误应该丢弃这部分无用消息,但要记录下日志,记清消息体本身数据,以及丢弃消息的原因。
  4. 消息重复处理,例如我们通过消息队列向数据库中添加数据,由于数据库网络波动,导致数据库连接超时,而我们的系统认为消息处理失败,就会把消息回滚到消息队列,继续尝试处理,这时就会造成消息重复处理的现象,对于重要的消息,我们可以每处理一条消息,就记录一下,处理新的消息时,进行判断消息是否已经处理,如果已经处理,就丢弃消息。
  5. 由于Spring 与RabbitMq集成 对消息的处理方式是默认自动应答,也就是处理消息时无论是否出现异常,都会给消息队列应答处理成功,消息队列删除消息,这时就会出现消息丢失的情况,为了解决这个问题,我们需要使用手动应答的方式处理消息。
    1. rabbitMQ消费者监听器的配置
      1.         
                
        1. <rabbit:listener-container connection-factory="connectionFactory" acknowledge="manual">
        2. <rabbit:listener queues="queueName" ref="Listiner"/>
        3. </rabbit:listener-container>
        acknowledge = "manual" 就表示该监听器手动应答消息
    2. 消费者监听器的编写
      1. 为了能够手动应答消息,我们编写的监听器需要实现ChannelAwareMessageListener,重写onMessage()方法,里面有两个参数Message messageChannel channel,Message 是消息体本身,Channel是RabbitMQ的连接通道。
    3. 异常的处理
      1. 消息处理正常,没有抛出异常,这时我们需要手动应答消息
        1.           
                    
          1. channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

      2. 当出现异常时,我们需要把这个消息回滚到消息队列,有两种方式
        1.           
                    
          1. //ack返回false,并重新回到队列,api里面解释得很清楚
          2. channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
          3. //拒绝消息
          4. channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);

      3. 经过开发中的实际测试,当消息回滚到消息队列时,这条消息不会回到队列尾部,而是仍是在队列头部,这时消费者会立马又接收到这条消息,进行处理,接着抛出异常,进行回滚,如此反复进行。这种情况会导致消息队列处理出现阻塞,消息堆积,导致正常消息也无法运行。对于消息回滚到消息队列,我们希望比较理想的方式时出现异常的消息到达消息队列尾部,这样既保证消息不会丢失,又保证了正常业务的进行,因此我们采取的解决方案是,将消息进行应答,这时消息队列会删除该消息,同时我们再次发送该消息到消息队列,这时就实现了错误消息进行消息队列尾部的方案。
        1.           
                    
          1. //手动进行应答
          2. channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
          3. //重新发送消息到队尾
          4. channel.basicPublish(message.getMessageProperties().getReceivedExchange(),
          5. message.getMessageProperties().getReceivedRoutingKey(), MessageProperties.PERSISTENT_TEXT_PLAIN,
          6. JSON.toJSONBytes(new Object()));

      4. 对于第三条中的解决方案会存在一个问题,如果一个消息体本身有误,会导致该消息体,一直无法进行处理,而服务器中刷出大量无用日志。解决这个问题可以采取两种方案
        1. 一种是对于日常细致处理,分清哪些是可以恢复的异常,哪些是不可以恢复的异常。对于可以恢复的异常我们采取第三条中的解决方案,对于不可以处理的异常,我们采用记录日志,直接丢弃该消息方案。
        2. 另一种是我们对每条消息进行标记,记录每条消息的处理次数,当一条消息,多次处理仍不能成功时,处理次数到达我们设置的值时,我们就 丢弃该消息,但需要记录详细的日志。
    4. 使用手动应答消息,有一点需要特别注意,那就是不能忘记应答消息,因为对于RabbitMQ来说处理消息没有超时,只要不应答消息,他就会认为仍在正常处理消息,导致消息队列出现阻塞,影响业务执行。
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值