Rocketmq 和 kafka 这两个消息队列大家应该都比较熟悉吧,哪怕不是很熟悉,应该也听说过的吧,你别告诉我,作为一个资深的程序员,你没听过这两门技术。
我之前使用这两个消息队列的时候就遇到一个很奇怪的问题,就是在 kafka 里面弄了比较多的 topic,性能下降的速度贼快,不知道大家遇到过没,而同样的场景切换到消息队列 rocketmq 中,下降速度却没有那么快。
不熟悉这俩消息队列结构的朋友,一听这个肯定还是不太清楚的,今天我来给大家分析分析这其中的原因,给大家解惑。
rocketmq 的结构
NameServer:主要是对元数据的管理,包括 Topic 和路由信息的管理,底层由 netty 实现,是一个提供路由管理、路由注册和发现的无状态节点,类似于 ZooKeeper
Broker:消息中转站,负责收发消息、持久化消息
Producer:消息的生产者,一般由业务系统来产生消息供消费者消费
Consumer:消息的消费者,一般由业务系统来异步消费消息
在 RocketMQ 中的每一条消息,都有一个 Topic,用来区分不同的消息。一个主题一般会有多个消息的订阅者,当生产者发布消息到某个主题时,订阅了这个主题的消费者都可以接收到生产者写入的新消息。
在 Topic 中有分为了多个 Queue,这其实是我们发送/读取消息通道的最小单位,我们发送消息都需要指定某个写入某个 Queue,拉取消息的时候也需要指定拉取某个 Queue,所以我们的顺序消息可以基于我们的 Queue 维度保持队列有序,如果想做到全局有序那么需要将 Queue 大小设置为 1,这样所有的数据都会在 Queue 中有序。
我们同一组 Consumer 会根据一些策略来选 Queue,常见的比如平均分配或者一致性 Hash 分配。
要注意的是当 Consumer 出现下线或者上线的时候,这里需要做重平衡,也就是 Rebalance,RocketMQ 的重平衡机制如下:
定时拉取 broker,topic 的最新信息,每隔 20s 做重平衡,随机选取当前 Topic 的一个主 Broker,这里要注意的是不是每次重平衡所有主 Broker 都会被选中,因为会存在一个 Broker 再多个 Broker 的情况。
获取当前 Broker,当前 ConsumerGroup 的所有机器 ID。然后进行策略分配。
由于重平衡是定时做的,所以这里有可能会出现某个 Queue 同时被两个 Consumer 消费,所以会出现消息重复投递。
Queue 读写数量不一致
在 RocketMQ 中 Queue 被分为读和写两种,在最开始接触 RocketMQ 的时候一直以为读写队列数量配置不一致不会出现什么问题的,比如当消费者机器很多的时候我们配置很多读的队列,但是实际过程中发现会出现消息无法消费和根本没有消息消费的情况。
当写的队列数量大于读的队列的数量,当大于读队列这部分 ID 的写队列的数据会无法消费