基本对比信息
ActiveMQ | RabbitMQ | RocketMQ | Kafka | ZeroMQ | |
吞吐量 | 比RabbitMQ低 | 2.6w/s(消息做持久化) | 11.6w/s | 17.3w/s | 29w/s |
开发语言 | Java | Erlang | Java | Scala/Java | C |
主要维护者 | Apache | Mozilla/Spring | Alibaba | Apache | iMatix,创始人已去世 |
成熟度 | 成熟 | 成熟 | 开源版本不够成熟 | 比较成熟 | 只有C、PHP等版本成熟 |
文档和注释 | 多 | 多 | 很少 | 较少 | 很少 |
订阅形式 | 点对点(p2p)、广播(发布-订阅) | 提供了4种:direct, topic ,Headers和fanout。fanout就是广播模式 | 基于topic/messageTag以及按照消息类型、属性进行正则匹配的发布订阅模式 | 基于topic以及按照topic进行正则匹配的发布订阅模式 | 点对点(p2p) |
持久化 | 支持少量堆积 | 支持少量堆积 | 支持大量堆积 | 支持大量堆积 | 不支持 |
顺序消息 | 不支持 | 不支持 | 支持 | 支持 | 不支持 |
消息回溯 | 不支持 | 不支持 | 支持指定时间点的回溯 | 支持指定分区offset位置的回溯 | 不支持 |
性能稳定性 | 好 | 好 | 一般 | 较差 | 很好 |
负载均衡 | 可以支持 | 可以支持 | 支持较好 | 支持很好 | 不支持 |
集群方式 | 支持简单集群模式,比如'主-备',对高级集群模式支持不好。 | 支持简单集群,'复制'模式,对高级集群模式支持不好。 | 常用 多对'Master-Slave' 模式,开源版本需手动切换Slave变成Master | 天然的‘Leader-Slave’无状态集群,每台服务器既是Master也是Slave | 不支持 |
管理界面 | 一般 | 较好 | 一般 | 无 | 无 |
而谈到消息系统的设计,就回避不了两个问题:
1、消息的顺序问题
2、消息的重复问题
关于这两方面,RocketMQ的测试结果如下:
一、消息顺序读写
参考文章:http://www.jianshu.com/p/453c6e7ff81c
1、常规的理解是:在同一个队列(分区)的消息是按顺序排列的。但测试结果如下:
单服务器单个线程的Producer异步生产数据,生产的数据都用同一个字符串做hash,数据都分配在同一台机器的同一个队列。
单服务器单Consumer配置1个或者10个线程一起消费,每次最多抓取1条或者1014条数据,结果:同一个线程同一批次取回来的数据,顺序却不一致。
例如,取回来的数据预期顺序是:12、13、14、15、16……但结果却是:13、14、15、16、12……
同一批次测试,所有环境都一样,有一定几率(大概15%)会出现该情况。
原因:Producer异步生产数据会导致数据乱序。即使是单线程的Producer。
解决方案:为保证生产的消息顺序一致,Producer需采用同步发送数据,但是性能会大大下降(实测1851条/秒,同等情况下比kafka慢45%,不过一般情况下这性能也足够了)。
二、消息不丢失、不存在重复发送
根据阿里的测试结论,RocketMQ和Kafka在 消息不丢失 方面,做得差不多,服务器基本上不会丢失数据。结论如下:
1、在Broker进程被Kill的场景(在消息收发过程中,利用Kill -9 命令使Broker进程终止), Kafka和RocketMQ都不丢消息,可靠性都比较高。
2、在宿主机掉电的场景,在“同步刷盘”策略下,Kafka与RocketMQ均能做到不丢消息,在“异步刷盘”策略下,Kafka和RMQ都无法保证掉电后不丢消息。
参考来源:http://jm.taobao.org/2016/04/28/kafka-vs-rocktemq-4/
在 消息不重复 方面,RocketMQ和Kafka估计都差不多,在kill或者宕机时,都会存在数据重复,而且RocketMQ官方说明,RocketMQ无法保证数据不重复,建议通过业务手段来保证。
实际应用场景分析(RocketMQ)
1、保证消息按顺序写入和读取
1)顺序写入(前提:单机,或者 集群但是每个节点来源数据不同)
原理:
在同一个队列(分区)的消息是按顺序排列的。(跟Kafka一样,只不过kafka的分区为物理分区,rocketMQ的队列是逻辑分区)
故,要保证消息按顺序处理,必须把它们放在同一个队列中。
实现方式:但producer同步发送数据,按orderid hash来区分队列存放数据。
单线程版:RocketMQ使用单线程同步写入消息到topic里面,topic使用消息类型区分,appid用tags区分,可以在消息中添加orderid关键字。
例如:
Message(topic->"abc", tags->"appid11111", keys->"M324343ef", content);
Message(topic->"cdb", tags->"appid33333", keys->"M684343ef", content);
多线程版:每个线程操作不同appId的数据。实测单机普通CPU多线程无益于提高producer的效率。(i7-CPU测试结果为:两线程比单线程提高36%,三线程比两线程提高12%,三线程CPU已爆满)
2)按顺序消费
RocketMQ的消费方式有两种,一种是传统的自动化的push推模式(对应的DefaultMQPushConsumer),服务器端主动推送消息。另一种是pull拉模式(对应的DefaultMQPullConsumer),客户端从指定位置主动去服务器拉取数据。
RocketMQ 的 推 模式原理:源码分析(略)
问题:Consumer可以设置消费线程的数量,但是在顺序消费的模式(MessageListenerOrderly)下,多个消费线程对于同一队列的数据,无法并行运行,仍然是串行执行,以达到顺序处理数据的目的。对多个不同队列的数据,消费线程可以并行执行。
例如:producer同步发送数据,按orderid hash来区分队列存放数据。假设一个topic,有999个orderid分配到999个队列,
假设consumer端有50个消费线程,那么这50个线程就可以并行的消费999个队列里面的数据。
3)与kafka对比
顺序写入:kafka producer同步发送数据,按orderid hash来区分队列存放数据。假设一个topic,有999个orderid分配到8个分区,
顺序消费:kafka consumer都订阅所有topics,但是consumer线程受制于partition数量的限制,假设为8,那么最多8个线程并行消费数据,这8个线程并行的消费8个partition里面的数据。
关键之处,kafka和rocketMQ的区别在于一个用物理分区来存放数据,一个按虚拟队列的存放数据,都能保证队列或分区里面数据的有序性。
据阿里中间件 官方给出的测试结论,RocketMQ虚拟队列的效率 高于kafka 物理分区的效率,当kafka的分区数大于8时,kafka性能快速下降,而rocketMQ支持1万队列而不会降低性能。
集群模式:
假设有4台master的RocketMQ ,
每台RocketMQ 的consumer都订阅所有topic,
假设一个topic,有999个appid分配到999个队列,
假设每台RocketMQ consumer端有50个消费线程,那么这4*50=200个线程就可以并行的消费999个队列里面的数据。
假设有4台broker的Kafka,
每台kafka的consumer都订阅所有topic,
假设一个topic,有999个orderid分配到8个分区,
总的consumer线程受制于partition数量的限制,假设为8,那么最多8个线程(4*2,每台broker2个线程)并行消费8个partition里面的数据。
显然,RocketMQ 更占优势,如果kafka要达到RocketMQ 这种效果,需要扩展到200个分区才能使200个线程同时消费。
开源版本RocketMQ存在的问题
1、主从不能自动切换,导致了一系列小问题。
1)普通消息当主挂了,会拉取从上面的消息,最后如果主又活过来了,会导致重复消费(之前消费的进度在从上面)。
2)主down,顺序消息不能写入,不能消费(顺序消费不能消费slave上面的消息)。顺序消息是写入特定的queue,这个queue所在的机器挂了,就不能写了,手动写入其他的queue,在业务来看,也是有问题。
2、rocketmq 对于消息重复的处理能力是不足且没有保障的,文档中也明确说明需要业务去重。
3、对于指定位置消费,RocketMQ 的PushAPI比较低级,需要自己实现消费位置的保存、节点的拉取和维护等。
Github上有300多个issues,坑很多,而且看评论,都没有及时解决。
相比Kafka,在Apache下,有完善的测试,能看到存在的bug和fix状态,以及比较详细的说明。比如:
https://issues.apache.org/jira/browse/KAFKA-4189?jql=project%20%3D%20KAFKA%20AND%20resolution%20%3D%20Unresolved%20AND%20component%20%3D%20consumer%20ORDER%20BY%20priority%20DESC
推荐一篇关于RocketMQ非常棒的文章:
http://www.jianshu.com/p/453c6e7ff81c#