Article / 文章中心

17 个方面,综合对比 Kafka、RabbitMQ、RocketMQ、ActiveMQ 四个分布式消息队列

发布时间:2022-01-27 点击数:852

本文将从,Kafka、RabbitMQ、ZeroMQ、RocketMQ、ActiveMQ 17 个方面综合比照作为音讯行列运用时的差异。

良心引荐:如下 10 篇文章,是艿艿写的四种 MQ 在 Spring Boot、Spring Cloud 的实战文章~~~

一、材料文档

Kafka:中。有kafka作者自己写的书,网上材料也有一些。rabbitmq:多。有一些不错的书,网上材料多。zeromq:少。没有专门写zeromq的书,网上的材料多是一些代码的完成和简略介绍。rocketmq:少。没有专门写rocketmq的书,网上的材料良莠不齐,官方文档很简洁,可是对技能细节没有过多的描绘。activemq:多。没有专门写activemq的书,网上材料多。

二、开发言语

Kafka:Scala rabbitmq:Erlang zeromq:c rocketmq:java activemq:java

三、支撑的协议

Kafka:自己界说的一套...(依据TCP) rabbitmq:AMQP zeromq:TCP、UDP rocketmq:自己界说的一套... activemq:OpenWire、STOMP、REST、XMPP、AMQP

四、音讯存储

Kafka:内存、磁盘、数据库。支撑许多堆积。

kafka的最小存储单元是分区,一个topic包括多个分区,kafka创立主题时,这些分区会被分配在多个服务器上,一般一个broker一台服务器。分区首体会均匀地散布在不同的服务器上,分区副本也会均匀的散布在不同的服务器上,确保负载均衡和高可用性,当新的broker参加集群的时分,部分副本会被移动到新的broker上。依据装备文件中的目录清单,kafka会把新的分区分配给目录清单里分区数最少的目录。默认状况下,分区器运用轮询算法把音讯均衡地散布在同一个主题的不同分区中,关于发送时指定了key的状况,会依据key的hashcode取模后的值存到对应的分区中。

rabbitmq:内存、磁盘。支撑少量堆积。

rabbitmq的音讯分为耐久化的音讯和非耐久化音讯,不管是耐久化的音讯还是非耐久化的音讯都能够写入到磁盘。耐久化的音讯在到达行列时就写入到磁盘,并且假如能够,耐久化的音讯也会在内存中保存一份备份,这样能够进步必定的功能,当内存吃紧的时分会从内存中清除。非耐久化的音讯一般只存在于内存中,在内存吃紧的时分会被换入到磁盘中,以节省内存。

引进镜像行列机制,可将重要行列“仿制”到集群中的其他broker上,确保这些行列的音讯不会丢掉。装备镜像的行列,都包括一个主节点master和多个从节点slave,假如master失效,参加时刻最长的slave会被提升为新的master,除发送音讯外的一切动作都向master发送,然后由master将指令履行结果播送给各个slave,rabbitmq会让master均匀地散布在不同的服务器上,而同一个行列的slave也会均匀地散布在不同的服务器上,确保负载均衡和高可用性。

zeromq:音讯发送端的内存或许磁盘中。不支撑耐久化。

rocketmq:磁盘。支撑许多堆积。

commitLog文件寄存实际的音讯数据,每个commitLog上限是1G,满了之后会主动新建一个commitLog文件保存数据。ConsumeQueue行列只寄存offset、size、tagcode,十分小,散布在多个broker上。ConsumeQueue相当于CommitLog的索引文件,顾客消费时会从consumeQueue中查找音讯在commitLog中的offset,再去commitLog中查找元数据。

ConsumeQueue存储格式的特性,确保了写过程的次序写盘(写CommitLog文件),许多数据IO都在次序写同一个commitLog,满1G了再写新的。加上rocketmq是累计4K才强制从PageCache中刷到磁盘(缓存),所以高并发写功能突出。

activemq:内存、磁盘、数据库。支撑少量堆积。

五、音讯事务

Kafka:支撑 rabbitmq:支撑。客户端将信道设置为事务办法,只要当音讯被rabbitMq接纳,事务才能提交成功,否则在捕获异常后进行回滚。运用事务会使得功能有所下降 zeromq:不支撑 rocketmq:支撑 activemq:支撑

六、负载均衡

Kafka:支撑负载均衡。

1>一个broker一般就是一台服务器节点。关于同一个Topic的不同分区,Kafka会极力将这些分区散布到不同的Broker服务器上,zookeeper保存了broker、主题和分区的元数据信息。分区首体会处理来自客户端的出产恳求,kafka分区首体会被分配到不同的broker服务器上,让不同的broker服务器一起分管使命。

每一个broker都缓存了元数据信息,客户端能够从恣意一个broker获取元数据信息并缓存起来,依据元数据信息知道要往哪里发送恳求。

2>kafka的顾客组订阅同一个topic,会尽或许地使得每一个顾客分配到相同数量的分区,分摊负载。

3>当顾客参加或许退出顾客组的时分,还会触发再均衡,为每一个顾客重新分配分区,分摊负载。

kafka的负载均衡大部分是主动完成的,分区的创立也是kafka完成的,躲藏了许多细节,避免了繁琐的装备和人为忽略构成的负载问题。

4>发送端由topic和key来决议音讯发往哪个分区,假如key为null,那么会运用轮询算法将音讯均衡地发送到同一个topic的不同分区中。假如key不为null,那么会依据key的hashcode取模计算出要发往的分区。

rabbitmq:对负载均衡的支撑欠好。

1>音讯被投递到哪个行列是由交换器和key决议的,交换器、路由键、行列都需求手动创立。

rabbitmq客户端发送音讯要和broker树立衔接,需求事先知道broker上有哪些交换器,有哪些行列。一般要声明要发送的方针行列,假如没有方针行列,会在broker上创立一个行列,假如有,就什么都不处理,接着往这个行列发送音讯。假设大部分深重使命的行列都创立在同一个broker上,那么这个broker的负载就会过大。(能够在上线前预先创立行列,无需声明要发送的行列,可是发送时不会尝试创立行列,或许呈现找不到行列的问题,rabbitmq的备份交换器会把找不到行列的音讯保存到一个专门的行列中,以便以后查询运用)

运用镜像行列机制树立rabbitmq集群能够处理这个问题,构成master-slave的架构,master节点会均匀散布在不同的服务器上,让每一台服务器分摊负载。slave节点仅仅负责转发,在master失效时会选择参加时刻最长的slave成为master。

当新节点参加镜像行列的时分,行列中的音讯不会同步到新的slave中,除非调用同步指令,可是调用指令后,行列会阻塞,不能在出产环境中调用同步指令。

2>当rabbitmq行列具有多个顾客的时分,行列收到的音讯将以轮询的分发办法发送给顾客。每条音讯只会发送给订阅列表里的一个顾客,不会重复。

这种办法十分合适扩展,并且是专门为并发程序设计的。

假如某些顾客的使命比较深重,那么能够设置basicQos约束信道上顾客能坚持的最大未承认音讯的数量,在到达上限时,rabbitmq不再向这个顾客发送任何音讯。

3>关于rabbitmq而言,客户端与集群树立的TCP衔接不是与集群中一切的节点树立衔接,而是挑选其间一个节点树立衔接。

可是rabbitmq集群能够借助HAProxy、LVS技能,或许在客户端运用算法完成负载均衡,引进负载均衡之后,各个客户端的衔接能够分摊到集群的各个节点之中。

客户端均衡算法:

1)轮询法。按次序回来下一个服务器的衔接地址。

2)加权轮询法。给装备高、负载低的机器装备更高的权重,让其处理更多的恳求;而装备低、负载高的机器,给其分配较低的权重,降低其体系负载。

3)随机法。随机选取一个服务器的衔接地址。

4)加权随机法。依照概率随机选取衔接地址。

5)源地址哈希法。经过哈希函数计算得到的一个数值,用该数值对服务器列表的巨细进行取模运算。

6)最小衔接数法。动态选择当时衔接数最少的一台服务器的衔接地址。

zeromq:去中心化,不支撑负载均衡。自身仅仅一个多线程网络库。

rocketmq:支撑负载均衡。

一个broker一般是一个服务器节点,broker分为master和slave,master和slave存储的数据相同,slave从master同步数据。

1>nameserver与每个集群成员坚持心跳,保存着Topic-Broker路由信息,同一个topic的行列会散布在不同的服务器上。

2>发送音讯经过轮询行列的办法发送,每个行列接纳均匀的音讯量。发送音讯指定topic、tags、keys,无法指定投递到哪个行列(没有意义,集群消费和播送消费跟音讯寄存在哪个行列没有关系)。

tags选填,类似于 Gmail 为每封邮件设置的标签,方便服务器过滤运用。现在只支 持每个音讯设置一个 tag,所以也能够类比为 Notify 的 MessageType 概念。

keys选填,代表这条音讯的事务关键词,服务器会依据 keys 创立哈希索引,设置后, 能够在 Console 体系依据 Topic、Keys 来查询音讯,因为是哈希索引,请尽或许 确保 key 仅有,例如订单号,产品 Id 等。

3>rocketmq的负载均衡战略规定:Consumer数量应该小于等于Queue数量,假如Consumer超越Queue数量,那么剩余的Consumer 将不能消费音讯。这一点和kafka是共同的,rocketmq会尽或许地为每一个Consumer分配相同数量的行列,分摊负载。

activemq:支撑负载均衡。能够依据zookeeper完成负载均衡。

七、集群办法

Kafka:天然的‘Leader-Slave’无状况集群,每台服务器既是Master也是Slave。

分区领袖均匀地散布在不同的kafka服务器上,分区副本也均匀地散布在不同的kafka服务器上,所以每一台kafka服务器既含有分区领袖,一起又含有分区副本,每一台kafka服务器是某一台kafka服务器的Slave,一起也是某一台kafka服务器的leader。

kafka的集群依赖于zookeeper,zookeeper支撑热扩展,一切的broker、顾客、分区都能够动态参加移除,而无需封闭服务,与不依托zookeeper集群的mq比较,这是最大的优势。

rabbitmq:支撑简略集群,'仿制'办法,对高档集群办法支撑欠好。

rabbitmq的每一个节点,不管是单一节点体系或许是集群中的一部分,要么是内存节点,要么是磁盘节点,集群中至少要有一个是磁盘节点。

在rabbitmq集群中创立行列,集群只会在单个节点创立行列进程和完好的行列信息(元数据、状况、内容),而不是在一切节点上创立。

引进镜像行列,能够避免单点故障,确保服务的可用性,可是需求人为地为某些重要的行列装备镜像。

zeromq:去中心化,不支撑集群。

rocketmq:常用 多对'Master-Slave' 办法,开源版别需手动切换Slave变成Master

Name Server是一个简直无状况节点,可集群布置,节点之间无任何信息同步。

Broker布置相对杂乱,Broker分为Master与Slave,一个Master能够对应多个Slave,可是一个Slave只能对应一个Master,Master与Slave的对应关系经过指定相同的BrokerName,不同的BrokerId来界说,BrokerId为0表示Master,非0表示Slave。Master也能够布置多个。每个Broker与Name Server集群中的一切节点树立长衔接,守时注册Topic信息到一切Name Server。

Producer与Name Server集群中的其间一个节点(随机选择)树立长衔接,守时从Name Server取Topic路由信息,并向供给Topic服务的Master树立长衔接,且守时向Master发送心跳。Producer彻底无状况,可集群布置。

Consumer与Name Server集群中的其间一个节点(随机选择)树立长衔接,守时从Name Server取Topic路由信息,并向供给Topic服务的Master、Slave树立长衔接,且守时向Master、Slave发送心跳。Consumer既能够从Master订阅音讯,也能够从Slave订阅音讯,订阅规则由Broker装备决议。

客户端先找到NameServer, 然后经过NameServer再找到 Broker。

一个topic有多个行列,这些行列会均匀地散布在不同的broker服务器上。rocketmq行列的概念和kafka的分区概念是根本共同的,kafka同一个topic的分区尽或许地散布在不同的broker上,分区副本也会散布在不同的broker上。

rocketmq集群的slave会从master拉取数据备份,master散布在不同的broker上。

activemq:支撑简略集群办法,比方'主-备',对高档集群办法支撑欠好。

八、办理界面

Kafka:一般 rabbitmq:好 zeromq:无 rocketmq:无 activemq:一般

九、可用性

Kafka:十分高(散布式) rabbitmq:高(主从) zeromq:高。rocketmq:十分高(散布式) activemq:高(主从)

十、音讯重复

Kafka:支撑at least once、at most once

rabbitmq:支撑at least once、at most once

zeromq:只要重传机制,可是没有耐久化,音讯丢了重传也没有用。既不是at least once、也不是at most once、更不是exactly only once

rocketmq:支撑at least once

activemq:支撑at least once

十一、吞吐量TPS

Kafka:极大 Kafka按批次发送音讯和消费音讯。发送端将多个小音讯合并,批量发向Broker,消费端每次取出一个批次的音讯批量处理。rabbitmq:比较大 zeromq:极大 rocketmq:大 rocketMQ接纳端能够批量消费音讯,能够装备每次消费的音讯数,可是发送端不是批量发送。activemq:比较大

十二、订阅办法和音讯分发

Kafka:依据topic以及依照topic进行正则匹配的发布订阅办法。

【发送】

发送端由topic和key来决议音讯发往哪个分区,假如key为null,那么会运用轮询算法将音讯均衡地发送到同一个topic的不同分区中。假如key不为null,那么会依据key的hashcode取模计算出要发往的分区。

【接纳】

1>consumer向群组协调器broker发送心跳来维持他们和群组的从属关系以及他们对分区的一切权关系,一切权关系一旦被分配就不会改变除非产生再均衡(比方有一个consumer参加或许脱离consumer group),consumer只会从对应的分区读取音讯。

2>kafka约束consumer个数要少于分区个数,每个音讯只会被同一个 Consumer Group的一个consumer消费(非播送)。

3>kafka的 Consumer Group订阅同一个topic,会尽或许地使得每一个consumer分配到相同数量的分区,不同 Consumer Group订阅同一个主题相互独立,同一个音讯会被不同的 Consumer Group处理。

rabbitmq:供给了4种:direct, topic ,Headers和fanout。

【发送】

先要声明一个行列,这个行列会被创立或许现已被创立,行列是根本存储单元。

由exchange和key决议音讯存储在哪个行列。

direct>发送到和bindingKey彻底匹配的行列。

topic>路由key是含有"."的字符串,会发送到含有“*”、“#”进行含糊匹配的bingKey对应的行列。

fanout>与key无关,会发送到一切和exchange绑定的行列

headers>与key无关,音讯内容的headers特点(一个键值对)和绑定键值对彻底匹配时,会发送到此行列。此办法功能低一般不必

【接纳】

rabbitmq的行列是根本存储单元,不再被分区或许分片,关于咱们现已创立了的行列,消费端要指定从哪一个行列接纳音讯。

当rabbitmq行列具有多个顾客的时分,行列收到的音讯将以轮询的分发办法发送给顾客。每条音讯只会发送给订阅列表里的一个顾客,不会重复。

这种办法十分合适扩展,并且是专门为并发程序设计的。

假如某些顾客的使命比较深重,那么能够设置basicQos约束信道上顾客能坚持的最大未承认音讯的数量,在到达上限时,rabbitmq不再向这个顾客发送任何音讯。

zeromq:点对点(p2p)

rocketmq:依据topic/messageTag以及依照音讯类型、特点进行正则匹配的发布订阅办法

【发送】

发送音讯经过轮询行列的办法发送,每个行列接纳均匀的音讯量。发送音讯指定topic、tags、keys,无法指定投递到哪个行列(没有意义,集群消费和播送消费跟音讯寄存在哪个行列没有关系)。

tags选填,类似于 Gmail 为每封邮件设置的标签,方便服务器过滤运用。现在只支 持每个音讯设置一个 tag,所以也能够类比为 Notify 的 MessageType 概念。

keys选填,代表这条音讯的事务关键词,服务器会依据 keys 创立哈希索引,设置后, 能够在 Console 体系依据 Topic、Keys 来查询音讯,因为是哈希索引,请尽或许 确保 key 仅有,例如订单号,产品 Id 等。

【接纳】

1>播送消费。一条音讯被多个Consumer消费,即便Consumer属于同一个ConsumerGroup,音讯也会被ConsumerGroup中的每个Consumer都消费一次。

2>集群消费。一个 Consumer Group中的Consumer实例均匀分摊消费音讯。例如某个Topic有 9 条音讯,其间一个Consumer Group有3个实例,那么每个实例只消费其间的 3 条音讯。即每一个行列都把音讯轮番分发给每个consumer。

activemq:点对点(p2p)、播送(发布-订阅)

点对点办法,每个音讯只要1个顾客;

发布/订阅办法,每个音讯能够有多个顾客。

【发送】

点对点办法:先要指定一个行列,这个行列会被创立或许现已被创立。

发布/订阅办法:先要指定一个topic,这个topic会被创立或许现已被创立。

【接纳】

点对点办法:关于现已创立了的行列,消费端要指定从哪一个行列接纳音讯。

发布/订阅办法:关于现已创立了的topic,消费端要指定订阅哪一个topic的音讯。

十三、次序音讯

Kafka:支撑。

设置出产者的max.in.flight.requests.per.connection为1,能够确保音讯是依照发送次序写入服务器的,即便产生了重试。

kafka确保同一个分区里的音讯是有序的,可是这种有序分两种状况

1>key为null,音讯逐一被写入不同主机的分区中,可是关于每个分区依然是有序的

2>key不为null , 音讯被写入到同一个分区,这个分区的音讯都是有序。

rabbitmq:不支撑

zeromq:不支撑

rocketmq:支撑

activemq:不支撑

十四、音讯承认

Kafka:支撑。

1>发送方承认机制

ack=0,不管音讯是否成功写入分区

ack=1,音讯成功写入领袖分区后,回来成功

ack=all,音讯成功写入一切分区后,回来成功。

2>接纳方承认机制

主动或许手动提交分区偏移量,早期版别的kafka偏移量是提交给Zookeeper的,这样使得zookeeper的压力比较大,更新版别的kafka的偏移量是提交给kafka服务器的,不再依赖于zookeeper群组,集群的功能愈加稳定。

rabbitmq:支撑。

1>发送方承认机制,音讯被投递到一切匹配的行列后,回来成功。假如音讯和行列是可耐久化的,那么在写入磁盘后,回来成功。支撑批量承认和异步承认。

2>接纳方承认机制,设置autoAck为false,需求显式承认,设置autoAck为true,主动承认。

当autoAck为false的时分,rabbitmq行列会分成两部分,一部分是等候投递给consumer的音讯,一部分是现已投递可是没收到承认的音讯。假如一向没有收到承认信号,并且consumer现已断开衔接,rabbitmq会安排这个音讯重新进入行列,投递给原来的顾客或许下一个顾客。

未承认的音讯不会有过期时刻,假如一向没有承认,并且没有断开衔接,rabbitmq会一向等候,rabbitmq允许一条音讯处理的时刻能够很久很久。

zeromq:支撑。

rocketmq:支撑。

activemq:支撑。

十五、音讯回溯

Kafka:支撑指定分区offset方位的回溯。rabbitmq:不支撑 zeromq:不支撑 rocketmq:支撑指守时刻点的回溯。activemq:不支撑

十六、音讯重试

Kafka:不支撑,可是能够完成。

kafka支撑指定分区offset方位的回溯,能够完成音讯重试。

rabbitmq:不支撑,可是能够利用音讯承认机制完成。

rabbitmq接纳方承认机制,设置autoAck为false。

当autoAck为false的时分,rabbitmq行列会分成两部分,一部分是等候投递给consumer的音讯,一部分是现已投递可是没收到承认的音讯。假如一向没有收到承认信号,并且consumer现已断开衔接,rabbitmq会安排这个音讯重新进入行列,投递给原来的顾客或许下一个顾客。

zeromq:不支撑,

rocketmq:支撑。

音讯消费失利的大部分场景下,立即重试99%都会失利,所以rocketmq的战略是在消费失利时守时重试,每次时刻距离相同。

1>发送端的 send 办法自身支撑内部重试,重试逻辑如下:

a)至多重试3次;

b)假如发送失利,则轮转到下一个broker;

c)这个办法的总耗时不超越sendMsgTimeout 设置的值,默认 10s,超越时刻不在重试。

2>接纳端。

Consumer 消费音讯失利后,要供给一种重试机制,令音讯再消费一次。Consumer 消费音讯失利一般能够分为以下两种状况:

  1. 因为音讯自身的原因,例如反序列化失利,音讯数据自身无法处理(例如话费充值,当时音讯的手机号被

注销,无法充值)等。守时重试机制,比方过 10s 秒后再重试。

  1. 因为依赖的下游应用服务不可用,例如 db 衔接不可用,外体系网络不可达等。

即便越过当时失利的音讯,消费其他音讯相同也会报错。这种状况能够 sleep 30s,再消费下一条音讯,减轻 Broker 重试音讯的压力。

activemq:不支撑

十七、并发度

Kafka:高

一个线程一个顾客,kafka约束顾客的个数要小于等于分区数,假如要进步并行度,能够在顾客中再敞开多线程,或许添加consumer实例数量。

rabbitmq:极高

自身是用Erlang言语写的,并发功能高。

可在顾客中敞开多线程,最常用的做法是一个channel对应一个顾客,每一个线程操纵一个channel,多个线程复用connection的tcp衔接,削减功能开销。

当rabbitmq行列具有多个顾客的时分,行列收到的音讯将以轮询的分发办法发送给顾客。每条音讯只会发送给订阅列表里的一个顾客,不会重复。

这种办法十分合适扩展,并且是专门为并发程序设计的。

假如某些顾客的使命比较深重,那么能够设置basicQos约束信道上顾客能坚持的最大未承认音讯的数量,在到达上限时,rabbitmq不再向这个顾客发送任何音讯。

zeromq:高

rocketmq:高

1>rocketmq约束顾客的个数少于等于行列数,可是能够在顾客中再敞开多线程,这一点和kafka是共同的,进步并行度的办法相同。

修正消费并行度办法

a) 同一个 ConsumerGroup 下,经过添加 Consumer 实例数量来进步并行度,超越订阅行列数的 Consumer实例无效。

b) 进步单个 Consumer 的消费并行线程,经过修正参数consumeThreadMin、consumeThreadMax

2>同一个网络衔接connection,客户端多个线程能够一起发送恳求,衔接会被复用,削减功能开销。

activemq:高

单个ActiveMQ的接纳和消费音讯的速度在1万笔/秒(耐久化 一般为1-2万, 非耐久化 2 万以上),在出产环境中布置10个Activemq就能到达10万笔/秒以上的功能,布置越多的activemq broker 在MQ上latency也就越低,体系吞吐量也就越高。