如何处理消息堆积

问题现象

在使用云消息队列 RocketMQ 版实例时收到消息堆积告警,登录云消息队列 RocketMQ 版控制台后发现了下列现象:

  • Group 详情页面,看到Group ID的实时消息堆积量的值高于预期。

  • 导航栏中选择消息轨迹,单击创建查询任务,选择按 Message ID 查询,输入对应的信息,发现部分消息已发送至Broker节点,但未投递给下游消费者。

可能原因

云消息队列 RocketMQ 版的消息发送至Broker节点后,配置了Group ID的客户端根据当前的消费位点,从Broker节点拉取部分消息到本地进行消费。一般情况下,客户端从Broker节点拉取消息的过程不会导致消息堆积,主要是客户端本地消费过程中,由于消费耗时过长或消费并发度较小等原因,导致客户端消费能力不足,出现消息堆积的问题。具体的消费原理和消息堆积原因请参见消息堆积和延迟问题

解决方案

若出现消息堆积,可参考以下措施进行定位和处理。

  1. 判断消息堆积在云消息队列 RocketMQ 版服务端还是客户端。

    查看客户端本地日志文件ons.log,搜索是否出现如下信息:

    the cached message count exceeds the threshold
    • 出现相关日志信息,说明客户端本地缓冲队列已满,消息堆积在客户端,请执行步骤2

    • 若未出现相关日志,说明消息堆积不在客户端,若出现这种特殊情况,请直接联系阿里云技术支持。

  2. 确认消息的消费耗时是否合理。

    • 若查看到消费耗时较长,则需要查看客户端堆栈信息排查具体业务逻辑,请执行步骤3

    • 若查看到消费耗时正常,则有可能是因为消费并发度不够导致消息堆积,需要逐步调大消费线程或扩容节点来解决。

    消息的消费耗时可以通过以下方式查看:

  3. 查看客户端堆栈信息。只需要关注线程名为ConsumeMessageThread的线程,这些都是业务消费消息的逻辑。可参见Java官方文档判断线程的状态并根据具体问题修改业务逻辑。

    客户端堆栈信息可以通过以下方式获取:

    • 登录云消息队列 RocketMQ 版控制台查看消费者状态,在客户端连接信息中查看Java客户端堆栈信息。具体操作,请参见查看消费者状态

    • 使用Jstack工具打印堆栈信息。

      1. 请参见查看消费者状态获取消息堆积的消费者实例所对应的宿主机IP地址,并登录该宿主机。

      2. 执行以下任意命令,查看并记录Java进程的PID。

        ps -ef 
        |grep javajps -lm
      3. 执行以下命令,查看堆栈信息。

        jstack -l pid > /tmp/pid.jstack
      4. 执行以下命令,查看ConsumeMessageThread的信息。

        cat /tmp/pid.jstack|grep ConsumeMessageThread -A 10 --color

    常见的异常堆栈信息如下:

    • 示例一:空闲无堆积的堆栈。

      消费空闲情况下消费线程都会处于WAITING状态等待从消费任务队中获取消息。

      堆栈示例一

    • 示例二:消费逻辑有抢锁休眠等待等情况。

      消费线程阻塞在内部的一个睡眠等待上,导致消费缓慢。堆栈示例二

    • 示例三:消费逻辑操作数据库等外部存储卡住。

      消费线程阻塞在外部的HTTP调用上,导致消费缓慢。堆栈示例3

  4. 针对某些特殊业务场景,如果消息堆积已经影响到业务运行,且堆积的消息本身可以跳过不消费,您可以通过重置消费位点跳过这些堆积的消息从最新位点开始消费,快速恢复业务。具体操作,请参见重置消费位点