【ActiveMQ、RabbitMQ、RocketMQ、Kafka、ZeroMQ】
典型应用场景有如下几个:
1)异步通信
注册时的短信、邮件通知,减少响应时间;
2)应用解耦
信息发送者和消息接受者无需耦合,比如调用第三方;
3)流量削峰
例如秒杀系统;
ActiveMQ特点
Apache ActiveMQ是Apache软件基金会所研发的开放源代码消息中间件;
由于ActiveMQ是一个纯Java程序,因此只需要操作系统支持Java虚拟机,ActiveMQ便可执行。
1)有点对点(p2p)、广播(基于topic的发布-订阅)两种消费方式。
2)支持来自Java,C,C ++,C#,Ruby,Perl,Python,PHP的各种跨语言客户端和协议
3)完全支持JMS客户端和Message Broker中的企业集成模式
4)支持许多高级功能,如消息组,虚拟目标,通配符和复合目标
5)完全支持JMS 1.1和J2EE 1.4,支持瞬态,持久,事务和XA消息
6)Spring支持,以便ActiveMQ可以轻松嵌入到Spring应用程序中,并使用Spring的XML配置机制进行配置
7)专为高性能集群,客户端 - 服务器,基于对等的通信而设计
8)CXF和Axis支持,以便ActiveMQ可以轻松地放入这些Web服务堆栈中以提供可靠的消息传递
9)可以用作内存JMS提供程序,非常适合单元测试JMS
10)支持可插拔传输协议,例如in-VM,TCP,SSL,NIO,UDP,多播,JGroups和JXTA传输
11)使用JDBC和高性能日志支持非常快速的持久性
ActiveMQ优势
1)产品成熟,在中等小型规模的场景有很多应用
2)Activemq高版本负载均衡做得比较好,高可用,支持动态扩展。使用zookeeper管理集群成员,master-slave架构,当master服务器出现故障,slave会顶替成为新的master。
3)功能齐全,支持多种恢复机制,支持事务,支持多种协议。
4)AcitiveMQ很容易嵌入到spring的项目中。
ActiveMQ劣势
1)存储方式只能支持少量堆积。
ActiveMQ有四种存储器
a) KahaDB message store:是ActiveMQ的默认以及推荐的存储器,特点是基于文件、支持事务日志、可靠、可扩展、速度快等。可扩展体现在KahaDB支持其他三种存储器的外接扩展,也就是说可以同时用多种,这样可以取长补短,适合更广的应用场景,达到性能最佳。
b) AMQ message store:在基于文件、支持事务方面和KahaDB类似。
c) JDBC message store:默认的JDBC驱动是ApacheDerby,同时支持MySQL、PostgreSQL、Oracle、SQLServer、Sybase、Informix、MaxDB等主流的关系数据库。用三张表结构来存储消息,分别是ACTIVEMQ_MSGS、ACTIVEMQ_ACKS、ACTIVEMQ_LOCK。
d) Memory message store:用于实时消息的缓存。
Activemq的存储方式对于hadoop、hdfs、hbase这类分布式系统没有支持。
能够支撑的队列数与消息保存机制有关,Activemq的存储方式决定了他不适合大量队列的场合,也决定了他只能支持少量堆积。
2)ActiveMQ默认的配置性能偏低,需要优化配置,但是配置文件复杂,ActiveMQ本身不提供管理工具,示例代码少。ActiveMQ适合一般的事务性业务场合,不适合大数据应用的场合。
3)只适合简单集群。
RabbitMQ特点
RabbitMQ是Rabbit科技有限公司用Erlang语言编写的,2010年4月被VMware旗下的SpringSource收购。
1)异步消息传递:支持多种消息协议,消息队列,传送确认,灵活的路由到队列,多种交换类型;
2)支持几乎所有最受欢迎的编程语言:Java,C,C ++,C#,Ruby,Perl,Python,PHP等等;
3)可以部署为高可用性和吞吐量的集群; 跨多个可用区域和区域进行联合;
4)可插入的身份验证,授权,支持TLS和LDAP;
5)提供了一个易用的用户界面,使得用户可以监控和管理消息 Broker 的许多方面;
6)提供了许多插件,来从多方面进行扩展,也可以编写自己的插件。
RabbitMQ优势
1)并发性能极好。
a) 本身是用Erlang语言写的,并发性能高。
b) 通常消费者中开启多线程,一个channel对应一个消费者,每一个线程把持一个channel,多个线程复用connection的tcp连接,减少性能开销。
c) 当rabbitmq队列拥有多个消费者的时候,队列收到的消息将以轮询的分发方式发送给消费者。每条消息只会发送给订阅列表里的一个消费者,不会重复。
这种方式非常适合扩展,而且是专门为并发程序设计的。
2)支持批量确认和异步确认。
RabbitMQ的comfirm机制支持批量确认,每发送一批消息后,调用channer.waitForConfirms方法,等待服务器的确认返回。
RabbitMQ的comfirm机制支持异步取确认,服务器确认了一条或者多条消息后客户端会调这个方法进行处理。
在要求消息发送不丢失的应用场景,设置批量确认和异步确认可以提高吞吐量。
3)支持长时间消费和消息事务。如果消费者没有断开连接,并且没有确认消费,那么rabbitmq会一直等待消费者消费完成。
4)权限控制比较完善。
5)有强大的WEB管理页面。
6)高效持久化。
RabbitMQ劣势
1)只支持简单集群,对高级集群模式支持不好。
在rabbitmq集群中创建队列,集群只会在单个节点创建队列进程和完整的队列信息(元数据、状态、内容),而不是在所有节点上创建。
这样只有队列的宿主节点,即所有者节点知道队列的所有信息,其他所有者节点只知道队列的元数据和指向该队列的那个节点的指针。
当集群节点崩溃时,该节点的队列进程和关联的绑定都会消失。附加在那些队列上的消费者也会丢失所订阅的信息,任何匹配该队列绑定信息的新消息也都会消失。
rabbitmq分为内存节点和磁盘节点,至少有一个磁盘节点,磁盘节点崩溃了可以发送消息,消费消息,但是无法创建队列、交换器、绑定关系、用户。
引入镜像队列,可以避免单点故障,确保服务的可用性,但是需要人为地为某些重要的队列配置镜像。
新节点加入镜像队列时候,镜像队列的消息不会主动同步到新的slave中,除非调用同步命令,调用同步命令会使得队列阻塞,不能在生产环境中操作。
2)不支持负载均衡,要借助LVS或者HAPROXY等技术实现。
rabbitmq的队列是预先创建在各个节点的,每个队列在节点的分布都是人为控制的,发送消息之前要和其中一台服务器建立连接,所以就会出现不均衡的情况。
要实现负载均衡,三种方式:
a) 引入镜像队列。
b) 借助LVS或者HAPROXY技术。
c) 客户端算法实现。
rabbitmq的负载均衡都是需要我们去做的,工作量不小。
3)只能支持少量堆积,各种队列和元数据的存储需要大量的磁盘空间。
4)Erlang语言开发,研究源码有一定难度。
rabbitmq的特性适合长时间消费的应用场景,比如邮箱通知系统,短信通知系统,不适合大数据的应用场合。
RocketMQ特点
RocketMQ是阿里开源的消息中间件,目前在Apache孵化,使用纯Java开发,思路起源于Kafka。
1)支持发布/订阅(Pub/Sub)和点对点(P2P)消息模型
2)在一个队列中可靠的先进先出(FIFO)和严格的顺序传递
3)支持拉(pull)和推(push)两种消息模式
4)单一队列百万消息的堆积能力
5)支持多种消息协议,如 JMS、MQTT 等
6)分布式高可用的部署架构,满足至少一次消息传递语义
7)提供 docker 镜像用于隔离测试和云集群部署
8)提供配置、指标和监控等功能丰富的 Dashboard
RocketMQ优势
1)支持消息失败重试、消息事务、消息回溯,高可靠的持久化策略,消息几乎不会丢失。
a) 消息重试:
大部分消息消费失败场景,立即重试99%都会失败,所以rocketmq的重试策略是定时重试,每次时间间隔相同。
发送端的 send 方法本身支持内部重试,接收端的Consumer 消费消息失败后,提供一种重试机制,令消息再消费一次。
b) 消息事务:事务成功提交,则消息一定被broker接收。
c) 消息回溯:消息写到磁盘,可以基于时间回溯。
2)实时性好。RocketMQ使用长轮询,同Push方式实时性一致,消息的投递延时通常在几个毫秒。
3)支持大量堆积,持久化效率高,批量刷盘。
commitLog文件存放实际的消息数据,每个commitLog上限是1G,满了之后会自动新建一个commitLog文件保存数据。ConsumeQueue队列只存放offset、size、tagcode,非常小,分布在多个broker上,磁盘空间的利用率比较高。
commitLog存放所有实际数据,顺序写消息的效率较高。
RocketMQ累计4K才强制从PageCache中刷到磁盘。
4)对分布式支持很好,使用nameserver管理集群成员,支持动态扩展。
RocketMQ劣势
1)存储方式只支持写到磁盘。
a) 无法充分利用内存来提高写入读取速度。
b) 虽然是顺序写,但是随机读,随机读比较慢。
2)使用消息事务,确保了消息的可靠投递,但是必然会导致并发性能下降,这个把双刃剑。
Kafka特点
Kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写。主要用于处理活跃的流式数据,因此Kafaka在大数据系统中使用较多,比如日志数据。
1)同时为发布和订阅提供高吞吐量。据了解,Kafka每秒可以生产约25万消息(50 MB),每秒处理55万消息(110 MB)。
2)可进行持久化操作。将消息持久化到磁盘,因此可用于批量消费,例如ETL,以及实时应用程序。通过将数据持久化到硬盘以及replication防止数据丢失。
3)分布式系统,易于向外扩展。所有的producer、broker和consumer都会有多个,均为分布式的。无需停机即可扩展机器。
4)消息被处理的状态是在consumer端维护,而不是由server端维护。当失败时能自动平衡。
5)支持online和offline的场景。
Kafka优势
1)吞吐量极大。
a) 充分利用缓冲区,发送端按批次批量发送消息,消费端按批次批量处理消息。
b) 高效持久化。
c) 批量刷盘。从页面缓存批量刷到磁盘。
2)扩展性:支持热扩展,添加consumer、broker、producer无需关闭服务。
3)高可用、容错性、伸缩性。
4)支持同步到数据库,能与hadoop、hbase等建立数据管道。
基于磁盘的数据存储,通过建立数据管道,可以把磁盘的数据同步到mysql或者hbase等数据库。
消费者可以在进行应用程序维护时离线一段时间,无需担心消息丢失或者堵塞在生产者端。
5)完全的分布式系统,Broker、Producer、Consumer都原生自动支持分布式,自动支持负载均衡,zookeeper负责管理集群成员,搭建、部署、维护分布式集群更加简单。
每一个topic有多个分区,每一个分区有多个副本,当分区首领所在的主机发生问题的时候,Kafka会自动从分区副本中选举下一个分区首领,让该分区首领的主机提供服务,分区副本的个数只需要简单配置即可,分区副本的创建和分配,不用我们去操心,负责选举的主机也是Kafka选举出来的,选举哪一台主机作为控制器的过程也不用我们操心。
6)流式处理能力。
流数据是数量无限的,连续的,时序性的数据,比如游戏里物体的移动、股票交易、制造商传感器发出的事件、用户行为事件、流经交换机的网络事件等等,公司里的系统一般都包含了大量有价值的数据流。
流式处理不要求实时性达到亚毫秒级的响应,也接受不了要等到第二天才知道结果,基于批处理和实时处理之间。
Kafka很多基于Kafka构建的流式处理系统都将Kafka作为唯一可靠的数据来源。
a) Kafka支持两个基于流的API,一个是底层的Processor API,一个是高级的Stream DSL。
b) Kafka0.10.0和更高的版本可以记录时序信息。
Kafka的生产者会自动在记录中添加记录的创建时间。
Kafka会记录日志追加时间,日志追加时间是指事件保存到broker的时间,如果启用了自动添加时间戳的功能,那么broker会在接收这些记录的时候自动添加时间戳。
Kafka劣势
1)虽然Kafka对分布式的支持极好,但是不支持消息事务。
消息事务和消息确认都是为了确保producer发送的消息能够被broker接收。
消息确认会等待确认信号,如果在规定时间内没有得到确认,就会尝试重新发送消息,重试次数是有限的。
消息事务的消息在成功提交之后,消息一定被broker接收,如果发生回滚,就会尝试重新提交。
这两种方式的区别在于消息事务提供更加可靠的保证,但是更加消耗性能。
2)不支持消息重试,消息消费失败后,把错误记录下来?把消息保存到磁盘上?回调另一个程序?具体哪一种逻辑是由我们决定的,消息可能丢失(消息来不及处理就宕机了,或者代码逻辑的疏忽)。
3)长时间的消费。 Kafka只支持pull模式订阅消费,消费者是通过轮询读取消息的,也是通过这个轮询去保持心跳,暂停轮询的时间不能超过几秒,否则会认为consumer退出了consumer group。可以把数据移交给线程池处理,但是最好还是不要长时间消费。
4)重复消息。 Kafka消费消息是按批次批量消费的,而确认消费成功是通过提交offset来完成的,提交的offset比已经处理的偏移量小,那么提交的offset和已经被处理的offset之间的消息都会被重复消费。
其实重复消息几乎是所有mq都会遇到的问题,Kafka避免重复消息可以通过提高offset的提交频度来实现,但是这样就要降低Kafka的批量处理性能。(按批次批量处理是Kafka高效的主要原因之一,充分利用内存来提高吞吐量)
长时间消费更加容易失败,这种消息的重复消费或者丢失了再消费,会消耗更多时间,Kafka不适合长时间消费的场景。
Kafka非常适合流式处理、大数据、单次消费时间较短的场合。不支持消息事务,对于交易系统、订单系统不太适合。
ZeroMQ特点
ZeroMQ号称是“史上最快的消息队列”,是Pieter Hintjens基于c语言开发的。
1)嵌入式消息组件
ZeroMQ就像是一个嵌入在操作系统内的一个组件,说白了ZeroMQ就是一组jar包,直接嵌入到项目中就可以运行,它不需要一台独立的服务器来承载整个消息系统。
ZeroMQ关注的不是消息的可靠送达,而是着眼于端到端的发送,接收…它希望的是尽快完成任务,而不介意部分消息的丢失。
但这也并不是说他完全没有持久化的功能,ZeroMQ是具有一定的本地持久化的功能的,但是能保存的数据量比较有限,而且是暂存于内存中的。
2)高的离谱的吞吐量
ZeroMQ对于消息的处理可以说除却请求-应答模式之外,基本就是不关注消息是否丢失,它只管发送。
3)多核下的线程绑定
传统的多线程并发模式一般会采用锁,临界区,信号量等技术来控制,而ZeroMQ给出的建议是:在创建IO时不要超出CPU核数。
ZeroMQ优势
1)性能极好,吞吐量极大,并发性能极好,实时性极好。
a) 无锁的队列模型
对于跨线程间的交互(用户端和session)之间的数据交换通道pipe,采用无锁的队列算法CAS;在pipe的两端注册有异步事件,在读或者写消息到pipe的时,会自动触发读写事件。
b) 批量处理的算法
对于传统的消息处理,每个消息在发送和接收的时候,都需要系统的调用,这样对于大量的消息,系统的开销比较大,zeroMQ对于批量的消息,进行了适应性的优化,可以批量的接收和发送消息。
c) 多核下的线程绑定,无须CPU切换
区别于传统的多线程并发模式,信号量或者临界区, zeroMQ充分利用多核的优势,每个核绑定运行一个工作者线程,避免多线程之间的CPU切换开销。
2)引用ZeroMQ程序库即可在应用之间发送消息,拿来即用,产品能够快速迭代迅速成型。
ZeroMQ的消息队列对于开发者来说是透明的,开发者只需要发送消息并消费消息,不需要指定某一个队列,甚至感觉不到消息队列的存在,开发过程像socket编程。
ZeroMQ支持三种发送接收方式:点对点模式、发布订阅模式、推拉模式。
点对点模式,绑定地址和建立两端连接即可通信。
发布订阅模式,发布端绑定地址,订阅端与发布端建立连接,即可通信。
推拉模式,推端绑定地址,拉端与推端建立连接。推拉模式与发布订阅模式相比,推拉模型在没有消费者的情况下,发布的消息不会被消耗掉;在消费者能力不够的情况下,能够提供多消费者并行消费解决方案,用于多任务并行处理。
3)可以构建复杂的队列,处理逻辑可以定制。
4)非持久化消息,对系统的存储空间要求不大,但是可以处理成千上万的数据,服务器成本低。
ZeroMQ劣势
1)消息丢失。
只有消息重传机制,但是不支持消息重试、不支持消息回溯,不支持备份机制,不支持消息事务,不支持持久化,消息丢了就是丢了。
2)资料很少,可借鉴的经验不多,出现问题维护起来比较困难。
3)功能不够完备,很多功能需要我们去实现,不适合复杂的业务。
能满足基本的需求,但是对于其他特殊要求需要我们自己去实现,加大了后期的研发维护成本。
ZeroMQ适合大数据、实时处理、高频计算、定制性强的应用场合,比如股票市场统计。
由于对服务器的要求低,性能极其优越,有利于小型企业的快速应用、软件的快速迭代。
总结
1)性能和量要求小,用什么都没有关系,性质是一样的;如果消息性能要求高,用RocketMQ与Kafka可以更优,RocketMQ与Kafka 比较就看技术选型了,各有利弊,看业务需要。
2)ActiveMQ、RabbitMQq 与 Kafka、RocketMQ有很大的区别就是前2个只支持主从模式,后2个是分布式消息系统,支持分布式。
3)持久化消息比较: zeroMQ不支持, Kafka、RocketMQ 、ActiveMQ 和 RabbitMQq都支持。
持久化消息主要是指:MQ down或者MQ所在的服务器down了,消息不会丢失的机制。
4)其中包括持久化消息和瞬时消息的测试。注意这篇文章里面提到的MQ,都是采用默认配置的,并无调优。
ZeroMQ 最好,RabbitMQ 次之, ActiveMQ 最差。
5)可靠性、灵活的路由、集群、事务、高可用的队列、消息排序、问题追踪、可视化管理工具、插件系统、社区等方面比较:
RabbitMQ最好,ActiveMQ次之,ZeroMQ最差。当然ZeroMQ也可以做到,不过自己必须手动写代码实现,代码量不小。尤其是可靠性中的:持久性、投递确认、发布者证实和高可用性。
所以在可靠性和可用性上,RabbitMQ是首选,虽然ActiveMQ也具备,但是它性能不及RabbitMQ。
6)高并发
从实现语言来看,RabbitMQ最高,原因是它的实现语言是天生具备高并发高可用的erlang语言。
7)Kafka和RabbitMQ的比较
RabbitMQ 比 Kafka成熟,在可用性上,稳定性上,可靠性上,RabbitMQ 超过 Kafka
Kafka 设计的初衷就是处理日志的,可以看做是一个日志系统,针对性很强,所以它并没有具备一个成熟MQ应该具备的特性
Kafka 的性能(吞吐量、tps)比 RabbitMQ 要强。