消费问题排查 | 《Rocket MQ 使用排查指南》第三章-阿里云开发者社区

开发者社区> 云服务技术课堂> 正文

消费问题排查 | 《Rocket MQ 使用排查指南》第三章

简介: 本章介绍 消费问题排查

上一章:发送问题排查 | 《Rocket MQ 使用排查指南》第二章>>>

下一章:其他问题排查 | 《Rocket MQ 使用排查指南》第四章>>>

点击免费下载
《Rocket MQ 使用排查指南》>>>

test

也可以PC端点击https://developer.aliyun.com/topic/download?id=820下载

消费问题排查

堆积负载问题常见问题

Java 进程消息堆积严重

【问题描述】:

消费者状态页面,Group ID 的实时消息堆积量的值高于预期,且性能明显下降。

【排查步骤】:

  1. 在消息队列 MQ 控制台 , 通过查看消费者状态获取消息堆积的消费者实例所对应的宿主机 IP,并登录该宿主机或容器。
  2. 执行以下任一命令查看进程 pid:
- ps -ef |grep java
 - jps -lm
  1. 执行以下命令查看堆栈信息:
- jstack -l pid > /tmp/pid.jstack
  1. 执行以下命令查看 ConsumeMessageThread 的信息,重点关注线程的状态及堆栈:
cat /tmp/pid.jstack|grep ConsumeMessageThread -A 10 –color

只需要注意两种状态就可以。

  • BLOCKED 此状态说明消费者线程被阻塞了,导致消息的消费被停滞了,从而导致消息堆积的产生。这时要通过上面的堆栈信息来查看具体是阻塞在那个接口。
  • WAITING 这个状态要分两种情况来说明:

image.png

(1)如果是上图所显示的堆栈信息,说明消费者线程在等待消息消费,此为正常状态。

(2)如果不是上图所显示的堆栈信息,可以重复上面的 3、4 两步,检查这个这个消费者线程是否一直处于这种状态,而且堆栈信息显示也是一样的。这个现象说明在消费逻辑的代码中,由于某种资源紧张,导致获取这种资源的时间较长,从而导致消息消费的耗时增长,TPS 下降,消息消费的速度跟不上消息生产的速度,从而导致消息堆积。

为什么消费者堆积负载不均

【问题描述】:
每个消费者堆积数量差异很大,负载非常不均,具体现象如图

image.png

【问题原因】:
这个是分配策略,当所有消费实例都达到消费能力上限后,不再完全分配到所有都队列,会集中分配到前面的队列。这种现象一般建议提升代码消费能力和增加消费实例数解决堆积问题后就不会出现这种堆积。
可以理解为消费能力已经饱和,其他队列本身也有堆积情况,那么饱和之后分配就会直接到指定的某个队列。这种情况需要增加消费者或者优化代码来提升能力减少堆积,堆积多肯定会更加满负荷在跑。

这个上限不是挤压的或者mq端大量堆积导致程序高负载运行的上限,是正常消费有堆积就认为达到上限,是一个正常消费的理论上限。

这个是产品侧的一个策略,无法做到堆积后再均衡对堆积量做进一步对均衡分配。建议增加消费实例或者优化代码,减少堆积压力。

广播模式消费堆积

【问题描述】:

广播模式下控制台显示有大量堆积

【问题回答】:

广播模式下控制台看到的这个堆积数据是无效的,广播模式下服务端不维护消费进度,消费进度在客户端维护,所以是否有堆积这个需要您客户端来维护,广播模式下我们服务端不维护消费进度,您的消费端的消费位点,我们这边不保存,这个只能您自己消费端配置好消费日志,查看消费情况的。

实时消息堆积量和各个具体消费端堆积量不一致

【问题描述】:

消费者的实时消息堆积量有堆积量,但是各个具体的消费端却显示没有堆积量。

image.png

【问题原因】:

实时消息堆积量是订阅的整个topic的堆积量,包括重试队列的

如果说这个gid曾经定阅过topicA,现在不订阅A了,换成订阅TopicB,那么这个堆积量也是包含曾经订阅A的堆积量

下面各个c端的堆积量,是精确到这个c端订阅的tag的堆积量。下面的c端堆积量之和应该小于等于实施堆积量

【建议方案】:

可以点击这个消费者的【重置消费位点】,看下可以选择到的topic是不是有目前没有在订阅的。如果有的话,可以把这个topic的位点清除下,那么这个消费者的关于这个不再订阅的topic的实时堆积量就会清除掉了

mq是否支持积压消息后批量消费

【问题描述】:

开源RocketMQ 里有 interval 积压时间,可以积压几秒钟再进行批量消费。
无序消费消息时,是否有参数可以设置Pull的实际间隔,从而保障拉取下来的消息有一定的量,而不是1个,主要目的是想提升批量。
有序分区消息时,是否支持批量的有序消费?

【问题回答】:

RocketMQ现在的消费模式本身就是push的

1、批量消费可在消费客户端中设置ConsumeMessageBatchMaxSize 参数,批量消费消息个数。

批量拉取也要有对应的消息数才行,这个是在预期范围内的。这个是根据当时队列有多少条消息未消费来决定的,并不能做到每次消费的消息是一个固定值。PropertyKeyConst.ConsumeMessageBatchMaxSize 取值范围为1-32
mq的消费逻辑是这样的,启动消费者之后,消费者会一直在线
如果topic当中一直没有消息过来,我们会每15秒长轮询一次,消费者主动到topic当中拉取消息。如果有消息,就会将消息拉取到进行消费。所以暂时不支持挤压一定的消息之后再批量消费的

2、有序消息不支持批量消费

消费负载不均衡,有台消费者实例没有消费消息

【问题描述】:

一个gid下面,多个消费端,有一/几台机器显示堆积量为0,其他的机器堆积量都很大

image.png

【排查步骤】:

可以查看下堆积量为0的机器的ons.log日志
通过关键字搜索日志信息(注意要找到对应的topic)
只用关注其中的 perm 的值就行,6表示正常,如果是 4表示则表示mq后端做了相关的运维操作,后面会恢复正常的,此时没有消费的客户端可以拿来容灾。

分区顺序消息消费负载不均

【问题描述】:

三台同样的机器,一台收到95%的消息,一台5%左右的消息,一台一直是0
个pod的代码部署的是一样的 就是一套代码,都去作为消费者
三台机器的属性是一模一样,都是同一个业务

【问题回答】:

可能原因:

发送分区顺序消息的时候, 指定的shardingKey不太合适。导致消息发送打散的不够均匀.,基本上都集中少量逻辑分区里面了

shardingKey会影响消息分布在不同队列,然后消费机器是对应到多个队列的

发送分区顺序消息指定sharding Key, 满足业务约束的前提下, 尽量引进一些变量. 分布就会均匀了. 不是随机。

举例来说: 如果是订单系统. 用性别作为sharding key, 就不太合适. 如果user id/ 或者订单号, 就是更好一些的选择。

为什么消费堆积显示为负数?

【问题描述】:

为什么消费堆积显示的是负数

【排查步骤】:

1、是否有删除过这个topic,如果之前已经使用了这个topic进行收发消息,后面又删除了,然后短时间内又创建了这个topic,就会导致这个问题。可以通过重置消费位点来解决这个问题。

2、如果没有,那么需要提供实例id/地域/topic等信息给到技术人员进行进一步的查看

消费者rebalanceservice线程

【问题描述】:

在消费者线程当中看到rebalanceservice线程是正常的吗?

image.png

【问题回答】:

这个是消费端负载均衡的线程。是一个正常状态的线程。rebalance 是有时间间隔的

http协议消费者实时堆积量

【问题描述】:

http协议下的消费者实时堆积量都包含了那些?

【问题回答】:

这个堆积量是表示该消费者订阅的topic当中的所有tag的总堆积量
举例:topic当中有5个tag,该消费者指订阅了其中1个,还有4个没订阅,但是这个四个没订阅的tag,在topic当中有堆积了,这个堆积量也会显示在控制台当中的

消息投递重试问题

如果消息业务消费时间太久,那过多久会重新投递该消息

【问题描述】:

在订阅消费消息时,假如消费这条消息需要10分钟,那么MQ大概多久会重新投递该消息

【问题回答】:

消费端到mq当中拉到消息进行消费之后,会反馈给mq已经成功拿到消息并且消费。如果mq没有接收到消费端的反馈,那么mq就会认为这个消息没有消费成功,那么这个消息在topic当中就会再次可见,那么消费者就可以再次来拉取这个消息(重试)

第一次发消息算是第0次,如果在10秒内没有给mq反馈,那么这个消息就会再次可见,消费端就会再去拉取这个消息,就是第一次重试了,如果在10秒之后,消费者给了第一次发消息(第0次)的响应,那么这个消费也是失败的。比如消费者现在拉取到的是10s之后第一次重试的,那么在之后的30秒之内,如果消费者给了mq第一次重试拉到的消息的响应,这个才算是消费成功的。

所以建议不要把业务逻辑放在返回给mq消息的代码之前,最好是保证10秒之内要给到mq响应。可以将业务逻辑放在其他地方做并发处理。

image.png

消息重复投递

【问题描述】:

同一个消息有多次成功消费记录

image.png

【排查步骤】:

1、如果只是偶尔有消息这样,是因为绝大多数情况下,消息是不重复的。作为一款分布式消息中间件,在网络抖动、应用处理超时等异常情况下,无法保证消息不重复,但是能保证消息不丢失。

这种情况下,需要做好消费幂等,具体可以参考文档:
https://help.aliyun.com/document_detail/44397.html?spm=5176.11065259.1996646101.searchclickresult.4a8f70e3uKZijr

2、如果是大量消息重复消费,需要核实您的代码是否和mq官方提供的一致,在重复消费消息的时候,消费端的网络情况,是否有fullgc等
如果以上都没有问题,则需要提供下具体的异常信息:实例id/地域/topic/msgid等,给到技术支持人员进行确认

消息消费失败,一直重试

【问题描述】:
消息消费失败,一直消息重试,并且重试的间隔时间都是正常的

image.png

【排查步骤】:

1、需要查看下业务上关于这个消息有没有什么报错,一般消费失败是业务处理消息失败,业务如果有问题,重试多少次还是会有问题的
2、可以查看下ons.log日志,看下有没有异常
3、需要检查下消费的逻辑,返回的状态需要是Action.CommitMessage才对的

广播模式消费失败重试

【问题描述】:
有 A,B,C 3个节点, 使用广播模式发送一条消息,实际的目标是 让B处理, A和C直接放弃 , 那么问题是A和C直接 Action.CommitMessage
掉这条消息后, B里面业务处理出了问题 我消息Action.ReconsumeLater 后 消息是否会重发,重发是发给B 还是 A,B,C都会收到

【问题回答】:

广播模式不支持消费失败重投

消费失败的消息没有被重试

【问题描述】:

消费失败的消息,一直没有进行重试或者重试间隔的时间不对,与官方文档提供的重试时间不符合

【排查步骤】:

1、检查下否是广播消费模式,因为广播方式不提供失败重试特性,即消费失败后,失败消息不再重试,继续消费新的消息。

2、如果确认使用的是集群消费模式,检查消费者启动时的配置,是否有将最大重试次数

MaxReconsumeTimes的值设置为0,设置为0后将不在重试。这时可以去死信队列里确认下是否有此条消息。

3、如果配置没问题,可以过会再去检查消息轨迹,因为在共享集群下,某个时间段broker压力比较大的时候,消费失败重试会有一定的延迟。可以多检查下,确认没有重试。

4、如果以上都确认没有问题了,需要提供实例id/地域/topic/msgid等信息给技术人员进行查看

订阅关系问题

订阅关系不一致

【问题描述】:

为什么消费端不消费了/为什么我的消息堆积了许多/为什么消费速度不及预期,只是偶尔消费一两条/为什么一条消息被重复消费了?

【问题原因】:

消费者的订阅关系不一致了

订阅关系一致指的是同一个消费者 Group ID 下所有 Consumer 实例的处理逻辑必须完全一致。一旦订阅关系不一致,消息消费的逻辑就会混乱,甚至导致消息丢失。

由于消息队列 RocketMQ 版的订阅关系主要由 Topic + Tag 共同组成,因此,保持订阅关系一致意味着同一个消费者 Group ID 下所有的消费者实例需在以下两方面均保持一致:

订阅的 Topic 必须一致
订阅的 Topic 中的 Tag 必须一致

image.png

http的消费者看不到订阅关系

【问题描述】:

http的gid正在消费,但是topic当中查看不到这个订阅关系

image.png

【问题回答】:
http协议的消费者的订阅关系控制台目前不支持显示的

客户端消费常见异常报错

启动消费端时报错

【问题描述】:

启动消费端时报错找不到gid

2019-11-18 20:29:04,004 WARN RocketmqClient - execute the pull request exception
com.aliyun.openservices.shade.com.alibaba.rocketmq.client.exception.MQBrokerException: CODE: 26 DESC: subscription group [MQ_INST__BaSllRRw%GID_] does not exist,

See http://rocketmq.apache.org/docs/faq/ for further details.

【问题原因】:

后台创建GID失败了

【解决方案】:

可以在控制台当中将已经创建好的gid删除,在重新创建,创建完成之后,再次启动消费端

消费线程被卡住
【问题描述】:
查看消费者状态—连接详情,看到消费者存在消费线程被卡组和现象,卡住时间已超过10min25s
image.png

【问题回答】:

线程阻塞一般是CPU或内存消耗过高导致,一般是业务代码处理复杂和线程数较多导致。

1、建议重启一下消费端看下堆积是否会降下去。
2、建议看看能否升级一下机器配置
3、优化一下接收到消息后的业务处理代码
4、减少消费并发线程数目

消费者启动后不消费

【问题描述】:

一个全新的消费者gid启动,但是不消费已经发送到topic当中的消息

【问题原因】:

一个topic如果从来没有任何一个gid连接消费过,假设这个topic当中已经有一千万条消息发进来了,第一个启动的gid是不会去消费这一千万条消息的。是会从这个gid启动当下开始,发送到tipic当中的消息开始消费

如果说这个topic已经有gid连接过了,如果再次启动一个全新的gid连接,是会去消费topic当中还存在的,tag匹配的消息的。

消费的时候,如何获取消息体内容

【问题描述】:

消费的时候,如何获取消息体内容

【问题回答】:

以java代码为例,可以使用new String(message.getBody())来获取消息体内容

消费消息时ack报错

【问题描述】:

消费消息时候ack报错,ErrorMessage: The receipt handle you provided has expired.code MessageNotExist

【问题原因】:

报错是消息句柄过期了,这个是访问超时了

【解决方案】:

重新发送下这条消息,然后重新消费下。

全局顺序消息为什么启动多个消费者只有一个在消费

【问题描述】:

全局顺序消息的topic下,一个gid启动了多个消费者,但是只有一个消费者在消费,其他的消费者都不消费?

【问题回答】:

全局顺序创建topic时会指定到固定一台broker,只会分配一个队列。也就是说只有一台消费者能消费到消息

全局顺序消息,不管启动几个消费端,实际上都只会有一个消费端来消费,也只会分配到一个broker一个queue

此时多启动的消费者可以用来容灾

消费失败的消息可以直接丢弃掉吗?

【问题描述】:

消费失败的消息可以手动丢弃掉吗

【问题回答】:

直接catch异常,然后返回成功,这个是有风险的,如果处理消息异常,会导致不会再收到

消息默认重试16次后会进入死信队列中,可以选择重新发送或者三天后会自动清理,或者可以在生产者中try catch异常直接返回成功状态,该条消息则不会再重试和消费

消费者出现rebalanceService线程

【问题描述】:

消费者出现rebalanceService线程

image.png

【问题回答】:

这个是消费端负载均衡的线程,rebalance 是有时间间隔的

这个是正常的一个线程状态

延迟消息被立马/提前消费

【问题描述】:

发送的是延时消息,为何立马就被消费端消费了或者设置的延时时间还没有到就被消费了

【排查步骤】:

1、确认发送延时消息的api是否和官方提供的demo是一致的

2、是否设置了如图所示的属性

image.png

3、如果核实这两者都没有问题,需要将实例id/地域/topic/gid/发送代码信息收集完整,提供给技术支持进行查看

顺序消息没有被顺序消费

【问题描述】:

为什么发送的顺序消息,到那时消费的时候乱序了

【排查步骤】:

1、检查下发送消费的相关代码,是否使用的是顺序消息的api。收发顺序消息

2、如果检查发现使用的api都正确,这时可以通过消息轨迹和消息的存储时间来判断消息发送的先后顺序。可能是当时发送时间的先后顺序问题导致您所认为的消费乱序。

3、如果以上都排查了,没有问题,需要将实例id/地域/topic/gid/发送消费代码提供给技术支持,进行进一步排查

消息一直没有被消费

【问题描述】:

某条/些消息一直没有被消费

【排查步骤】:

1、检查消费者是否在线
2、检查消息的tag,该消费者是否有订阅
3、检查消费者是否订阅关系保持一致。一旦订阅关系不一致,消息消费的逻辑就会混乱,甚至导致消息丢失。
4、业务上核实是否真的没有收到该消息,mq是保证以消息准确到达服务端被消费为第一优先准则,所以在网络环境较差或抖动的情况下,消息轨迹可能会丢失,根据消息轨迹查询到的消费状态是未消费,但是实际上该消息已经被消费了

消息没有被立马消费,延迟很久才被消费

【问题描述】:

消息发送时间到消费中间这段时间延迟比较久,例如上午发送的消息,到下午才被消费

【排查步骤】:

1、查看下发送的时间段,topic的发送量和消费量对比,看下是否处于一个业务高峰期,导致消息有堆积,如果有消息堆积,那么延迟投递是正常现象
如果一直有堆积,建议增大消费能力,比如优化消费逻辑业务代码,或者增加消费者机器

2、查看ons.log日志,如果在ons.log中看到了
2019-07-05 16:46:39,039 WARN RocketmqClient - the cached message count exceeds the threshold 1000, so do flow control, minOffset=4731, maxOffset=5738, count=1008, size=0 MiB, pullRequest=PullRequest 【consumerGroup=GID_MR_SG_ACTIVITY_TEST, messageQueue=MessageQueue 【topic=T_MR_SG_USER_TASK_NORMAL_TEST, brokerName=hz-share2-03, queueId=7】, nextOffset=5739】, flowControlTimes=7235001。
这个警告是因为客户端消费能力不足,导致拉取消息也被暂停了。此时就需要增加消费能力,比如增加消费线程,或者增加消费者实例

3、查看下是否是消费速度太低,可以根据消费者状态当中的实时消费速度判断,如果消费速度过低,那么消息存放的队列堆积就会比较严重,影响消费时间,建议配置上堆积监控。配置后超过多少堆积告警,或者考虑增加消费实例,让消费能力稍微大于生成能力

重置消费位点失败

【问题描述】:

重试消费者的消费位点没有效果,还是有许多堆积

【问题回答】:

1、确认是否为集群消费(因广播模式下,消费位点都由客户端本地维护,因此广播消费模式下不支持重置消费位点)
2、确认当前消费者是否在线,消费者必须在线才能重置消费位点
3、确认sdk版本,sdk版本过低也会导致此问题。(建议升级sdk,至少是1.8.0版本
4、可以点击单个c端的详情查看当前消费者当中的消息是否是在重试队列当中的,如果选择的是清除所有堆积消息,从最新位点开始消费方式重置消费位点,是不能清除重试队列里的消息的。这个时候可以选择使用按时间点进行消费位点重置方式进行重置,此方式没有这个限制。

同一条消息,为什么发送方和订阅方的msgid不一样?

【问题描述】:

同一条消息,为什么发送方和订阅方的msgid不一样?

【排查步骤】:

1检查是否是事务消息或延时消息,如果是,则是正常现象。需要做幂等的话可以使用消息key来做幂等。事务消息或延时消息订阅方的msgid取的是transactionId。

通过message.getMsgID()这个获取的transactionId在控制台上是查不到消息的,这时候可以通过message.getUserProperties().getProperty("UNIQ_KEY")这个来获取真正的msgid

2、因为某些sdk的原因,有可能发送方和订阅方的msgid也会不一样。任何类型的消息都是这样,这时订阅方的msgid是offsetmsgid。这个很好区分,transactionId中英文字母是小写的,msgid和offsetmsgid中英文字母都是大写的。

消费者显示离线

【问题描述】:

查看消费者状态,发现消费者是离线状态

【问题原因】:

1、消费者实例没有启动
2、路由信息未注册到NameServer上面

【解决方案】:

1.原因里第一点直接启动消费者皆可,
2.首先确认在MQ控制台已经创建了GID
3、客户端可根据ons.log来排查是否有No route info of this topic的相关报错信息;
4、此时重点检查实例化消费者参数时NAMESRV_ADDR 参数配置是否与MQ控制台上的一致;排查接入点是否异常

步骤:删除客户端日志------>重启应用----->查看最新的ons.log。

同时确认NameServer是可连接的,telnet控制台提供的接入点看下是否telnet通。

如果不通,需要看下是不是该机器所属地域与mq实例所属不是同一个地域

ackmessage时报错Number of receiptHandles in XML is out of range

【问题描述】:

http协议的RocketMQ ackmessage时返回了 message: Number of receiptHandles in XML is out of range 错误

【问题原因】:

ack删除消息时,在xml body体中的receiptHandles数量大于16条。

一次最多是16个,超过就会报错了

启动消费端提示Group ID重复

【问题描述】:

启动消息队列Rocket MQ版的Producer(生产者)实例或Consumer(消费者)实例时,提示Group ID重复。

【问题原因】:

单个JVM进程中出现下列情况时,会导致客户端启动失败,提示Group ID重复:

启动了一个以上的Producer实例,并且这些实例使用相同的Group ID。

启动了一个以上的Consumer实例,并且这些实例使用相同的Group ID。

启动了一个以上的Producer实例和一个以上的Consumer实例,并且这些实例使用相同的Group ID。

【解决方案】:

单个JVM进程中使用相同Group ID的Producer实例或Consumer实例支持情况如下表:

image.png

如果出现上述不支持的情况,请改正后重新启动应用。

消费者启动时提示获取Topic队列失败

【问题描述】:

消息队列RocketMQ版中Consumer(消费者)主动订阅消息,启动客户端时系统提示获取Topic队列失败。

【问题原因】:

导致此问题的主要原因是客户端中订阅的Topic未在消息队列RocketMQ版的控制台中创建。

【解决方案】:

1、登录消息队列RocketMQ版的控制台,创建Topic和Group ID。
2、更新客户端中订阅的Topic和Group ID,确保其与控制台中创建的信息一致。
3、重新启动客户端,确认问题已经修复。

应用内存不足

【问题描述】:

1、在应用部署的机器上通过查看内存已消耗完。
2、在/{user.home}/logs/ons.log能搜索到 OutOfMemory 关键字。
3、在消息队列 RocketMQ 版控制台:进入消费者管理 > 消费者状态,堆积量栏显示消息堆积较多,连接状态栏显示了各个已连接客户端的消息堆积。通过 Jstack 排查, ConsumeMessageThread_ 线程无消费卡住现象。

【问题分析】:

在 1.7.0.Final 版本之前,默认客户端最多会给每个 Topic 的每个队列缓存 1000 条消息。假设每个 Topic 的队列数是 16 个(集群 2 主 2 备,每台 broker 上 8 个队列),该 Topic 下单条消息平均大小为 64 KB,那么最终该 Topic 在客户端缓存的消息 Size:16 1000 64 KB = 1 GB。如果用户同时订阅了 8 个 Topic 都在客户端内存缓存消息,最终占用内存将超过用户的 JVM 配置,导致 OOM。

原因 1:
依赖 1.7.0.Final 之前的 ons-client 版本,Topic 的平均消息大小超过 4 KB,并且消息消费较慢容易在客户端内存缓存消息。

确认方式:
在 /{user.home}/logs/ons.log 能搜索到 OutOfMemory 关键字;或者通过jmap -dump:live,format=b,file=heap.bin 命令确认哪些对象占用了大量内存。

恢复方案:
升级 ons-client 版本至 1.7.0.Final 或以上,同时给对应的 ConsumerBean 配合设置 com.aliyun.openservices.ons.api.PropertyKeyConst#MaxCachedMess ageSizeInMiB参数,然后重启应用。

原因 2:
依赖 1.7.0.Final 及以上的 ons-client 版本,默认最大消耗内存 512 MB(Group ID 订阅的所有 Topic 缓存总和);如果应用仍然出现 OOM 现象,可在 ConsumerBean启动时,配置:
com.aliyun.openservices.ons.api.PropertyKeyConst#MaxCachedMessageSizeInMiB参数自行定义最大消耗内存(范围在 16 MB ~ 2048 MB)。

确认方式:
确认应用依赖的 ons-client 版本,并通过 JVM 确认给进程分配的内存大小。

恢复方案:
根据应用机器的内存使用清况给对应的 ConsumerBean 设置com.aliyun.openservices.ons.api.PropertyKeyConst#MaxCachedMessageSizeInMiB参数,然后重启应用。

消费者报错参数不合法

【问题描述】:

消费者报错参数不合法

【异常及描述】:

参数不合法的情况有以下几种:

1、异常:consumeThreadMin Out of range [1, 1000]
描述:消费端线程数设置不合理
2、异常:consumeThreadMax Out of range [1, 1000]
描述:消费端线程数设置不合理
3、异常:messageListener is null
描述:未设置 messageListener
4、异常:consumerGroup is null
描述:未设置 Group ID
5、异常:msg delay time more than 40 day
描述:定时消息延时不能超过 40 天

消息显示 _Consumed_, 但消费端未感知到

【问题描述】:

消息状态显示“Consumed”,但是消费端业务日志显示没有收到消息。

【问题原因】:

1、业务代码在接收到消息后,不立即打印消息
收到消息后,如果直接进入业务逻辑,一旦代码遗漏某个逻辑分支,就会导致消息信息没有被留在业务日志里,造成没有收到消息的假象。
建议您收到消息后,立即打印消息信息留存 messageId, timestamp, reconsumeTime 等。
2、消费端部署了多个消费实例
尤其是在调试阶段,消费端不可避免会多次重启,一旦多个消费进程同时存在(进程未退出),那么相当于进入集群的消费模式,多个消费实例会共同分担消费消息。以为没有收到的消息,其实是被另一个消费端接收了。
到消息队列 RocketMQ 版控制台,进入Group 管理 > 消费者状态 > 连接状态,会显示消费端的实例部署情况(有几个消费实例,各自的连接 IP 等等),然后可以自行排查。
3、消息消费过程出现未被 Catch 的异常,导致消息被重新投递。

批量消费不起作用

【问题描述】:

使用的是批量消费的api BatchConsumer,为何每次消费的消息都是一条或者不是我设置的属性 PropertyKeyConst.ConsumeMessageBatchMaxSize 的值?

【问题原因】:

这个是在预期范围内的。这个是根据当时队列有多少条消息未消费来决定的,并不能做到每次消费的消息是一个固定值。

PropertyKeyConst.ConsumeMessageBatchMaxSize 取值范围为1-32

消息轨迹常见问题

消息轨迹显示消费结果未返回

【问题描述】:

消息轨迹显示消费结果未返回

image.png

【问题原因】:

消费消息的方法尚未返回结果,或者中断,导致本次消费结果未传回服务端

【建议方案】:

建议您不要把业务逻辑放在返回给mq服务端的代码之前,最好是保证尽快给到mq响应。这样可以避免消息消费失败,在进行消息重试。如果您的业务逻辑时间的确很长,建议您可以将信息拉取到之后,存到数据库、redis当中,然后尽快给到mq ackMessage,之后再异步进行业务消费。

消息已经消费,但是消费轨迹显示尚未消费

【问题描述】:

消息本地日志记录该消息已经完成消费,但是在控制台查询消费轨迹却显示该消息尚未消费

【排查步骤】:

1、首先确认发送方或订阅方应用的sdk版本(1.2.7 版本及以上)
2、查看发送端或消费端启动时,将PropertyKeyConst.MsgTraceSwitch这个属性值设置是否为false。这个属性是启用消息轨迹的开关。
3、如果sdk版本和发送端消费端实例化时参数配置都正常,可以让查看那个时间段的ons.log,检查日志中是否有:

send trace data,the traceData is Pub ...
send trace data,the traceData is SubBefore ...
send trace data,the traceData is SubAfter ...
等等相关日志。出现了相关日志,说明消息轨迹发送失败了。所以会缺失,不完整。

因为消息轨迹是异步发送的,存在的发送失败的可能,具体以您业务中是否有被消费为准

轨迹消息在网络不稳定,客户端机器压力大等一些情况下,可能存在发送失败的可能性。因为轨迹消息重要性不及业务消息,这种情况一般不会重试,所以存在少量的消息无法采集到的情况。所以会看到上面的问题。后面我们会继续优化。

批量导出消息的消费轨迹

【问题描述】:

需要批量导出某个topic某段时间内所有消息的消费轨迹

【问题回答】:

目前后端没有存储某个topic的消息轨迹,无法支持批量导出。
提供思路建议:

1、新建一个GID, 订阅指定的topic. 控制台上Reset这个新建的gid的消费位
点到指定开始时间点. 消费程序调用 OpenAPI查询轨迹信息:
https://help.aliyun.com/document_detail/59830.html?spm=a2c4g.11186623.6.711.7fd27e80IBF0mT

2、注意一点, OpenAPI本身是运维接口, 需要控制查询速度.

事务消息事务已提交,但是轨迹显示事务未提交

【问题描述】:

事务消息事务已提交,但是轨迹显示事务未提交。事务消息提交的轨迹记录丢失 如下图所示

image.png

【问题原因】:

事务消息的半消息存在db当中,消息commit的时候才会存到broker,但是轨迹是发到其他机器完成轨迹的记录,收到轨迹记录请求的目标机器并非原来发送方的机器,导致轨迹记录失败

消息轨迹名词解释

【问题描述】:

关于消息轨迹名词的解释

image.png

【问题回答】:

1、发送耗时:
这个耗时的时间是调用发送消息的com.aliyun.openservices.shade.com.alibaba.rocketmq.client.impl.MQClientAPIImpl#sendMessage() 的耗时时间。如果是同步发送,则会包含存储到broker的时间,异步和oneWay 则不包含。
发送端的代码逻辑可以看 DefaultMQProducerImpl.sendKernelImpl() 中执行的
com.aliyun.openservices.ons.api.impl.tracehook.OnsClientSendMessageHookImpl#sendMessageBefore
com.aliyun.openservices.ons.api.impl.tracehook.OnsClientSendMessageHookImpl#sendMessageAfter

2、消费耗时
这个时间是消费耗时,是调用客户端的 consume() 的整个花费的时间。也就是图2的 SubAfter 的 TimeStamp 减去 SubBefore 的 TimeStamp 的时间。
消费段的代码逻辑可以看
com.aliyun.openservices.shade.com.alibaba.rocketmq.client.impl.consumer.ConsumeMessageConcurrentlyService.ConsumeRequest#run()(注意,这是非顺序消费的执行逻辑) 中执行的
com.aliyun.openservices.ons.api.impl.tracehook.OnsConsumeMessageHookImpl#consumeMessageBefore
com.aliyun.openservices.ons.api.impl.tracehook.OnsConsumeMessageHookImpl#consumeMessageAfter

3、消费轨迹的ip就是本机ip。linux环境下利用 ifconfig 查看,windows环境利用ipconfig查看

消息轨迹中记录消费的ip与实际消费该消息的ip不一致

【问题描述】:

消息轨迹当中记录的消费端的消费ip与实际业务上消费该消息的机器的ip不一致

【问题原因】:

如果消费消息的ecs当中有docker,mq取的客户端Ip会取到docker网卡的ip,而不是ecs的内网ip
这个是您运行环境下拿出来的ip,如果是docker环境,不一定是真实ip
具体消费的ip以实际您自己业务当中记录的ip为准

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

分享:

云服务技术课堂,各类技术课程、最佳实践输出,来好好听课吧!

官方博客