rocketmq和kafka的区别之顺序消费
文章目录
- 一.背景
- 相同点
- 二.差异
- 1. rocketmq的实现方式
- 1.1 消费线程对ProcessQueue加锁要解决什么问题?
- 2. kafka的实现方式
- 三. 为什么会有这样的差异?
一.背景
rocketmq和kafka都可以保证消息消费的有序性, 但是由于设计理念的区别导致大家的实现方式完全不同。
相同点
两者都是通过key取模 使拥有相同key的消息进入同一个分区中。
二.差异
两者在消费端的处理模式是不同的。
1. rocketmq的实现方式
rocketmq采用一个消费者实例 + 内部线程池的模型。为保证消费的有序性需要加3把锁1. 消费者实例对Broker实例的MessageQueue加锁, 保证该队列的消息只会投递给同一个消费者实例2. 消费者实例单次拉取多条消息到l本地ProcessQueue,并且提交到线程池。 为了保证同一时间一个queue只会被同一个线程消费,要对本地的MessageQueue加锁。持锁的线程才有资格消费。3. 消费线程对ProcessQueue加锁,因为要确保在发生重平衡时 Rebalance线程无法获取到ProcessQueue的锁, 无法对ProcessQueue修改,造成重复消费。
1.1 消费线程对ProcessQueue加锁要解决什么问题?
时刻 | 线程 | 操作 | 说明 |
---|---|---|---|
T1 | 消费线程A | 从ProcessQueue.msgTreeMap 中取出10条消息 | 消息处于"在途"状态,已从队列取出但未完成处理 |
T2 | Broker | 触发重平衡(如新消费者加入) | 通知当前消费者不再负责MessageQueue-X |
T3 | 重平衡线程 | 将ProcessQueue-X.dropped = true ,准备移除队列并持久化消费进度 | 此时认为该队列已不再属于当前消费者 |
T4 | 消费线程A | 处理完10条消息,尝试更新消费进度并删除msgTreeMap 中的消息 | 操作一个可能已被标记为丢弃的队列 |
重平衡线程在T3时刻持久化的消费进度不包含T1时刻取出的10条"在途"消息
2. kafka的实现方式
1. kafka采用一个线程对应着一个消费者的模型
2. 一个应用实例可以有多个消费者(KafkaConsumer), 每个Kafka都是单线程执行的。即一个应用实例有多个消费者实例, 这些消费者实例是单线程运行的,所以不需要有rocketmq的3把锁。
三. 为什么会有这样的差异?
1. 因为rocketmq采用rocketmq采用一个消费者实例 + 内部线程池的模型, 加上考虑到重平衡的影响,需要加3次锁。
2. kafka采用一个线程对应着一个消费者的模型, 本身就是单线程执行的,不存在并发的问题。