现象
在 spring boot 项目中集成 RocketMQ 时发现消费者接收消息丢失,比如生产者发送了 10 条消息,但是消费者只能接收到 4 条。
在项目中使用的 RocketMQ 版本是 4.9.2,rocketmq-spring-boot-starter 版本是 2.2.2,消息处理逻辑也不复杂,直接引用依赖,然后创建监听器。如下:
接收消息后没有其他操作,直接打印。
问题排查
从客户端到服务端,总结出可能有以下原因:
● 客户端业务代码的影响
● 主题多分区,其中一个分区有问题
● 消息被其他客户端接收
● RocketMQ 部署有问题
第一个原因很快就能排除。我们简化了代码,去掉业务代码,只保留消息接收部分,问题仍然存在。
然后重新创建主题,并设置分区数为 1 ,问题仍然存在。
剩下就是消息被其他客户端接收和部署问题了。
用户一致强调只有一个客户端,因此问题排查的进度就卡在这里。我用自己写的测试客户端没有复现这个问题,因此还是怀疑消息是被其他客户端接收了。
之后换了其他的订阅组,发现消息没有丢失,但是重启几次后问题又出现了。至此确认有多个客户端使用相同订阅者订阅该主题的消息。
登录用户服务器,执行以下命令查看客户端连接信息:
netstat -anp |grep 9876
,连接数为 2。
停掉 RocketMQ 客户端,再次执行上述命令,连接数为 0。
这就很奇怪了,一个 spring boot 项目理论上只有一个连接,但是每次启动程序都有两个连接。在研究 rocketmq-spring-boot-starter 代码后,发现创建消费者连接有两种方式,一种是代码里实现 RocketMQListener 接口,另外一种是在配置文件中添加订阅信息。
然后查看用户代码,很明显,代码里在两个地方都加了相同主题、相同订阅组信息,因此消费者连接数就是 2。
问题解决
问题找到后就很容易解决了,直接把配置文件中的消费者配置删除即可。
rocketmq.consumer 配置后会自动初始化消费者,因此代码里需要在其他配置名称下配置消费者信息。