分享5款主流分布式MQ消息队列对比

Posted wecloud1314

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分享5款主流分布式MQ消息队列对比相关的知识,希望对你有一定的参考价值。

对于即时通讯网来说,所有的技术文章和资料都在围绕即时通讯这个技术方向进行整理和分享,这一次也不例外。对于即时通讯系统(包括IM、消息推送系统等)来说,MQ消息中件间是非常常见的基础软件,但市面上种类众多、各有所长的MQ消息中件间产品,该怎么去选择?这是个问题!

 

对于很多经验不足的开发者来说,一个公司内部用的IM聊天系统,总用户量也不过百十来人,动辄就是Kafka、MongoDB,美其名曰为了高性能和可扩展性,真是大炮打蚊子。而对于中大型的即时通讯场景来说,有的开发者确为了贪图使用简单、资料全面,反而使用臃肿不堪的ActiveMQ,这就有点失去章法了。

维度1:资料文档

    1)Kafka:资料数量中等。有Kafka作者自己写的书,网上资料也有一些。
    2)RabbitMQ:资料数量多。有一些不错的书,网上资料多。
    3)ZeroMQ:资料数量少。专门写ZeroMQ的书较少,网上的资料多是一些代码的实现和简单介绍。
    4)RocketMQ:资料数量少。专门写RocketMQ的书目前有了两本;网上的资料良莠不齐,官方文档很简洁,但是对技术细节没有过多的描述。
    5)ActiveMQ:资料数量多。没有专门写ActiveMQ的书,网上资料多。

维度2:开发语言

    1)Kafka:Scala
    2)RabbitMQ:Erlang
    3)ZeroMQ:C语言
    4)RocketMQ:Java
    5)ActiveMQ:Java

维度3:支持的协议

    1)Kafka:自己定义的一套…(基于TCP)
    2)RabbitMQ:AMQP
    3)ZeroMQ:TCP、UDP
    4)RocketMQ:自己定义的一套…
    5)ActiveMQ:OpenWire、STOMP、REST、XMPP、AMQP

维度4:消息存储

1)Kafka:

内存、磁盘、数据库。支持大量堆积。

Kafka的最小存储单元是分区,一个topic包含多个分区,Kafka创建主题时,这些分区会被分配在多个服务器上,通常一个broker一台服务器。即时通讯聊天软件app开发可以加蔚可云的v:weikeyun24咨询

 

分区首领会均匀地分布在不同的服务器上,分区副本也会均匀的分布在不同的服务器上,确保负载均衡和高可用性,当新的broker加入集群的时候,部分副本会被移动到新的broker上。

根据配置文件中的目录清单,Kafka会把新的分区分配给目录清单里分区数最少的目录。

默认情况下,分区器使用轮询算法把消息均衡地分布在同一个主题的不同分区中,对于发送时指定了key的情况,会根据key的hashcode取模后的值存到对应的分区中。

2)RabbitMQ:

内存、磁盘。支持少量堆积。

RabbitMQ的消息分为持久化的消息和非持久化消息,不管是持久化的消息还是非持久化的消息都可以写入到磁盘。

持久化的消息在到达队列时就写入到磁盘,并且如果可以,持久化的消息也会在内存中保存一份备份,这样可以提高一定的性能,当内存吃紧的时候会从内存中清除。

非持久化的消息一般只存在于内存中,在内存吃紧的时候会被换入到磁盘中,以节省内存。

引入镜像队列机制,可将重要队列“复制”到集群中的其他broker上,保证这些队列的消息不会丢失。

配置镜像的队列,都包含一个主节点master和多个从节点slave,如果master失效,加入时间最长的slave会被提升为新的master,除发送消息外的所有动作都向master发送,然后由master将命令执行结果广播给各个slave,RabbitMQ会让master均匀地分布在不同的服务器上,而同一个队列的slave也会均匀地分布在不同的服务器上,保证负载均衡和高可用性。

3)ZeroMQ:

消息发送端的内存或者磁盘中。不支持持久化。

4)RocketMQ:

磁盘。支持大量堆积。

commitLog文件存放实际的消息数据,每个commitLog上限是1G,满了之后会自动新建一个commitLog文件保存数据。

ConsumeQueue队列只存放offset、size、tagcode,非常小,分布在多个broker上。

ConsumeQueue相当于CommitLog的索引文件,消费者消费时会从consumeQueue中查找消息在commitLog中的offset,再去commitLog中查找元数据。

ConsumeQueue存储格式的特性,保证了写过程的顺序写盘(写CommitLog文件),大量数据IO都在顺序写同一个commitLog,满1G了再写新的。

加上RocketMQ是累计4K才强制从PageCache中刷到磁盘(缓存),所以高并发写性能突出。

5)ActiveMQ:

内存、磁盘、数据库。支持少量堆积。

维度5:消息事务

    1)Kafka:支持
    2)RabbitMQ:支持。客户端将信道设置为事务模式,只有当消息被RabbitMQ接收,事务才能提交成功,否则在捕获异常后进行回滚。使用事务会使得性能有所下降
    3)ZeroMQ:不支持
    4)RocketMQ:支持
    5)ActiveMQ:支持

维度6:负载均衡

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技术,或者在客户端使用算法实现负载均衡,引入负载均衡之后,各个客户端的连接可以分摊到集群的各个节点之中。

客户端均衡算法:

    a. 轮询法:按顺序返回下一个服务器的连接地址。
    b. 加权轮询法:给配置高、负载低的机器配置更高的权重,让其处理更多的请求;而配置低、负载高的机器,给其分配较低的权重,降低其系统负载。
    c. 随机法:随机选取一个服务器的连接地址。
    d. 加权随机法:按照概率随机选取连接地址。
    e. 源地址哈希法:通过哈希函数计算得到的一个数值,用该数值对服务器列表的大小进行取模运算。
    f. 最小连接数法:动态选择当前连接数最少的一台服务器的连接地址。

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实现负载均衡。

以上是关于分享5款主流分布式MQ消息队列对比的主要内容,如果未能解决你的问题,请参考以下文章

多维度对比主流分布式MQ消息队列,妈妈再也不担心我的技术选型了

MQ之主流MQ:kafaka+RocketMQ+RabbitMQ对比

分布式消息队列(上):主流MQ的二三事

分布式消息队列--RabbitMQ

消息队列篇—常用消息队列MQ产品介绍及对比

深入消息队列MQ,看这篇就够了!