kafkarabbitmq优劣对⽐_17个⽅⾯,综合对⽐主流消息队列⼀、资料⽂档
⼆、开发语⾔
三、⽀持的协议
四、消息存储
五、消息事务
六、负载均衡
七、集⽅式
⼋、管理界⾯
九、可⽤性
⼗、消息重复
⼗⼀、吞吐量TPS
⼗⼆、订阅形式和消息分发
⼗三、顺序消息
⼗四、消息确认
⼗五、消息回溯
⼗六、消息重试
⼗七、并发度
本⽂将从,Kafka、RabbitMQ、ZeroMQ、RocketMQ、ActiveMQ 17 个⽅⾯综合对⽐作为消息队列使⽤时的差异。
⼀、资料⽂档
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队列拥有多个消费者的时候,队列收到的消息将以轮询的分发⽅式发送给消费者。每条消息只会发送给订阅列表⾥的⼀个消费者,不会重复。activemq和rocketmq的区别
这种⽅式⾮常适合扩展,⽽且是专门为并发程序设计的。
如果某些消费者的任务⽐较繁重,那么可以设置basicQos限制信道上消费者能保持的最⼤未确认消息的数量,在达到上限时,rabbitmq不再向这个消费者发送任何消息。
zeromq:点对点(p2p)
rocketmq:基于topic/messageTag以及按照消息类型、属性进⾏正则匹配的发布订阅模式
【发送】
发送消息通过轮询队列的⽅式发送,每个队列接收平均的消息量。发送消息指定topic、tags、keys,⽆法指定投递到哪个队列(没有意义,集消费和⼴播消费跟消息存放在哪个队列没有关系)。
tags选填,类似于 Gmail 为每封邮件设置的标签,⽅便服务器过滤使⽤。⽬前只⽀ 持每个消息设置⼀个 tag,所以也可以类⽐为 Notify
的 MessageType 概念。
keys选填,代表这条消息的业务关键词,服务器会根据 keys 创建哈希索引,设置后, 可以在 Console 系统根据 Topic、Keys 来查询消息,由于是哈希索引,请尽可能 保证 key 唯⼀,例如订单号,商品 Id 等。
【接收】
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论