一、MQ及MQ组件
1. MQ的解释与用处
如果你已经对MQ有所了解,想必对其用途已经了然于胸了。如果你仅仅是听说过,或许可以直白的描述它,它就相当于日常生活中的社交软件的消息,可以通过它把信息发给对方。特点是不如电话那么及时,但可以群发,即使对方不在线,等其上线照样可以获得该信息。当然,从架构角度消息归纳起来有以下几种好处
- 解耦应用程序: 使用MQ,应用程序之间可以通过中间件进行通信,这样应用程序之间的连接就成为松散的,即使一方出现问题也不会影响其他应用程序的正常运行。
- 提高系统可靠性:MQ允许将消息存储在队列中,这样如果一个应用程序出现故障,消息也不会丢失。在应用程序恢复正常运行后,它可以从队列中读取并处理这些消息。
- 增加系统伸缩性:MQ允许多个应用程序同时访问同一个队列,这样就可以轻松地添加更多消费者来处理消息,从而实现水平扩展。
- 支持异步处理:使用MQ,发送者可以异步发送消息到队列中,接收者可以在自己的时间内获取并处理这些消息,从而提高系统的性能和响应速度。
- 支持多种协议和消息格式:MQ支持多种协议和消息格式,如AMQP、JMS、Kafka等,可根据需要选择合适的协议和格式。
2. 几款常用的MQ框架简介
除了我们今天的主角rabbitMQ,目前市面上还有几款消息中间件是比较流行的,如ActiveMQ、Apache Kafka、以及阿里的RocketMQ,我们以一张简表速览一下
二、RabbitMQ的特点
1. RabbitMQ的模型与优势
我们先来看看RabbitMQ的模型图,其主要有交换机(Exchange)、队列(Queue)两个组件构成。然后通过绑定和路由配置来实现多种传递方式,可以说功能十分强大
更具体的说,其具备以下特点:
- AMQP支持:RabbitMQ 实现了 AMQP,这是一个强大的开放标准消息协议,支持多语言和平台。
- 可靠性:RabbitMQ 提供了丰富的特性来保证消息的可靠性,包括消息确认、持久化、镜像队列、备份队列等。
- 灵活性:RabbitMQ 支持多种消息模式,如点对点、发布/订阅、任务队列、RPC等,满足各种应用场景的需求
- 扩展性:RabbitMQ 拥有分布式架构,支持高可用和集群部署,可以实现水平和垂直扩展
- 监控和管理:RabbitMQ 提供了 web 控制台和命令行工具,方便用户对队列状态进行监控和管理。
- 社区支持:RabbitMQ 的用户社区非常活跃,提供了大量的文档和教程,有问题可以很快得到解决
2. 与kafka的对比
kafka严格的讲,并不是一款MQ框架,也没有实现 AMQP 协议。更确切的说,kafka是一款分布式流处理平台,以高吞吐量、低延迟和可靠性为特点,适用于大规模数据处理和实时数据集成,但我们仍然可以把它作为一种消息中间件来使用,我们来看下它与rabbitMQ的详细对比:
对比项 |
kafka |
rabbitmq |
单机吞吐量 |
10万级 |
万级 |
时效性 |
ms级以内 |
us级(微秒级) |
是否支持消息回溯 |
支持消息回溯,因为消息持久化,消息被消费后会记录offset和timstamp |
不支持,消息确认被消费后,会被删除 |
是否支持消息数据持久化 |
支持消息数据持久 |
支持消息数据持久 |
优先级队列 |
不支持 |
支持。建议优先级大小设置在0-10之间。 |
延迟队列 |
不支持 |
支持 |
重试队列 |
不支持。 |
不支持RabbitMQ中可以参考延迟队列实现一个重试队列,二次封装比较简单。如果要在Kafka中实现重试队列,首先得实现延迟队列的功能,相对比较复杂。 |
是否支持消息堆积 |
支持消息堆积,并批量持久化到磁盘 |
支持阈值内的消息对接,无法支持较大的消息堆积 |
是否支持流量控制 |
支持控制用户和客户端流量 |
支持生产者的流量控制 |
开发语言 |
scala,Java |
erlang |
是否支持多租户 |
2.x.x支持多租户 |
支持多租户 |
是否支持topic优先级 |
不支持 |
支持 |
是否支持消息全局有序 |
不支持 |
支持 |
是否支持消息分区有序 |
支持 |
支持 |
是否内置监控 |
无内置监控 |
内置监控 |
是否支持多个生产者 |
一个topic支持多个生产者 |
|
是否支持多个消费者 |
一个topic支持多个消费者 |
|
是否支持一个分区多个消费者 |
不支持 |
不支持 |
是否支持JMX |
支持 |
不支持(非java语言编写) |
是否支持加密 |
支持 |
支持 |
消息队列协议支持 |
仅支持自定义协议 |
支持AMQP、MQTT、STOMP协议 |
客户端语言支持 |
支持多语言客户端 |
支持多语言客户端 |
是否支持消息追踪 |
不支持消息追踪 |
支持消息追踪 |
是否支持消费者推/拉模式 |
拉模式 |
推模式+拉模式 |
是否支持广播消息 |
支持广播消息 |
支持广播消息 |
元数据管理 |
通过zookeeper进行管理 |
支持消息数据持久 |
默认服务端口 |
9200 |
5672 |
默认监控端口 |
kafka web console 9000;kafka manager 9000; |
15672 |
网络开销 |
相对较小 |
相对较大 |
内存消耗 |
相对较小 |
相对较大 |
cpu消耗 |
相对较大 |
相对较小 |
3. 为什么选择RabbitMQ?
什么时候才能选rabbitMQ作为自己系统的中间件呢?我可以举一个实例
我们系统在过去有大量的同步调用,而且因为下游的实现语言有很多种,有java、C# 、PHP等。所以同步调用其实采用的自研协议,但是同步调用加自研协议的性能,带来的一个问题就是链路很耗时,硬件利用率低,给用户的印象就是卡和延迟,因此急需缩短链路上的耗时,但因为承担的核心系统间的调用功能,所以业务的可靠性需要极高的保障,而且下游真的出现问题要能及时发现和通知。
针对这种场景,那么我们就需要一款消息组件来作为异步调用中转,而且该组件需要有可靠性。那么它应当有以下几种功能:
- 消息可靠,要求消息全程都能有保障,消息能落在硬盘上
- 下游多语言的支持
- 对下游有容错,消息有自动重发能力。
- 支持一条消息被多个下游消费,且下游数量可随意增减
- 消息支持轮流消费和广播两种能力
- 有方便的管理界面,进行总体情况的查看
- 灵活的消息传递路径
- 社区活跃,有问题方便解决
其中有几种是MQ组件独有的能力,比如有消息重发的能力,这一点Kafka就得开发者自己去搞定了,所以kafka首先排除。
然后是RocketMQ,RocketMQ其实顺序消息和实时性方面更加优秀,但一个是下游多语言,一个是社区活跃度就稍有不足了,尤其是rocketMQ目前仅支持java及c++,这一点是致命伤,所以用不了RocketMQ
同样的,ActiveMQ也是个成熟的项目,支持多语言而且功能完善,但也有问题,就是其界面支持比较弱。另外现在Apache的工作中心在其下一代Apollo,社区活跃度也下降了,所以ActiveMQ后续的长期维护肯定不方便的,被排除
如此一来,只剩一个水桶选择了,那就是rabbitMQ,它满足了我们需要种种功能,社区活跃度还高,支持多种模型和管理都是加分项,而且延迟很低
4. 不可避免的弊端
尽管我们最后选了RabbitMQ,但也不能忽视其存在的问题:
使用的学习成本:其基于AMQP的协议,有着交换机和队列及绑定操作,以及多种路由规则,并不是傻瓜式的上手就能掌握。
排查的成本,RabbitMQ的性能和可靠性是使用Erlang语言的结果,但这也使得它的维护成本较高,因为Erlang相对于其他编程语言使用较少,而且维护排查问题的成本较高
限制较多:RabbitMQ限制了消息的大小、队列数量、连接数量等,这可能在一些特定场景下对业务造成限制。