求助:ActiveMQ Artemis 2.16.0在K8s+KEDA环境下消息已消费确认但控制台计数仍不为零
我之前帮团队排查过类似的Artemis队列计数问题,结合你的配置和现象,来拆解下可能的原因和解决办法:
先明确你的场景
你这边是把Artemis 2.16.0容器化部署在K8s上配合KEDA做弹性扩缩,用Python的stomp.py走STOMP协议消费,配置了client-individual的ACK模式、consumerWindowSize=0,而且消费后立刻确认消息。现在的问题是:明明消息都消费确认完了,Web控制台的消息计数却偶尔清不了零,但手动浏览队列又看不到任何消息,结果KEDA误判队列还有消息,启动多余的Pod。
可能的几个原因
1. Artemis控制台的统计是缓存的,不是实时的
Artemis Web控制台显示的队列计数,很多时候是基于后台的统计缓存,不是直接读队列的实时状态。尤其是高并发消费的时候,统计数据的更新会有延迟,就会出现“实际没消息,但控制台显示还有”的情况。
2. STOMP的ACK和服务端状态没同步上
虽然你设置了client-individual并立刻ACK,但有可能ACK消息因为网络波动丢了,或者Artemis在处理ACK的时候出现了短暂的状态不一致——比如服务端已经处理了消息,但统计模块没及时更新。
3. 2.16.0版本的已知Bug
Artemis 2.16.0是2021年的老版本了,当时在队列计数、STOMP ACK处理这块确实有一些已知问题,后续版本修复了不少。
4. KEDA的指标采集逻辑踩坑
KEDA是靠采集Artemis的队列指标来扩缩容的,如果它读的是缓存的旧数据(比如用了Prometheus exporter但采集频率太低,或者用JMX读取的是过时统计),就会误触发扩容。
一步步排查和解决
第一步:先确认队列的真实状态,别信控制台
Web控制台的计数可能不准,直接用Artemis的CLI命令查真实的队列状态:
# 进入Artemis容器里执行这个命令 ./artemis queue stat --name=你的队列名称
如果CLI显示消息数是0,但控制台还有数,那就是控制台的统计缓存问题,不用慌,重点解决统计更新的问题就行。
第二步:调小Artemis统计的更新间隔
默认情况下Artemis的统计更新可能比较慢,你可以改broker.xml里的配置,让统计更频繁:
<metrics> <metric-setting name="queue"> <setting name="update-interval" value="1000"/> <!-- 改成1秒更一次,默认可能是5秒或更长 --> </metric-setting> </metrics>
改完重启Broker,看看控制台的计数能不能及时跟上实际状态。
第三步:给STOMP的ACK加日志,确保没丢
有时候你以为发了ACK,但其实客户端发送失败了,建议在Python代码里加日志,确认每个消息的ACK都成功发出去了:
import stomp class MyConsumerListener(stomp.ConnectionListener): def on_message(self, headers, message): # 先处理你的业务逻辑 print(f"处理完消息:{message[:50]}...") # 发送ACK的时候加异常捕获和日志 try: conn.ack(id=headers['message-id'], subscription=headers['subscription']) print(f"成功发送ACK,消息ID:{headers['message-id']}") except Exception as e: print(f"发送ACK失败:{str(e)}") # 初始化连接和订阅的代码 conn = stomp.Connection([('artemis服务地址', 61613)]) conn.set_listener('', MyConsumerListener()) conn.connect('用户名', '密码', wait=True) conn.subscribe( destination='/queue/你的队列名', id='1', ack='client-individual', headers={'consumerWindowSize': '0'} )
同时去Artemis的日志里看看有没有ACK相关的错误或警告,确认服务端收到了ACK。
第四步:升级Artemis版本(最推荐)
2.16.0真的太老了,很多队列统计和STOMP相关的Bug在后续版本都修复了,比如2.20+之后的版本在这方面稳定很多。建议升级到最新的稳定版(比如2.30.x),大概率能直接解决这个问题。
第五步:给KEDA加冷却时间,避免误扩缩
就算指标偶尔不准,也可以通过KEDA的配置来减少误触发,比如加个冷却时间,让KEDA在指标变化后等一会儿再扩缩容:
apiVersion: keda.sh/v1alpha1 kind: ScaledObject metadata: name: artemis-consumer-scaler spec: scaleTargetRef: name: 你的消费端Deployment名称 triggers: - type: activemq-artemis metadata: managementEndpoint: "artemis-broker:8161" queueName: "你的队列名" queueLength: "5" # 你设置的扩容阈值 cooldownPeriod: 300 # 5分钟冷却,避免因为短暂的指标波动乱扩容
第六步:临时调整consumerWindowSize试试
虽然你设置consumerWindowSize=0是为了关闭预取,但这个配置在某些场景下可能会让Artemis的统计逻辑出现异常。可以临时改成一个小值(比如10),看看问题会不会复现,排除这个配置的影响。
最后总结
这个问题大概率是Artemis老版本的统计延迟或者Bug,或者控制台缓存导致的显示不一致。优先用CLI确认真实队列状态,然后试试升级版本、调统计间隔,再配合KEDA的冷却配置,应该就能解决KEDA误扩容的问题了。
内容的提问来源于stack exchange,提问作者Amit

