一、前言
前面我们介绍了ActiveMQ,RabbitMq,RocketMQ,Kafka,Pulsar五种消息中间件的基本的功能和架构原理,每种中间件从功能上是比较类似的,但是又各有千秋,不能笼统的说谁最优秀,需要针对具体的应用场景,做出适合的选择。今天我们从功能,性能,可靠性方面,总结下这几个中间件特点,以便给我们的选型做参考。
二、选型标准
1、功能
对于消息中间件选型,功能是优先要考虑的因素,如果功能方面不满足生产要求,其他的也无从考虑。
(1)优先级消息
对于消息可以设置优先级,优先级高的消息拥有优先被消费的特权,这种在是消费速度小于生产速度,产生消息堆积的时候才会有效。如果消息速度大于生产速度,即生产的消息马上被消息,优先级消息也就没有实际意义了。
(2)延迟消息
某些场景中,我们希望投递的消息,不要立即被消息,而是延迟一段时间。比如购买火车票,选择对应的车次后,锁定10分钟,如果该时段内没有付款,将会取消本次购买,释放车票,该场景就可以使用延迟消息实现。从性能上考虑,一般采用固定的定时延迟,比如5s,10s,1m等等,这样可以将相同延迟时间的消息放在一个延迟队列中,批量处理和发送。
(3)事务消息
在可靠性要求比较高的场景,预先发送或者消费消息,再本地逻辑处理,根据处理结果决定提交或者回滚消息。一般采用二阶段提交模式,当Broker没有接受到commit或者rollback指令,会回查该消息,确保消息被处理。
(4)顺序消息
保证消息的生产和消费有序性,很常见的场景就是数据抽取CDC(Change Data Chapture),以Mysql为例,需要确保binlog的抽取和消费的顺序性,否则会导致数据的不一致。
(5)死信队列
某些异常场景下,导致消息投递失败,或者消费失败,为了确保消息的不丢失,并且不影响其他消息的正常消费,一般将该异常消费放置到特定的队列,这个队列被称之为死信队列,死信队列具有普通队列的所有特性,也可以被消费。通过监控死信队列,可以查看异常消息的状态。
(6)消费模式
消费模式分为"推"和"拉"两种模式,"推"模式是Broker主动将消息推送到消费端,这种模式,实时性较好,不过要有措施确保消息端的处理能力,不要被压垮;"拉"模式是消费端主动从Broker获取消息,消费端可以自身的处理能力确定获取消息的速度,但实时性较差。
(7)订阅模式
订阅模式包括点对点模式和发布订阅模式,点对点模式,生产的消息仅能被一个消费者消费;发布订阅模式,生产的消息被所有订阅的消费端消费。实际生产过程中,很多时候是这两种模式的组合,比如在电商业务中,用户下单成功的消息需要被物流,供应商等多个系统同时消费,这种是发布订阅模式;每个系统的消费者为集群模式,仅能被其中某个实例消费,此时又是点对点模式。
(8)消息堆积
削峰是MQ主要场景之一,当消息洪峰到来,消息无法来得及处理,此时就需要依赖中间件的消息堆积能力,实现延迟消费。一般通过大容量磁盘实现消息的持久化存储。
(9)消息回溯
在有些场景下,消息被正确的消费了,但是由于某些异常情况,导致下游的消息丢失,比如数据库磁盘损坏等,此时需要指定消息的位置,进行回溯和重新消费。消息回溯功能对于保证消息“不丢失”非常重要。
(10)消息过滤
按一定的过滤规则为下游消费者提供消息,过滤规则包括值匹配,范围,以及SQL语句,当然,消息过滤会损耗一定的性能。在跨机房转发的场景中,可以通过消息过滤将特定的部分消息转发到其他机房。
(11)消息的查询和追踪
消息从哪里来,最终又到哪里去了,消息的链路追踪对于问题的定位和排查非常重要。
(12)消息清除
对于已消费过,或者超期的消息实施清除,以确保足够的空间接受新的消息。
(13)多租户
在共享相同的系统或程序组件的场景下,实现租户之间数据的隔离。一套集群就可以服务多个租户,多租户带来了成本的降低和运营的简便。
(14)安全性
消息中间件也可以看做是存储模块,如果存在敏感数据或者保密性要求高,那么安全性是必选项。MQ的安全性需要包括身份认证和权限控制,身份认证是指客户端与Broker,Broker与Broker之间的连接认证;权限控制是指对客户端的读写操作进行权限控制。
2、性能
对于MQ而言,性能主要是指吞吐量,时延虽然也是重要的指标,但是对于中间件异步解耦系统来说,无法满足低时延的场景,一般采用RPC同步方式。
为了提升性能,各中间件采用多种方式,如先写入内存然后异步落盘;仅支持顺序追加方式写入;创建索引文件,根据位移快速定位消息位置;批量读取和确认消息等。
3、可靠性
可靠性也是消息中间件重要的指标,需要确保 消息的不丢失,对于某些特定的场景,比如金融,消息的可靠性是要严格得到保证。但是没有任何一款中间件能100%确保消息的不丢失,且可靠性要求越高,必然能损失部分性能,比如同步发送,事务消息,同步落盘等,都是以损耗性能为代价,鱼与熊掌不可兼得。
广义上的可靠性,也包含可用性,故障发送时,能快速转移和恢复,对业务的影响降到最低。中间件采用主从,分布式集群等架构模式,满足对可用性的要求。
4、开发语言和社区生态
这条也是选择中间的现实考虑因素之一,特别对于中小企业,这个可能成为最优先考虑因素,如果选择的中间件与团队的技能不匹配,或者中间件的社区活跃读不高,就意味后续需要投入更多成本进行学习和踩坑。
当然选型过程中,还有其他很多考虑因素,比如运维工具,项目的继承性等等。总之,没有一个中间件能包治百病,只能对症下药,综合各种因素,最大程度选择适合自己的。
三、总结
下面我们用表格来总结下各个中间件的特点
分类 | 子项 | ActiveMQ | RabbitMQ | Kafka | RocketMQ | Pulsar |
产品定位 | 可靠性消息系统 | 可靠性消息系统 | 分布式的流平台 | 可靠性消息系统 | 多租户,高性能的数据交互平台 | |
基本功能 | 消息优先级 | 支持 | 支持 | 不支持 | 支持,采用不同Topic实现 | 不支持 |
延迟消息 | 不支持 | 支持 | 不支持 | 支持 | 支持 | |
事务消息 | 支持 | 支持 | 支持 | 支持 | 不支持 | |
顺序消息 | 部分支持,仅对点对点模式 | 不支持 | 部分支持,仅单分区模式 | 支持,全局顺序以及分区顺序 | 部分支持,仅单分区独占模式 | |
死信队列 | 支持 | 支持 | 不支持 | 支持 | 支持 | |
消费模式 | 推,拉 | 推,拉 | 拉 | 推,拉 | 推 | |
订阅模式 | 点对点,订阅发布 | 点对点,设置交换器类型变相实现订阅发布 | 发布订阅,通过消息组变相实现订阅 | 点对点,发布订阅 | 发布订阅,通过消费者,独占模式变相实现点对点 | |
消息堆积 | 支持 | 支持 | 支持,能力较高 | 支持,能力较高 | 支持,能力较高 | |
消息回溯 | 不支持 | 不支持 | 支持,可按照offset以及timestamp回溯 | 支持,按照时间维度回溯 | 支持,与kafka类似 | |
消息过滤 | 支持,通过消息过滤器 | 支持 | 不支持 | 支持,按照Tag或者自定义属性过滤 | 支持,支持sql过滤 | |
消息追踪 | 不支持 | 支持 | 不支持 | 支持 | 不支持 | |
消息清除 | 消息被消费以及过期后清除 | 消息被消费以及过期后清除 | 指定保存时间,或者日志大小,达到阀值后清除 | 指定保存时间,过期后清除 | 指定保存时间,过期后清除 | |
多租户 | 不支持 | 支持 | 支持 | 不支持 | 支持 | |
安全性 | 支持 | 支持 | 支持 | 支持 | 支持 | |
性能 | 写入性能 | 好,单机吞吐达到万级 | 好,单机单broker,7W/s | 非常好,每条10字节,达到百万条/s | 好,RAM为rocket的1/2,disk为roket的1/2 | 非常好,与kafka接近 |
性能的稳定性 | 消息堆积时,性能不稳定 | 消息堆积时,性能不稳定 | partiton过多(单机达到64),写入性能明显下降。堆积时性能稳定 | 队列较多,消息堆积时,性能稳定 | 队列较多,消息堆积时,性能稳定 | |
单机的队列数 | 依赖存储模式,AMQ不超过200,KahaDB支持数较大 | 依赖内存 | 单机超过64个分区/队列,load发生明显的飙高,发送的响应时间长 | 支持5万个队列,不会明前的变化 | 可支持10W+队列 | |
堆积性能 | 好,利用KahaDBd对接 | 一般,利用磁盘对堆积 | 非常好,每个partition存在一个log中 | 非常好,每台都存在commitlog中 | 非常好,利用Bookkeeper堆积 | |
可靠性 | 很好,支持主从间同步 | 好,producer生产数据可以同步/异步ack,数据持久化,镜像数据会主动同步。消费方消费数据后,返回ack | 很好,支持同步复制,同步刷盘,性能会下降 | 很好,支持同步复制,同步刷盘, | 很好,支持同步复制,同步刷盘,性能会下降 | |
可用性 | 高,采用主从模式 | 高,采用镜像式主从实现 | 非常高,分布式集群 | 非常高,采用主从模式集群 | 非常高,分布式集群 | |
社区成熟度 | 成熟度 | 高 | 高 | 高 | 中 | 中 |
活跃度 | 高 | 高 | 高 | 中 | 中 | |
开发语言 | java | Erlang | Scala | java | java | |
api以及文档完备度 | 高 | 高 | 高 | 高 | 高 | |
支持协议 | JMS | AMQP | 自行设计的基于tcp的二进制协议 | 自定义协议(基于netty通讯) | 自定义的tcp二进制协议 | |
特点 | 优点 | 1、支持JMS协议,有多种客户端选择 2、功能完备,性能稳定,成熟度高 3、java语言,入门简单,适合中型规模的吞吐的场景 | 1、支持AMQP协议,多种客户端 2、路由策略灵活,可靠性高 | 1、高吞吐量,低延迟,高可用,集群扩展,容错。 2、生态好,尤其在大数据处理上 | 1、高吞吐量,低延迟 2、支持顺序消息,消息过滤,事务消息等,功能较全 3、不受分区限制,水平扩展能力强 | 1、高吞吐量,低延迟 2、计算存储分离,水平扩展和rebalance效率高 3、支持的topic的分区数可达百万级 |
缺点 | 1、由于历史的包袱,在高并发,高吞吐不如其他的中间件 | 1、吞吐量上不如kafka如rocketmq 2、erlang难度较大,不利于普及 | 1、集群消费收分区数目限制 2、单机的partition过多,性能下降明确 3、rebalance对生产运行影响较大。 | 1、吞吐量上不如kafka 2、不支持master主动切换,客户端只支持java | 1、目前使用的案例没有kafka多,在稳定性上有待进一步检测。 |
附录: