在 IM 这种讲究高并发、高消息吞吐的互联网场景下,MQ 消息中间件是个很重要的基础设施,它在 IM 系统的服务端架构中担当消息中转、消息削峰、消息交换异步化等角色。
当然,MQ 消息中间件的作用远不止于此,它的价值不仅仅存在于技术上,更重要的是改变了以往同步处理消息的思路。
比如进行 IM 消息历史存储时,传统的信息系统作法可能是收到一条消息就马上同步存入数据库,这种作法在小并发量的情况下可以很好的工作,但互联网大并发环境下就是灾难。
MQ 消息中间件可以理解为一个水池,水池的这头是消息生产者,水池的那头是消息消费者,生产者和消息者无需直接对接,这将带来很多好处:业务解耦、架构分布式化等,生产者和消费者互相完全透明。
但市面上的 MQ 消息中间件产品很多,作为 IM 系统中必不可少的一环,我们该如何选型?
什么是消息队列中间件
消息队列中间件(简称消息中间件)是指利用高效可靠的消息传递机制进行与平台无关的数据交流,并基于数据通信来进行分布式系统的集成。
通过提供消息传递和消息排队模型,它可以在分布式环境下提供应用解耦、弹性伸缩、冗余存储、流量削峰、异步通信、数据同步等等功能,其作为分布式系统架构中的一个重要组件,有着举足轻重的地位。
目前开源的消息中间件可谓是琳琅满目,能让大家耳熟能详的就有很多,比如 ActiveMQ、RabbitMQ、Kafka、RocketMQ、ZeroMQ 等,不管选择其中的哪一款,都会有用的不趁手的地方,毕竟不是为你量身定制的。
可能有些大厂在长期的使用过程中积累了一定的经验,加上其消息队列的使用场景也相对稳定固化,或者目前市面上的消息中间件无法满足自身需求,同时它也具备足够的精力和人力而选择自研来为自己量身打造一款消息中间件。
但是绝大多数公司还是不会选择重复造轮子,那么选择一款适合自己的消息中间件显得尤为重要。
就算是前者,那么在自研出稳定且可靠的相关产品之前也会经历这样一个选型过程。
在整体架构中引入消息中间件,势必要考虑很多因素,比如成本及收益问题,怎么样才能达到最优的性价比?
虽然消息中间件种类繁多,但是各自都有各自的侧重点,选择合适自己、扬长避短无疑是最好的方式。如果你对此感到无所适从,本文或许可以参考一二。
各类消息队列简述
ActiveMQ
Apache 出品的、采用 Java 语言编写的完全基于 JMS1.1 规范的面向消息的中间件,为应用程序提供高效的、可扩展的、稳定的和安全的企业级消息通信。
不过由于历史原因包袱太重,目前市场份额没有后面三种消息中间件多,其最新架构被命名为 Apollo,号称下一代 ActiveMQ,有兴趣的同学可自行了解。
RabbitMQ
采用 Erlang 语言实现的 AMQP 协议的消息中间件,最初起源于金融系统,用于在分布式系统中存储转发消息。
RabbitMQ 发展到今天,被越来越多的人认可,这和它在可靠性、可用性、扩展性、功能丰富等方面的卓越表现是分不开的。
Kafka
起初是由 LinkedIn 公司采用 Scala 语言开发的一个分布式、多分区、多副本且基于 ZooKeeper 协调的分布式消息系统,现已捐献给 Apache 基金会。
它是一种高吞吐量的分布式发布订阅消息系统,以可水平扩展和高吞吐率而被广泛使用。目前越来越多的开源分布式处理系统如 Cloudera、Apache Storm、Spark、Flink 等都支持与 Kafka 集成。
RocketMQ
是阿里开源的消息中间件,目前已经捐献给 Apache 基金会,它是由 Java 语言开发的,具备高吞吐量、高可用性、适合大规模分布式系统应用等特点,经历过双 11 的洗礼,实力不容小觑。
ZeroMQ
号称史上最快的消息队列,基于 C 语言开发。ZeroMQ 是一个消息处理队列库,可在多线程、多内核和主机之间弹性伸缩。
虽然大多数时候我们习惯将其归入消息队列家族之中,但是其和前面的几款有着本质的区别,ZeroMQ 本身就不是一个消息队列服务器,更像是一组底层网络通讯库,对原有的 Socket API 上加上一层封装而已。
目前市面上的消息中间件还有很多,比如腾讯系的 PhxQueue、CMQ、CKafka,又比如基于 Go 语言的 NSQ,有时人们也把类似 Redis 的产品也看做消息中间件的一种。
当然,它们都很优秀,但是本文篇幅限制无法穷其所有,下面会针对性地挑选 RabbitMQ 和 Kafka 两款典型的消息中间件来做分析,力求站在一个公平公正的立场来阐述消息中间件选型中的各个要点。
消息中间件选型要点
衡量一款消息中间件是否符合需求,需要从多个维度进行考察。
首要的就是功能维度,这个直接决定了你能否最大程度上地实现开箱即用,进而缩短项目周期、降低成本等。
如果一款消息中间件的功能达不到想要的功能,那么就需要进行二次开发,这样会增加项目的技术难度、复杂度以及增大项目周期等。
消息中间件具体选型指标
功能维度
功能维度又可以划分成多个子维度,大致可以分为以下这些。
优先级队列
优先级队列不同于先进先出队列,优先级高的消息具备优先被消费的特权,这样可以为下游提供不同消息级别的保证。
不过这个优先级也是需要有一个前提的:如果消费者的消费速度大于生产者的速度,并且消息中间件服务器(一般简单的称之为 Broker)中没有消息堆积。
那么对于发送的消息设置优先级也就没有什么实质性的意义了,因为生产者刚发送完一条消息就被消费者消费了,那么就相当于 Br