前言

“我正在参与「启航计划」”

目前企业中最常用到的音讯行列便是 RabbitMQ(主要是由于它在中小企业遍及更早,经受的考验也更久,带来了一大批“回头客”),所以把握 RabbitMQ 的相关技能就显得是比较重要了。咱们在运用 RabbitMQ 的过程中比较常见的问题便是音讯丢掉、音讯积压等等,所以此类问题也就成为了面试官们陈词滥调的问题了… 今日就和咱们共享一下我在作业过程中处理 RabbitMQ 音讯丢掉与音讯积压的一点经历心得

传送门:大聪明教你学Java | Win10 环境下安装部署 RabbitMQ

传送门:大聪明教你学Java | RabbitMQ 的作业原理及其简单操作

RabbitMQ 的音讯丢掉问题

RabbitMQ 防止音讯丢掉的办法主要是利用音讯承认机制和手动签收机制,所以在处理音讯丢掉问题之前,咱们有必要把这两个概念搞清楚。

音讯承认机制(针对生产者)

咱们能够经过在 .yml 文件中增加如下装备,开始音讯承认机制

spring:
  rabbitmq:
    publisher-returns: true #音讯失利承认
    publisher-confirm-type: CORRELATED  #音讯成功承认
    template:
      mandatory: true #手动签收机制

这样,当咱们完成 ConfirmCallback、ReturnCallback 这两个接口的办法后,就能够有针对性地进行音讯承认的日志记载与后续的进一步操作(如:音讯发送补偿等),从而到达挨近100%投递的目的。

import com.rabbitmq.client.ConfirmCallback;
import com.rabbitmq.client.Return;
import com.rabbitmq.client.ReturnCallback;
import java.io.IOException;
/**
 * @description: RabbitMQSender
 * @author: 庄霸.liziye
 * @create: 2022-08-03 09:39
 **/
public class RabbitMQSender implements ConfirmCallback, ReturnCallback {
    /**
     * 音讯发送
     * @param msg
     */
    public void sendMsg(String msg){
    }
    /**
     * 成功接受后的回调
     * @param l
     * @param b
     * @throws IOException
     */
    @Override
    public void handle(long l, boolean b) throws IOException {
        //详细处理
    }
    /**
     * 失利后的回调
     * @param aReturn
     */
    @Override
    public void handle(Return aReturn) {
        //详细处理
    }
}

注意:生产者音讯承认机制会下降 RabbitMQ 功能,个人主张非必要不运用此机制。咱们也能够经过人工辨认事务状况判断顾客是否处理了事务逻辑,假如没有处理相关音讯,咱们能够经过人工进行补偿。这两种计划各有利弊,前者会下降功能,后者会提升运维成本,所以咱们需要根据详细情况选择最合适的处理计划。

音讯承认机制(针对顾客)

RabbitMQ的音讯是自动签收的,你能够了解为快递签收了,那么这个快递的状况就从发送变为已签收,仅有的区别是快递公司会对物流轨道有记载,而MQ签收后就从行列中删除了。企业级开发中,RabbitMQ咱们基本都敞开手动签收办法,这样能够有用防止音讯的丢掉。

敞开手动签收的办法也很简单,只需要在 .yml 文件中新增一条装备即可

spring:
  rabbitmq:
    listener:
      direct:
        acknowledge-mode: manual #手动签收机制

在代码中运用手动签收也很简单,只需要一行代码,如下图所示(该截图来自于目前我参与的项目)

大聪明教你学Java | 面试管:谈谈如何解决 RabbitMQ 消息丢失与消息积压

我目前参与的项目中,手动签收办法几乎都是处理完事务逻辑之后再手动签收,个人认为这种用法是不科学的(在处理完事务逻辑后再手动签收,不然不签收,就好比客人进店了你得买东西,不然不让走 )。

在分布式的架构中,RabbitMQ 用来解耦和转发对错常常见的,假如是付出事务,往往在回调通知中经过 RabbitMQ 转发到其他服务,假如其他服务处理不成功,那么手动签收也不执行,这个音讯又会入队发给其他顾客,这样就可能在流量洪峰阶段由于偶尔的事务处理失利形成堵塞,这样就得不偿失了。个人认为咱们能够运用 try-catch-finally 代码块包裹住音讯处理部分的代码,将手动签收(即 .basicAck)部分放在 finally 模块中,这样能够保证 RabbitMQ 的责任单一、运行流畅。

音讯丢掉

咱们了解了音讯承认机制和手动签收机制,接下来咱们就能够开始处理消失丢掉问题了。音讯丢掉的原因主要有以下三种:

  • 音讯宣布后,中途网络故障,RabbitMQ 服务器没收到
  • 音讯宣布后,RabbitMQ 服务器收到了,但是还没耐久化,服务器就宕机了
  • 音讯宣布后,RabbitMQ 服务器收到了,但是消费方还未做事务逻辑处理,服务却挂掉了

针对上面的问题原因,咱们能够运用以下计划来处理问题:

  • 生产方在发送音讯时,要用 try-catch代码块包裹发送音讯的代码,在 catch 中捕获异常,并将 RabbitMQ 发送的要害内容记载到日志中(并存储音讯发送状况),若发送失利,由守时任务守时扫描重新发送并更新状况。
  • 音讯的生产者必须要加入承认回调机制,经过回调办法承认成功发送并签收的音讯;假如音讯发送失利进入失利回调办法,就修改数据库音讯的状况,等待守时任务重发。
  • 消费方要敞开手动签收 ACK 机制,消费成功才将音讯移除,失利或因异常情况而没有处理,就重新入队。

RabbitMQ 的音讯积压问题

讲完了音讯丢掉问题的原因及其处理办法,咱们接下来再看看如何处理音讯积压的问题。导致出现音讯积压的原因一般是两种:

  • 顾客的服务挂掉,导致一直无法消费音讯。
  • 消费方的服务节点太少,导致消费才能不足,从而出现积压。

针对此类问题的处理办法就很直接了

  • 已然消费才能不足,那就扩展更多消费节点,提升消费才能。这是最直接的办法,也是音讯积压最常用的处理计划。
  • 树立专门的行列消费服务,将音讯批量取出并耐久化(存入数据库、存入本地文件等等),之后再渐渐消费。这种办法主要针对于考虑到服务器成本压力的企业,先经过一个独立服务把要消费的音讯存起来,之后再渐渐处理这些音讯。

小结

自己经历有限,有些地方可能讲的没有特别到位,假如您在阅读的时候想到了什么问题,欢迎在谈论区留言,咱们后续再一一探讨‍

希望各位小伙伴动动自己心爱的小手,来一波点赞+重视 (✿◡‿◡) 让更多小伙伴看到这篇文章~ 蟹蟹呦(●’◡’●)

假如文章中有过错,欢迎咱们留言纠正;若您有更好、更独到的了解,欢迎您在留言区留下您的宝贵想法。

爱你所爱 行你所行 遵从你心 无问东西