状态不一致

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

非预期的客户端连接

现象

  • 部分消息发送后客户端未收到。按 Message ID 查询消息(具体操作方法详见 消息查询)后,发现部分消息已发送至 Broker,但未投递给下游消费者。

  • 查看目标 Group ID 的消费者状态(具体操作方法详见 查看消费者状态),连接信息中出现了不在预期范围内的客户端 IP,同时存在部分消息只堆积在非预期范围内的客户端上的情况。

可能的原因

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

解决方案

  1. 先根据连接状态定位有问题的进程,然后查看 /{user.home}/logs/sofamq.log 日志以及程序代码确认配置的 AK、SK、Topic 等信息是否配置正确。

  2. 快速恢复。

    将有问题的客户端进程先关闭,此时之前堆积的消息会马上进行 Rebalance 投递至正常的客户端,待问题修复后再重启有问题的进程。

结果验证

登录消息队列控制台查看目标 Group ID 的消费者状态,确认连接信息中显示的所有已连接的客户端都能在预期范围内,并能正常消费消息。同时订阅关系一致栏显示

消息不合法

可能的原因

消息属性、消息内容不合法,有以下 4 种情况:

  • 消息为空。

  • 消息内容为空。

  • 消息内容长度为 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() 方法关闭了客户端。

解决方案

查看 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 是一致的。