Kafka和RocketMQ存储模型对比
文章目录
- Kafka和RocketMQ存储模型对比
-
- Kafka存储模型:以Partition为中心
- RocketMQ存储模型:以CommitLog为中心
- 深度对比分析:核心差异点
- 适用场景推荐
-
- [1. 什么时候选 Kafka?](#1. 什么时候选 Kafka?)
- [2. 什么时候选 RocketMQ?](#2. 什么时候选 RocketMQ?)
- 总结
Kafka存储模型:以Partition为中心
物理结构 Topic -> Partition -> Segmet
- Kafka的数据按照Topic分类;
- 每个Topic被切分为多个Partition(分区数量尽量不要变动),每个Partition分区在物理磁盘对应一个文件夹;
- 每个Partition分区文件夹下包含多个Segment段文件(日志文件.log、索引文件.index、时间索引文件.timeindex),按照1G或7天进行切分
markdown
/kafak_logs/
├── my_topic_0 #分区0对应的文件夹
├── 00000000000000000000.log
├── 00000000000000000000.index
├── 00000000000000000000.timeindex
├── 00000000000000000005.log #对应offset、size、body
├── 00000000000000000005.index
├── 00000000000000000005.timeindex
├── my_topic_1 #分区1对应的文件夹
├── 00000000000000000000.log
├── 00000000000000000000.index
├── 00000000000000000000.timeindex
├── 00000000000000000005.log
├── 00000000000000000005.index
├── 00000000000000000005.timeindex
├── ...
IO特征
- 局部顺序写:在一个Partition分区内部,写入是安全顺序的
- 全局随机写:如果一个 Kafka 集群中有成百上千个 Topic,每个 Topic 又有多个 Partition,磁盘磁头需要在不同的 Partition 文件夹之间频繁跳跃。这会导致宏观上的随机 I/O,这也是Topic越多多会导致Kafka性能下降的原因
索引机制
- 稀疏索引:Kafa的.index文件不会为每条消息建立索引,而是每个一定字节比如4K建立一条索引,查找时先二分查找找到最近的索引点,然后顺序扫描 .log 文件。
RocketMQ存储模型:以CommitLog为中心
物理结构:RocketMQ采用了分离式的存储设计,主要由三部分组成
- **CommitLog消息主体:**所有的Topic消息,全部顺序写入同一个CommitLog文件中
- **ConsumeQueue逻辑队列:**每个Topic的每个Queue对应一个ConsumeQueue,只存储消息的在CommitLog中的偏移量Offset、消息长度Size、标签Tag Hash
- Index消息索引: 支持按照Key或时间进行快速查询消息
markdown
/RokcetMQ_HOME/
├── commitLog
├── 00000000000000000000 #每个文件大小1G/ 结构化的格式存储的消息体
├── 00000000010300000000
├── 00000000021400000000
├── 00000000033200000005
├── ...
├── consumeQueue
├── Topic1
├── 0
├── 00000000000000000000 #CommitLog的偏移量、消息长度、TagHashCode
├── 00000000000066000000
├── 1
├── 00000000000000000000
├── 00000000000066000000
├── index
├── 1230000000000000000 #TODO
├── 2110000000000000000
IO特征
- 顺序写(全局的) :无论有多少个 Topic,写入操作永远是追加到 CommitLog 的末尾。这保证了绝对的顺序写,极大提高了写入性能,尤其是在 Topic 数量巨大的时候。
- 随机读:消费者读取消息时,需要先查 ConsumeQueue 拿到位置,再去读 CommitLog。这看似是随机读,但 RocketMQ 通过 PageCache 预读和 Mmap 内存映射机制进行了优化
索引机制
- 密集索引:ConsumeQueue 是定长的,每个消息都在里面有记录,可以通过下标定位到物理位置。
深度对比分析:核心差异点
| 特性 | Kafka (Partition-Based) | RocketMQ (CommitLog-Based) |
|---|---|---|
| 写入方式 | 分区内顺序写,多分区导致磁盘随机写 | 全局顺序写,所有消息写入一个文件 |
| Topic 数量影响 | 敏感。Topic/Partition 越多,磁盘随机 I/O 越严重,性能急剧下降。 | 不敏感。Topic 再多也只是写 CommitLog,性能几乎无衰减。 |
| 读取方式 | 直接读 Partition 文件,利用零拷贝 (sendfile) 效率极高。 | 先读 ConsumeQueue 再读 CommitLog,利用 Mmap。 |
| 数据可靠性 | 依赖副本机制 (ISR),单机可靠性相对较弱。 | 支持同步刷盘/异步刷盘,同步双写/异步复制,单机可靠性高。 |
| 消息查询 | 只能按 Offset 消费,不支持按 Key 查询。 | 支持按 Offset、Message Key 、时间段查询。 |
| 过滤机制 | 客户端过滤 (主要是)。 | 服务端过滤 (Tag/SQL92),减少无效数据传输。 |
适用场景推荐
1. 什么时候选 Kafka?
- 大数据日志采集:ELK stack,用户行为日志收集。
- 流式计算管道:配合 Spark Streaming、Flink 进行实时数仓建设。
- Topic 数量可控:业务场景不需要动态创建成千上万个 Topic。
- 容忍少量丢失,追求极致吞吐:例如监控打点数据。
2. 什么时候选 RocketMQ?
- 核心业务链路:订单、支付、交易、物流等金融级或电商级场景(阿里双11的核心)。
- 微服务解耦:系统庞大,微服务众多,导致 Topic 数量非常多。
- 需要复杂消息特性:需要使用分布式事务消息保持最终一致性,或者需要延时消息。
- 消息查询需求:经常需要通过 OrderID 或 TransactionID 去查询消息轨迹进行排错。
总结
- Kafka 是为了**"数据流"**而设计的,它不仅是队列,更是流存储平台。
- RocketMQ 是为了**"业务"**而设计的,它更像是一个可靠的、高性能的分布式消息总线。