Kafka与RocketMQ:消息队列的华山论剑

653 阅读15分钟

一、前言

在分布式系统的宏大版图中,消息队列宛如一座沟通的桥梁,连接着各个独立的服务与组件,为它们提供了一种高效、可靠的异步通信方式。它的核心作用在于解耦、异步处理和削峰填谷,就像是一个智能的协调者,让整个分布式系统的运作更加流畅和稳定。

而在众多的消息队列中间件中,Kafka 和 RocketMQ 无疑是两颗璀璨的明星,它们以各自独特的优势和特点,在不同的领域和场景中发挥着重要作用。

接下来,就让我们深入剖析这两款消息队列中间件,一探究竟它们的异同与优劣。

二、Kafka的特点与优势

2.1 架构剖析

Image1.png

如上图,我们逐一介绍其中的组成组件。

Producer(生产者)作为消息的源头,负责将应用程序产生的消息发送到 Kafka 集群中。它就像是一位勤劳的快递员,将包裹(消息)源源不断地送到 Kafka 这个 “物流中心”。Producer 在发送消息时,可以根据不同的策略选择将消息发送到特定的 Topic(主题)和 Partition(分区)。例如,在一个电商系统中,订单创建的消息可以由 Producer 发送到名为 “order - created” 的 Topic 中,以便后续的处理。

Consumer(消费者)则是消息的接收者,它从 Kafka 集群中拉取消息并进行处理。Consumer 可以订阅一个或多个 Topic,就像订阅报纸一样,只接收自己感兴趣的内容。Consumer 通常以 Consumer Group(消费者组)的形式存在,同一组内的 Consumer 会共同消费订阅的 Topic 中的消息,每个 Partition 只会被组内的一个 Consumer 消费,这样可以实现负载均衡和并行处理。比如,在一个日志处理系统中,多个 Consumer 可以组成一个 Consumer Group,共同消费 “system - logs” 主题的日志消息,提高处理效率。

Broker 是 Kafka 集群中的服务实例,它负责存储和管理消息。多个 Broker 组成的集群可以提供高可用性和扩展性。每个 Broker 都可以存储多个 Topic 的 Partition,并且可以通过配置副本(Replicas)来保证数据的可靠性。当某个 Broker 出现故障时,其他副本可以迅速接替工作,确保消息的正常读写。

Topic 是消息的逻辑分类,每个 Topic 可以看作是一个消息的集合。生产者将消息发送到特定的 Topic,消费者则从感兴趣的 Topic 中订阅消息。通过 Topic 的划分,可以方便地对不同类型的消息进行管理和处理。比如,在一个社交媒体平台中,可以创建不同的 Topic 来分别存储用户动态、评论、点赞等消息。

Partition 是 Topic 的物理分区,每个 Topic 可以包含多个 Partition。Partition 的设计不仅提高了消息处理的并行性,还增强了系统的扩展性和容错性。不同的 Partition 可以分布在不同的 Broker 上,从而实现负载均衡。同时,每个 Partition 都有一个 Leader 副本和多个 Follower 副本,Leader 负责处理读写请求,Follower 则实时同步 Leader 的数据,当 Leader 出现故障时,Follower 可以自动选举出新的 Leader,保证数据的一致性和可用性。这里的主从也就是Replicas机制。

在早期的 Kafka 版本中,ZooKeeper 扮演着至关重要的角色,它是一个通用的分布式协调服务,用于管理 Kafka 集群中的元数据信息,如 Broker 的注册、Topic 的创建和删除、Partition 的分配等。同时,ZooKeeper 还负责维护 Consumer 的消费进度,确保 Consumer 在故障恢复后能够从正确的位置继续消费消息。然而,在最新的 Kafka 版本中,引入了自带的 KRaft 机制,逐渐取代了 ZooKeeper 的部分功能,使得 Kafka 的架构更加简洁和高效 。

2.2 性能表现

Kafka 以其卓越的性能表现,在众多消息队列中间件中脱颖而出,成为了大规模数据处理场景下的首选。

  • 顺序写磁盘:Kafka 的消息存储采用了顺序写磁盘的方式,这与传统的随机写磁盘相比,大大提高了 I/O 性能。在 Kafka 中,每个 Partition 都是一个有序的消息序列,消息按照时间顺序追加到磁盘上,避免了磁盘寻道时间,使得写入速度接近磁盘的顺序写入速度。这种高效的写入方式,使得 Kafka 能够轻松应对高并发的消息写入请求。

  • 零拷贝技术:为了进一步提升数据传输效率,Kafka 引入了零拷贝技术。传统的数据传输过程需要经过多次数据拷贝,从磁盘到内核空间,再从内核空间到用户空间,最后从用户空间到网络接口。而 Kafka 使用的 sendfile 技术,实现了数据从内核空间缓冲区直接拷贝到网卡,减少了 CPU 拷贝的次数,只有 DMA(直接内存访问)控制器在参与工作,从而大大提高了数据传输的速度。这种零拷贝技术的应用,使得 Kafka 在高吞吐量的场景下依然能够保持极低的延迟。

2.3 应用场景

Kafka 凭借其强大的性能和灵活的架构,在各个领域都有着广泛的应用。

  • 日志收集:在分布式系统中,各个服务产生的日志数据量巨大,且格式各异。Kafka 可以作为一个统一的日志收集平台,将不同服务的日志数据收集起来,并进行集中存储和管理。通过 Kafka 的高吞吐量和低延迟特性,能够确保日志数据的实时传输和处理,为后续的日志分析、故障排查等工作提供有力支持。

  • 大数据处理:在大数据领域,Kafka 常常与 Hadoop、Spark 等大数据处理框架结合使用。它可以作为数据的来源,将实时产生的数据快速传输到大数据处理平台,进行实时分析和挖掘。例如,在电商领域,可以通过 Kafka 收集用户的行为数据,如浏览记录、购买记录等,然后利用大数据处理框架对这些数据进行分析,为精准营销、个性化推荐等业务提供数据支持。

  • 实时流处理:对于实时性要求较高的场景,如金融交易监控、物联网设备数据处理等,Kafka 可以作为实时流处理的消息管道。它能够快速地接收和分发数据,确保数据的实时性和准确性。同时,结合一些流处理框架,如 Apache Flink、Apache Storm 等,可以对实时数据进行实时计算和处理,及时发现异常情况并做出响应。

三、RocketMQ 的特点与优势

RocketMQ参考了Kafka的架构设计并做了调整,在架构上做了减法,在功能上做了加法

3.1 架构剖析

Image2.png

Producer:Producer 负责将应用程序产生的消息发送到 RocketMQ 集群。它可以根据业务需求,选择不同的发送模式,如同步发送、异步发送和单向发送。同步发送会等待 Broker 的确认响应,确保消息发送成功;异步发送则会在发送消息后立即返回,通过回调函数来处理发送结果;单向发送则不等待任何响应,直接将消息发送出去,适用于对消息可靠性要求不高的场景。此外,Producer 还支持消息的批量发送和事务消息的发送,进一步提高了消息发送的效率和可靠性。

Consumer:Consumer 是消息的接收者和处理者,它从 Broker 中拉取消息并进行消费。RocketMQ 的 Consumer 支持两种消费模式:集群消费和广播消费。在集群消费模式下,同一 Consumer Group 内的多个 Consumer 实例共同消费一个 Topic 的消息,每个 Consumer 实例只消费其中的一部分,实现了负载均衡;在广播消费模式下,每个 Consumer 实例都会消费 Topic 的所有消息,适用于需要将消息广播给所有消费者的场景。同时,RocketMQ 还提供了丰富的消息过滤机制,消费者可以根据自己的需求,对消息进行灵活的过滤和筛选。

NameServer:这是 RocketMQ 的核心组件之一,它是一个轻量级的分布式协调服务,取代了 Kafka 中的 Zookeeper。NameServer 主要负责管理 Broker 的元数据信息,包括 Broker 的地址、Topic 与 Broker 的映射关系等。它采用了去中心化的设计理念,各个 NameServer 节点之间相互独立,没有主从之分,从而避免了单点故障的问题。Producer 和 Consumer 通过定期向 NameServer 发送心跳请求,获取最新的 Broker 信息,实现了服务的自动发现和动态感知。

Broker:Broker 是 RocketMQ 的消息存储和转发中心,它负责接收 Producer 发送的消息,并将其存储到磁盘上,同时为 Consumer 提供消息的拉取服务。与 Kafka 不同的是,RocketMQ 的 Broker 采用了一种独特的存储结构,它将所有 Topic 的消息统一存储在一个 CommitLog 文件中,而不是像 Kafka 那样每个 Partition 对应一个文件(segment)。这种设计大大减少了文件数量,降低了随机写概率,降低了磁盘 I/O 的压力,提高了存储和读写效率。同时,RocketMQ 还支持 Broker 的主从复制,通过异步复制的方式,将主 Broker 的数据同步到从 Broker,确保数据的可靠性和高可用性。

Queue: rocketMQ用queue代替了partition,原partition中保留消息的完整信息,而queue只有简要信息,比如offset,完整的消息在commitlog中,通过offset去获取

3.2 功能特性

RocketMQ 不仅在架构上有着独特的优势,在功能特性方面也表现出色,为开发者提供了丰富的功能支持。

  • 事务消息:RocketMQ 支持事务消息的发送,它通过引入 Half Message(半消息)机制,实现了消息发送与本地事务的原子性操作。在发送事务消息时,Producer 首先向 Broker 发送一个 Half Message,此时消息对 Consumer 不可见。然后,Producer 执行本地事务,如果本地事务执行成功,Producer 向 Broker 发送 Commit 消息,将 Half Message 标记为可消费;如果本地事务执行失败,Producer 向 Broker 发送 Rollback 消息,删除 Half Message。这种机制确保了在分布式事务场景下,消息的发送与本地业务操作的一致性。

  • 顺序消息:在某些业务场景中,消息的顺序性至关重要,如电商订单的处理、金融交易的清算等。RocketMQ 提供了严格的顺序消息支持,它通过将同一业务逻辑的消息发送到同一个 Queue 中,并由同一个 Consumer 按照先进先出的顺序进行消费,保证了消息的顺序性。同时,RocketMQ 还支持分区顺序消息,即在一个分区内保证消息的顺序性,而不同分区之间的消息顺序可以不一致,满足了不同业务场景对消息顺序性的要求。

  • 消息过滤:RocketMQ 支持在 Broker 端对消息进行过滤,消费者可以根据自己的需求,通过设置消息的 Tag 或 SQL 表达式来筛选感兴趣的消息。这种消息过滤机制大大减少了 Consumer 不必要的消息拉取和处理,提高了系统的性能和效率。例如,在一个电商系统中,消费者可以通过设置 Tag 为 “订单创建”,只接收和处理与订单创建相关的消息,而忽略其他类型的消息。

  • 延时队列:延时队列是一种特殊的消息队列,它允许消息在指定的时间后被消费。RocketMQ 原生支持延时队列,通过设置消息的延时级别,实现了消息的延迟发送和消费。这种功能在一些需要定时处理的业务场景中非常有用,如订单超时取消、优惠券过期提醒等。

  • 死信队列:当消息在消费过程中出现多次失败后,RocketMQ 会将其发送到死信队列中,以便后续的排查和处理。死信队列的存在,避免了因消息消费失败而导致的业务异常,提高了系统的稳定性和可靠性。同时,RocketMQ 还支持对死信队列中的消息进行重新投递和处理,方便开发者对异常消息进行修复和重试。

3.3 应用场景

RocketMQ 凭借其强大的功能和卓越的性能,在各个领域都有着广泛的应用。

  • 金融领域:在金融行业,对消息的可靠性和顺序性要求极高。RocketMQ 的事务消息、顺序消息等特性,能够确保金融交易的准确性和一致性,满足了金融业务对消息处理的严格要求。例如,在证券交易系统中,RocketMQ 可以用于处理订单的创建、撤销、成交等消息,保证交易的实时性和可靠性。

  • 电商领域:在电商系统中,RocketMQ 可以用于处理订单的创建、支付、发货等业务流程。它的高并发处理能力和丰富的功能特性,能够满足电商业务在促销活动、秒杀等场景下对消息处理的高要求。同时,RocketMQ 的消息过滤和延时队列功能,还可以用于实现精准营销、订单超时处理等业务逻辑。

  • 物联网领域:在物联网场景中,大量的设备会产生海量的实时数据。RocketMQ 可以作为物联网数据的传输和处理平台,通过其高吞吐量和低延迟的特性,确保设备数据的实时传输和处理。同时,RocketMQ 的消息过滤和分组功能,还可以对设备数据进行有效的管理和分析,为物联网应用提供有力支持。

四、对比与总结

4.1 对比

4.1.1 性能对比

一般场景下,Kafka性能优于RocketMQ,rocketMQ每秒10W,kafka每秒17W,几乎翻倍。那么Kafka性能为什么更高呢?与其运用的零拷贝技术有所不同有关。

发消息一般需要从磁盘拷贝一份数据传到内核空间,内核空间再拷贝一份数据到用户空间,用户空间再拷贝一份到内核空间,内核空间再拷贝一份到网卡,完成消息发送的过程。

而这里两个MQ对这块的优化用到了零拷贝技术。

rocketMQ用了mmap技术,这是操作系统自带的方法,大致流程为磁盘拷贝一份数据传到内核空间后,mmap在用户空间保留了一份映射(这里就不是拷贝过去了),然后映射拷贝到内核空间的socket缓存,再从缓存拷贝到网卡,总共3次数据拷贝。这里的零拷贝指的是内核空间与用户空间之间的拷贝。

kafka用了sendfile技术,大致流程为磁盘拷贝一份数据到内核空间缓冲器,内核空间缓冲区可以之间拷贝到网卡,总共2次数据拷贝。这里的零拷贝是指0CPU拷贝,这里只有DMA控制器在参与工作。

而因为mmap方法返回的是数据信息,sendfile只返回发送出去的字节数。只有有数据信息才能做一些额外功能,比如打tag、死信队列等。所以这块rocketMQ在底层设计上的性能难以超过kafka

4.1.2 功能特性对比

在功能特性方面,RocketMQ 则优于Kafka。Kafka 原生支持消息的分区和多副本复制,保证了数据的高可用性和容错性,并且提供了丰富的流处理功能,如 Kafka Streams API 可用于构建实时数据管道和微批处理应用。但是,Kafka 在消息事务、消息顺序、消息过滤等方面的功能相对较弱,需要开发者自行处理。

RocketMQ 则提供了更为丰富的功能特性,它支持事务消息、顺序消息、消息过滤、延时队列、死信队列等功能,能够满足复杂业务场景的需求。例如,在金融交易场景中,RocketMQ 的事务消息功能可以确保交易的原子性,保证资金的安全;顺序消息功能可以保证交易消息的顺序性,避免交易混乱。

4.2 总结

根据上述对比,我们可以总结出在不同应用场景下如何选择 Kafka 或 RocketMQ。如果你的应用场景主要是处理大规模的数据流,对吞吐量和性能要求较高,如日志收集、实时流处理、大数据集成等场景,那么 Kafka 可能是更好的选择。它能够高效地处理海量数据,并且与许多大数据处理框架有良好的集成,方便进行实时数据分析和流式处理。

而如果你的应用场景对消息的可靠性、顺序性和事务完整性要求较高,如金融交易、订单处理、秒杀活动等场景,那么 RocketMQ 则更为适合。它提供的金融级别的消息可靠性保障、事务消息和顺序消息等功能,能够确保业务的正确性和一致性。