消息队列(Message Queue, MQ),顾名思义,就是存放消息的队列,MQ遵循先入先出原则( First Input First Output, FIFO)。且是一种跨进程的通信机制,主要用于上下游传递消息,MQ是一种常见的上下游“逻辑解耦+物理解耦”的消息通信服务。引入MQ之后,系统和系统间只需要依赖于MQ,而无需进行直接依赖。

实现:消息队列常常保存在链表结构中。拥有权限的进程可以向消息队列中写入或读取消息。[1]

目前,有很多消息队列有很多开源的实现,包括JBoss Messaging、JORAM、Apache ActiveMQ、Sun Open Message Queue、RabbitMQ、IBM MQ、Apache Qpid、Apache RocketMQ和HTTPSQS。
为什么要使用MQ:
1、流量削峰
比如,公司订单系统经过测试部门测试,最多能处理10000次订单/秒,正常时段处理订单是完全够用,但是如果在一次商品大促时,此时20000次订单/秒,只能限制订单超过10000订单后不允许用户下单。

如果我们引入消息队列(Message Queue, MQ)来做缓存,我们可以使用户订单排队处理,将1秒中的订单分散成一个时间段来处理,让部分用户等待5~10秒才能响应下单成功,这样即便是让用户等待了几秒或者十几秒,也比无法下单的体验要好上太多。从而为公司挽回了极大的损失。
2、应用解耦
还是电商系统为例,电商系统中有订单子系统、库存子系统、支付子系统和物流子系统等。当用户点击下单,处理链条将会是:订单系统(创建订单等操作)->库存系统(查询库存,减库存等操作)->物流系统(查询收件人、或填写收件等操作)->支付系统。

在这环环相扣的处理链条下,但凡是一个子系统有故障,将会导致整合下单业务操作异常。当引用消息队列(Message Queue, MQ)后,将各个系统进行解耦,如积分系统故障,此时将积分系统要处理的内容缓存到消息队列里,只需要公司运维人员、程序员发现并修复库存系统,用户下单操作依旧可以,且用户感受不到积分系统故障,唯一能让用户感受到的是积分延迟导致,这样系统就不会因为一些非核心流程导致系统不可用。
3、异步处理
在实际环境中,有些服务之间调用是异步执行的,比如说服务A调用服务B需要花费20~30秒,但是服务A并不知道服务B什么时候可以执行完成,在未引入MQ时,有2种传统的方案:
方案一:服务A等待一段时间再去调用服务B的查询API。
方案二:服务A提供一个回调(CallBack)API, 服务B执行完之后,再去调用该API去通知服务A,说执行完成了(这种方案在对接微信支付宝支付很常见)。

如果是公司内部的系统,引入MQ的消息总线,可以更方便、省事去解决异步调用问题,服务A调用服务B后,只需要去监听服务B处理完成放在MQ中的消息。当服务B处理完成后,会发送一条消息给MQ,此时MQ会将消息转发给服务A。
常用MQ对比:
| 产品名称 | 优点 | 缺点 |
| ActiveMQ | 单机吞吐量可达万级,时效性毫秒(ms)级别,可用性高,基于主从架构实现高可用,消息可靠性高较低的概率丢失数据 | 官方对现在ActiveMQ5.x维护越来越少,高吞吐量场景较少使用。 |
Kafka 为大数据而生的消息中间件,百万级TPS 的吞吐量 | 性能卓越,单机写入 TPS 约在百万条/秒,最大的优点,就是吞吐量高, 时效性 ms 级可用性非常高,kaika是分布式的; 在日志领域比较成熟,被多家公司和多个开源项目使用;功能支持: 功能较为简单,主要支持简单的 MQ 功能,在大数据领域的实时计算以及日志采集被大规模使用 | Kafka 单机超过 64个队列/分区,Load 会发生明品的CPU飙高现象,队列越多,load 越高,发送消息响应时间变长,使用短轮询方式,实时性取决于轮询间隔时间,消费失败不支持重试,支持消息顺序但是一台代理宕机后,就会产生消息乱序,社区更新较慢 |
RocketMQ 出自阿里巴巴的开源产品,用Java 语言实现,在设计时参考了Kafka,并做出了自己的一些改进。被阿里巴巴广泛应用在订单,交易,充值,流计算,消息推送,日志流式处理,binglog 分发等场景。 | 单机吞吐量10万级,可用性非常高,分布式架构,消息可以做到0丟失,MQ 功能较为完善,还是分布式的,扩展性好,支持 10 亿级别的消息堆积,不会因为堆积导致性能下降,源码是Java 我们可以自己阅读源码,定制自己公司的MQ | 支持的客户端语言不多,目前是Java及C++,其中C++不成熟;社区活跃度一般,没有在MQ核心中去实现 JMS 等接口,有些系统要迁移需要修改大量代码 |
RabbitMQ 2007 年发布,是一个在AMQP(高级消息队列协议)基础上完成的,可复用的企业消息系统,是当前最主流的消息中间件之一。 | 由于erlang 语言的高并发特性,性能较好;吞吐量到万级,MQ 功能比较完备,健壮、稳定、易用 跨平台、支持多种语言 如:Python. Ruby-. NET、Java、 JMS. C. PHP. ActionSaript、 XMPP、STOMP等,支持AJAX 文档齐全;开源提供的管理界面非常棒,用起来很好用,社区活跃度高;更新频率相当高 | 商业版需要收费,学习成本高 |
参考文献:
[1]郑彦兴. Linux环境进程间通信(三). IBM. 2003-01-17 [2011-01-01]. (原始内容存档于2019-12-01). 消息队列就是一个消息的链表。……它提供有格式字节流,有利于减少开发人员的工作量
[2]尚硅谷RabbitMQ教程丨快速掌握MQ消息中间件