`
m635674608
  • 浏览: 5030944 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

分布式消息队列RocketMQ与Kafka架构上的巨大差异之2 -- CommitLog与ConsumeQueue

    博客分类:
  • MQ
 
阅读更多

在前面Rocket与Kafka的对比之“拨乱反正”续篇中,我们已经提到了RocketMQ和Kafka在架构上面的一个巨大差异:Kafka是每个partition对应一个文件,而RocketMQ是把所有topic的所有queue的消息存储在一个文件里面,然后再分发给ConsumeQueue。

存储上的巨大差异

Kafka的存储

下图展示了Kafka的存储结构: 其中每个topic_partition对应一个日志文件,Producer对该日志文件进行“顺序写”,Consumer对该文件进行“顺序读”。

但正如在“拨乱反正”续篇中所提到的:这种存储方式,对于每个文件来说是顺序IO,但是当并发的读写多个partition的时候,对应多个文件的顺序IO,表现在文件系统的磁盘层面,还是随机IO。

因此出现了当partition或者topic个数过多时,Kafka的性能急剧下降。参见http://blog.csdn.net/chunlongyu/article/details/53913758

这里写图片描述

RocketMQ的存储

为了解决上述问题,RocketMQ采用了单一的日志文件,即把同1台机器上面所有topic的所有queue的消息,存放在一个文件里面,从而避免了随机的磁盘写入。其存储结构如下:

这里写图片描述

如上图所示,所有消息都存在一个单一的CommitLog文件里面,然后有后台线程异步的同步到ConsumeQueue,再由Consumer进行消费。

关键性差异

上面的存储差异,说的明显一点,就是:Kafka针对Producer和Consumer使用了同1份存储结构,而RocketMQ却为Producer和Consumer分别设计了不同的存储结构,Producer对应CommitLog, Consumer对应ConsumeQueue。

这其实也是“异步化“,或者说”离线计算“的一个典型例子。参见分布式思想汇总一文:http://blog.csdn.net/chunlongyu/article/details/52525604

这里至所以可以用“异步线程”,也是因为消息队列天生就是用来“缓冲消息”的。只要消息到了CommitLog,发送的消息也就不会丢。只要消息不丢,那就有了“充足的回旋余地”,用一个后台线程慢慢同步到ConsumeQueue,再由Consumer消费。

可以说,这也是在消息队列内部的一个典型的“最终一致性”的案例:Producer发了消息,进了CommitLog,此时Consumer并不可见。但没关系,只要消息不丢,消息最终肯定会进入ConsumeQueue,让Consumer可见。

CommitLog与ConsumeQueue结构

CommitLog的文件结构

下图展示了CommitLog的文件结构,可以看到,包含了topic、queueId、消息体等核心信息。

同Kafka一样,消息是变长的,顺序写入。

这里写图片描述

ConsumeQueue的文件结构

ConsumeQueue中并不需要存储消息的内容,而存储的是消息在CommitLog中的offset。也就是说,ConsumeQuue其实是CommitLog的一个索引文件。

如下图所示: 
这里写图片描述

ConsumeQueue是定长的结构,每1条记录固定的20个字节。很显然,Consumer消费消息的时候,要读2次:先读ConsumeQueue得到offset,再读CommitLog得到消息内容。

CommitLog的“顺序写”与“随机读”– MappedFileQueue

从上面的分析我们已经知道:对于ConsumeQueue,是完全的顺序读写。可是对于CommitLog,Producer对其“顺序写”,Consumer却是对其“随机读”。

对于这样的一个大型文件,又要随机读,如何提高读写效率呢?

答案就是“内存映射文件”。关于内存映射文件的原理,以后有机会,可以在LInux的篇章中,详细分析。此处就不展开了。

对于RocketMQ来说,它是把内存映射文件串联起来,组成了链表。因为内存映射文件本身大小有限制,只能是2G。所以需要把多个内存映射文件串联成一个链表,来和一个屋里文件对应起来。

public class CommitLog { ... private final MappedFileQueue mappedFileQueue; ... } */ public class ConsumeQueue { ... private final MappedFileQueue mappedFileQueue; ...

从上面源代码可以看出,无论CommitLog,还是ConsumeQueue,都有一个对应的MappedFileQueue,也就是对应的内存映射文件的链表。

public class MappedFileQueue { ... private final CopyOnWriteArrayList<MappedFile> mappedFiles = new CopyOnWriteArrayList<MappedFile>(); ... }

读写时,根据offset定位到链表中,对应的MappedFile,进行读写。

通过MappedFile,就很好的解决了大文件随机读的性能问题。

 

http://blog.csdn.net/quhongwei_zhanqiu/article/details/39144223

分享到:
评论

相关推荐

    消息中间件消息队列常见面试题

    RocketMQ使用了分布式存储和CommitLog机制,而Kafka则利用了高效的日志压缩和文件分段策略。这些设计使得它们在高吞吐量和低延迟方面表现出色。 【面试准备】 对于大厂的面试,理解消息队列的核心知识点,如消息不...

    【课程笔记】分布式消息通讯之Kafka的实现原理1

    分布式消息通讯之Kafka的实现原理 Kafka是一种高吞吐量、可持久化、可水平扩展、支持多分区的分布式消息队列系统。其核心实现原理可以分为两大部分:副本数据同步原理和副本leader选举原理。 副本数据同步原理: ...

    rocketMQ介绍ppt

    commitlog存储所有消息,consumeQueue用于消费队列,index存储消息key与offset的对应关系,方便快速查找。 ### 高可用设计 - **消息重试机制**:当发送失败时,RocketMQ会自动重试,以保证消息最终能够送达。 - **...

    kafka集群搭建与使用

    * 消息队列:Kafka 可以用来作为消息队列,例如处理订单、支付等业务逻辑。 Kafka 集群搭建与使用需要了解 Kafka 的设计理念和架构,了解 Kafka 的概念和组件,以及 Kafka 的性能和数据保留机制。同时,Kafka 也...

    kafka简介

    - **消息存储**: Kafka采用类似于commit-log的日志存储方式,即所有消息都被追加到磁盘上的文件中。这种方式不仅提高了写入速度,还降低了磁盘I/O开销。 - **消息分区**: 为了提高并行处理能力和存储容量,每个Topic...

    RocketMQ精选面试题50道(含答案解析)

    RocketMQ 是一款高性能、分布式的消息中间件,广泛应用于大型互联网公司的微服务架构中。以下是对RocketMQ面试题的详细解答,涵盖了多个MQ的选型、MQ的作用、RocketMQ的角色及特点、Topic与JMS Queue的区别以及消息...

    消息队列1

    RocketMQ的设计强调高性能和高可用性,通过CommitLog和ConsumeQueue实现消息的高效检索和顺序写盘,利用PageCache优化磁盘I/O。 ActiveMQ同样用Java编写,支持多种协议如OpenWire、STOMP等,消息存储在内存、磁盘和...

    RocketMQ面试中常见的问题及答案详解.docx

    - 消息在Broker上持久化到CommitLog,并维护消费者的消费进度(offset)。 - 消息不会在消费后立即删除,而是根据配置的保留时间(默认48小时)定期清理过期消息。清理过程通常在凌晨4点进行,检查文件最后访问...

    Kafka_API_文档

    - **负载均衡**: 分布式架构允许将数据均匀地分布在多个节点上。 - **异步发送**: 生产者可以异步发送消息,从而提高吞吐量。 **6.4 消费者** - **推送vs拉取**: 消费者可以选择接收数据的方式。 - **消费者位置**...

    Kafka常见23道面试题以答案.docx

    Kafka是一个流行的分布式消息队列系统,广泛应用于异步处理、日常系统解耦、削峰、提速、广播等场景。本文将详细解释Kafka面试题答案,涵盖Kafka的用途、ISR、AR、HW、LEO、LSO、LW等概念,以及Kafka的消息顺序性、...

    基于Kafka构建的Java日志系统.zip

    Kafka是一个高吞吐量、低延迟的消息队列,它允许生产者发布消息到主题(topics),然后消费者可以从这些主题中订阅并消费消息。在日志系统中,我们可以将每个应用程序视为一个生产者,将日志事件作为消息发布到Kafka...

    jocko:Kafka通过内置协调在Golang中实现(无需ZooKeeper,单个二进制安装,Cloud Native)

    黑猩猩 Go中与Kafka有线兼容的分布式提交日志服务。 由创建,由继续。目标: 协议与Kafka兼容,因此Kafka客户端和服务可与Jocko一起使用分发一个二进制文件使用Serf进行发现,使用Raft进行共识(并消除了运行...

    Java实时回单同步的代码

    2. **消息队列**:在高并发环境下,为了保证系统的稳定性和可扩展性,通常会采用消息队列(如RabbitMQ、Kafka或ActiveMQ)进行解耦。交易完成后,系统会将回单信息发送到消息队列,消费者端接收到消息后进行同步操作...

Global site tag (gtag.js) - Google Analytics