阿里云首页 金融分布式架构 SOFAStack

状态不一致

本文将介绍常见的状态不一致问题及相应的解决方案。

非预期的客户端连接

现象

  • 用户侧反馈部分消息发送后未收到。登录消息队列控制台。点击 消息轨迹 > 创建查询任务 > 按 Message ID 查询,发现部分消息已发送至 broker,但未投递给下游消费者。

  • 登录消息队列控制台。点击 Group 管理 > 消费者状态,连接状态栏下方出现不在预期范围内的客户端 IP,同时存在部分消息堆积只在非预期范围内的客户端上。

分析

  • 原因在同—套环境中,以错误的方式(AccessKeyId、AccessKeySecret、Topic 等信息配置错误)启动了 Group ID 的客户端,导致该客户端进程占用了 Topic 下的部分消息队列而无法正确消费消息,消息在服务端堆积,无法实时投递给下游正确的消费者。

  • 确认方式先根据连接状态定位有问题的进程,然后通过 /{user.home}/logs/sofamq.log 以及程序代码确认配置的 AK、SK、Topic 等信息。

  • 恢复方法可以先将有问题的客户端进程先关闭,此时之前堆积的消息会立马进行 Rebalance 投递至正常的客户端,待定位到问题修复后再重启有问题的进程。(快速恢复)

验证

  1. 登录消息队列控制台。

  2. 选择 Group 管理 > 消费者状态。连接状态栏下方显示的所有已连接的客户端都能在预期范围内,并能正常消费消息。同时订阅关系是否一致栏显示是。

消息不合法

可能产生的原因:一般是消息属性、消息内容不合法,不合法的情况有:

  • 消息为空;

  • 消息内容为空;

  • 消息内容长度为 0;

  • 消息内容超过限定长度。

建议解决方案:请确保消息没有以上的不合法情况,并根据异常提示进行解决。

参数不合法

可能产生的原因:参数不合法的情况有以下几种:

嵌套的异常说明

异常描述

consumeThreadMin Out of range [1, 1000]

消费端线程数设置不合理

consumeThreadMax Out of range [1, 1000]

消费端线程数设置不合理

messageListener is null

未设置 messageListener

consumerGroup is null

未设置 Group ID

msg delay time more than 40 day

定时消息延时不能超过 40 天

建议解决方案:按如下步骤操作:

  1. 按照异常提示修改客户端对应参数的配置,确保其在合理范围内。

  2. 重启应用。

客户端状态异常

可能产生的原因

  • 创建 Consumer、Producer 之后未调用 start() 方法来启动客户端;

  • 创建 Consumer、Producer 之后 start() 过程有异常导致客户端启动失败;

  • 创建 Consumer、Producer 并成功调用 start() 方法后,显示调用了 shutdown() 方法关闭了客户端。

建议解决方案:按如下步骤操作:

  1. 确保创建 Consumer、Producer 之后调用 start() 保证客户端处于启动状态;

  2. 查看 ons.log 判断在客户端在启动过程中是否有异常。

订阅关系不一致

原因描述

在不同的 JVM 中启动了多个 Consumer,并且给相同的 Group ID 配置了不同的 Topic,或者是相同的 Topic 但 Tag 不同,最终导致订阅关系不一致,消息不符合预期。

  • 错误示例一:同一个 Group ID(GID-MQ-FAQ)订阅的 Topic 不同(分别是 MQ-FAQ-TOPIC-1、MQ-FAQ-TOPIC-2)。JVM-1上的代码:

    Properties properties = new Properties();
    properties.put(PropertyKeyConst.GROUP_ID,"GID-MQ-FAQ");
    Consumer consumer=ONSFactory.createConsumer(properties);
    consumer.subscribe("MQ-FAQ-TOPIC-1","NM-MQ-FAQ",new MessageListener(){
        public Action consume(Message message,ConsumeContext context){
            System.out.println("Receive: "+message);
            return Action.CommitMessage;
        }
    });
    consumer.start();

    JVM-2上的代码:

    Properties properties = new Properties();
    properties.put(PropertyKeyConst.GROUP_ID,"GID-MQ-FAQ");
    Consumer consumer=ONSFactory.createConsumer(properties);
    consumer.subscribe("MQ-FAQ-TOPIC-2","NM-MQ-FAQ",new MessageListener(){
        public Action consume(Message message,ConsumeContext context){
            System.out.println("Receive: "+message);
            return Action.CommitMessage;
        }
    });
    consumer.start();
    
  • 错误示例二:同一 Group ID(GID-MQ-FAQ)订阅的 Topic 相同,但 Tag 不同(分别 NM-MQ-FAQ-1、NM-MQ-FAQ-2)。JVM-1上的代码:

    Properties properties =new Properties();
    properties.put(PropertyKeyConst.GROUP_ID,"GID-MQ-FAQ");
    Consumer consumer =ONSFactory.createConsumer(properties);
    consumer.subscribe("MQ-FAQ-TOPIC-1","NM-MQ-FAQ-1",new MessageListener(){
      public Action consume(Message message,ConsumeContext context){
          System.out.println("Receive: "+ message);
          return Action.CommitMessage;
      }
    });
    consumer.start();

    JVM-2上的代码:

    Properties properties =new Properties();
    properties.put(PropertyKeyConst.GROUP_ID,"GID-MQ-FAQ");
    Consumer consumer =ONSFactory.createConsumer(properties);
    consumer.subscribe("MQ-FAQ-TOPIC-1","NM-MQ-FAQ-2",new MessageListener(){
        public Action consume(Message message,ConsumeContext context){
            System.out.println("Receive: "+ message);
            return Action.CommitMessage;
        }
    });
    
    consumer.start();

建议解决方案:请确保在不同 JVM 中使用相同的 Group ID 启动多个 Consumer 时,配置的 Topic 和 Tag 是一致的。