背景
消息队列中间件(简称消息中间件)是指利用高效可靠的消息传递机制进行与平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息排队模型,它可以在分布式环境下提供应用解耦、弹性伸缩、冗余存储、流量削峰、异步通信、数据同步等等功能,其作为分布式系统架构中的一个重大组件,有着举足轻重的地位。本文将对比一下kafka和RabbitMQ。
Kafka
介绍
Kafka起初是由 LinkedIn 公司采用 Scala 语言开发的一个分布式、多分区、多副本且基于 zookeeper 协调的分布式消息系统,现已捐献给 Apache 基金会。它是一种高吞吐量的分布式发布订阅消息系统,以可水平扩展和高吞吐率而被广泛使用。目前越来越多的开源分布式处理系统如 Cloudera、Apache Storm、Spark、Flink 等都支持与 Kafka 集成。Kafka 高吞吐率的在于批量异步推送、零拷贝技术、文件分段、服务端顺序写、数据压缩、批量拉取。

特点
- 高吞吐量:Kafka 每秒可以生产约 25 万消息(50 MB),每秒处理 55 万消息(110 MB)
- 持久化数据存储:可进行持久化操作。将消息持久化到磁盘上,因此可用于批量消费,例如 ETL,以及实时应用程序。通过将数据持久化到硬盘以及replication 防止数据丢失。
- 分布式系统易于扩展:所有的producer、broker 和 consumer 都会有多个,均为分布式的。无需停机即可扩展机器。
- 客户端状态维护:消息被处理的状态是在 consumer 端维护,而不是由 server 端维护。当失败时能自动平衡。
场景
- 消息系统:Kafka作为一款优秀的消息系统,具有高吞吐量、内置的分区、备份冗余分布式等特点,为大规模消息处理提供了一种很好的解决方案。
- 应用监控:利用Kafka采集应用程序和服务器健康相关的指标,如CPU占用率、IO、内存、连接数、TPS、QPS等,然后将指标信息进行处理,从而构建一个具有监控仪表盘、曲线图等可视化监控系统。例如,许多公司采用Kafka与ELK(ElasticSearch、Logstash和Kibana)整合构建应用服务监控系统。
- 网站用户行为追踪:为了更好地了解用户行为、操作习惯,改善用户体验,进而对产品升级改善,将用户操作轨迹、内容等信息发送到Kafka集群上,通过Hadoop、Spark或Strom等进行数据分析处理,生成相应的统计报告,为推荐系统推荐对象建模提供数据源,进而为每个用户进行个性化推荐。
- 流处理:需要将已收集的流数据提供给其他流式计算框架进行处理,用Kafka收集流数据是一个不错的选择,而且当前版本的Kafka提供了Kafka Streams支持对流数据的处理。
- 持久性日志:Kafka可以为外部系统提供一种持久性日志的分布式系统。日志可以在多个节点间进行备份,Kafka为故障节点数据恢复提供了一种重新同步的机制。同时,Kafka很方便与HDFS和Flume进行整合,这样就方便将Kafka采集的数据持久化到其他外部系统。
架构
基本概念
- Broker:Kaka集群中的一台或多台服务器称为Broker
- Topic:发布到Kafka的每条消息都有一个类别,是个逻辑概念。物理上不同Topic的消息分开存储,逻辑上一个Topic的消息虽然保存于一个或多个broker上,但用户只需指定消息的Topic即可生产或消费数据而不必关心数据存于何处
- Partition:物理上的Topic分区,一个Topic可以分为多个Partition,至少有一个Partition。每个Partition中的数据使用多个segment文件存储,每个Partition都是一个有序的队列,不同Partition间的数据是无序的。Partition中的每条消息都会被分配一个有序的ID(即offset)。
- Replica: 副本因子,为实现备份的功能,保证集群中的某个节点发生故障时,该节点上的 partition 数据不丢失,且 Kafka 依旧能够继续工作,Kafka 提供了副本机制,一个 topic 的每个分区都有若干个副本,一个 leader 和若干个 follower。
- Producer:消息和数据的生产者。Producer将消息发布到Kafka的topic中。Broker接收到Producer发布的消息后,Broker将该消息追加到当前用于追加数据的segment文件中。Producer发送的消息,存储到一个Partition中,Producer也可以指定数据存储的Partition。
- Consumer:消息和数据的消费者。Consumer从Broker中读取数据。Consumer可以消费多个topic中的数据。
- Consumer Group:每个消费者都属于一个特定的消费者组。可为每个Consumer指定group name,若不指定group name则属于默认的group。一个Topic可以有多个消费者组,Topic的消息会被复制到所有的消费者组中,但每个消费者组只会把消息发送给该组中的一个消费者。消费者组是Kafka用来实现一个Topic消息的广播和单播的手段。
- Leader:每个Partition有多个副本,其中有且仅有一个作为leader。Leader是当前负责数据的读写的Partition。
- Follower:Follower跟随Leader,所有写请求都通过Leader路由,数据变更会广播给所有Follower,Follower与Leader保持数据同步。如果Leader失效,则从Follower中选举出一个新的Leader。如果Follower与Leader挂掉、卡住或同步太慢,Leader会把这个Follower从"in sync replicas"## 高吞吐量的分布式消息组件Kafka是如何工作的
架构介绍
集群架构,如下Kafka 集群中有4个 broker,某个主题中有3个分区,且副本因子(即副本个数)也为3,如此每个分区便有1个 leader 副本和2个 follower 副本

生产者客户端的整体结构,整个生产者客户端由两个线程协调运行,这两个线程分别为主线程和 Sender 线程(发送线程)。在主线程中由 KafkaProducer 创建消息,然后通过可能的拦截器、序列化器和分区器的作用之后缓存到消息累加器(RecordAccumulator,也称为消息收集器)中。Sender 线程负责从 RecordAccumulator 中获撤销息并将其发送到 Kafka 中。RecordAccumulator 主要用来缓存消息以便 Sender 线程可以批量发送,进而减少网络传输的资源消耗以提升性能。请求在从 Sender 线程发往 Kafka 之前还会保存到 InFlightRequests 中,它的主要作用是缓存了已经发出去但还没有收到响应的请求。

RabbitMQ
介绍
RabbitMQ 是采用 Erlang 语言实现的 AMQP 协议的消息中间件,最初起源于金融系统,用于在分布式系统中存储转发消息。RabbitMQ 发展到今天,被越来越多的人认可,这和它在可靠性、可用性、扩展性、功能丰富等方面的卓越表现是分不开的。

特点
- 可靠性(Reliablity):使用了一些机制来保证可靠性,列如持久化、传输确认、发布确认。
- 灵活的路由(Flexible Routing):在消息进入队列之前,通过Exchange来路由消息。对于典型的路由功能,Rabbit已经提供了一些内置的Exchange来实现。针对更复杂的路由功能,可以将多个Exchange绑定在一起,也通过插件机制实现自己的Exchange。
- 消息集群(Clustering):多个RabbitMQ服务器可以组成一个集群,形成一个逻辑Broker。
- 高可用(Highly Avaliable Queues):队列可以在集群中的机器上进行镜像,使得在部分节点出问题的情况下队列依旧可用。
- 多种协议(Multi-protocol):支持多种消息队列协议,如STOMP、MQTT等。
- 多种语言客户端(Many Clients):几乎支持所有常用语言,列如Java、.NET、Ruby等。
- 管理界面(Management UI):提供了易用的用户界面,使得用户可以监控和管理消息Broker的许多方面。
- 跟踪机制(Tracing):如果消息异常,RabbitMQ提供了消息的跟踪机制,使用者可以找出发生了什么。
- 插件机制(Plugin System):提供了许多插件,来从多方面进行扩展,也可以编辑自己的插件。
场景
- 应用解偶:系统间交互采用mq进行数据传输,像这种不同系统利用mq进行数据的传递是不错的选择,但是遇到海量的数据,但是不提议使用mq进行去传递,一般mq擅长传递小规模的数据
- 流量削峰:例如像阿里的双十一进行秒杀的时候或者进行系统最忙碌的时候,进行流量控制的时候,削峰,平谷
- 消息通知:mq本身支持定阅和发布的模式或者是进行点对点消费的模式
- 高可靠系统:rabbitmq最值得骄傲的是高可靠性,对于应用来说mq本身就是高可靠性,同时对数据也进行了高可靠的支持,几乎不会出现数据mq的层面上丢失的情况
架构
基本概念
- Broker:它提供一种传输服务,它的角色就是维护一条从生产者到消费者的路线,保证数据能按照指定的方式进行传输
- Exchange:消息交换机,它指定消息按什么规则,路由到哪个队列。
- Queue:消息的载体,每个消息都会被投到一个或多个队列。
- Binding:绑定,它的作用就是把exchange和queue按照路由规则绑定起来.
- Routing Key:路由关键字,exchange根据这个关键字进行消息投递。
- vhost:虚拟主机,一个broker里可以有多个vhost,用作不同用户的权限分离。
- Producer:消息生产者,就是投递消息的程序.
- Consumer:消息消费者,就是接受消息的程序.
- Channel:消息通道,在客户端的每个连接里,可建立多个channel.
整体架构
消息生产者并没有直接将消息发送给消息队列,而是通过建立与Exchange的Channel,将消息发送给Exchange,Exchange根据规则,将消息转发给指定的消息队列。消费者通过建立与消息队列相连的Channel,从消息队列中获撤销息。

运行流程
第一生产者将业务方数据进行可能的包装,之后封装成消息,发送到 Broker 中。消费者订阅并接收消息,经过可能的解包处理得到原始的数据,之后再进行业务处理逻辑。这个业务处理逻辑并不必定需要和接收消息的逻辑使用同一个线程。消费者进程可以使用一个线程去接收消息,存入到内存中,列如使用 Java 中的 BlockingQueue。业务处理逻辑使用另一个线程从内存中读取数据,这样可以将应用进一步解耦,提高整个应用的处理效率。

交换机类型
- Direct Exchange 直连交换机:发送消息到直连类型的交换机时,只有routing key跟binding key完全匹配时,绑定的队列才能收到消息。
- Topic Exchange 主题交换机:发送消息到主题类型的交换机时,routing key符合binding key的模式时,绑定的队列才能收到消息。主题类型的交换机与一个队列绑定时,可以指定按模式匹配的routing key。通配符有两个,*代表匹配一个单词。#代表匹配零个或者多个单词。单词与单词之间用 . 隔开
- Fanout Exchange 广播交换机:当消息发送到广播类型的交换机时,不需要指定routing key,所有与之绑定的队列都能收到消息。
- Header Exchange 头交换机 :headers与direct的模式不同,不是使用routingkey去做绑定。而是通过消息headers的键值对匹配
总结
RabbitMQ与Kafka都有很好的客户端语言支持、安全机制与生态支持。Kafka的诞生的是处理高并发日志的,吞吐量比较高,每秒请求数达到数十万量级,RabbitMQ每秒请求数则为万级别,有测试报告指出Kafka是RabbitMQ的10倍以上性能,RabbitMQ具有死信的功能,可以通过死信形成重复消费与延时发送。对于选择Kafka还是RabbitMQ,主要思考三个因素:吞吐量、运维能力和平台熟悉度。如果是需要流处理和高并发的日志处理,首选Kafka。但是大部分公司并没有什么高并发的处理,因此可以着重思考运维程度和平台熟悉度。RabbiMQ运维比较直接,包括客户端EasyNetQ使用简易性,基本上就是”开箱即用“。
对比项 | RabbitMQ | Kafka |
吞吐量 | 低 | 高 |
有序性 | 全局有序性 | 分区有序性 |
消息可靠性 | 多策略组合 | 消息持久化 |
流处理 | 不支持 | 支持 |
时效性 | 高 | 中 |
运维便捷度 | 高 | 中 |
系统依赖 | 无 | zookeeper(新版本已经不需要) |
Web监控 | 自带 | 第三方 |
优先级队列 | 支持 | 不支持 |
死信 | 支持 | 不支持 |
客户端支持 | 支持多种语言 |
社区生态 | 好 |
安全机制 | (TLS/SSL、SASL)身份认证和(读写)权限控制 |
消息回溯 | 支持 | 不支持 |
应用场景 | 分布式、高可靠系统 | 日志处理及大数据应用 |