MQ消息中间件

Navy2026-08-02mq

1、什么是消息中间件?

利用高效可靠的消息传递机制进行平台无关的数据交流,并基于数据通信来进行分布式系统的集成。通过提供消息传递和消息排队模型,它可以在分布式环境下扩展进程之间的通信。

消息中间件类似于以前的邮局,比如在没有电话电报等情况下我们想约远方的朋友一起去一个第三方城市旅行,这个时候A可以写一封信,并且在信里表达想约B在几月几号一起去城市X旅行,写完信后A就可以将其放进信封封好贴好邮票,并且填好对方的邮编、地址以及联系方式之后就可以交给邮局。之后邮局就会安排邮政的车给你送达对方城市,并安排邮差根据填的对方地址投递给B。B接收到信并阅读后知道A的意图,这个时候可以给A同样回一封信表示信件已收到,并且同意A的旅行建议。这个时候A再收到B的回信就只需要按照既定行程去落实就行了。

这期间,邮局、邮差只是一个载体,并不负责A和B之间通信内容的磋商,甚至可以说信件里边的文字内容对于邮局和邮差来说都是不可见的,他只提供A和B之间通信的能力

消息中间件也是同样如此,我们可以利用消息中间件在进程之间进行通信,在分布式环境下共同构建合适的业务模型。

2、消息中间件的使用场景

2.1、异步化

在我们日常的业务开发中,经常会有一些伴随的“非核心”的业务,比如用户注册成功之后赠送积分、订单发货之后短信通知等等,这类业务往往是在核心业务执行之后连带执行,这类看起来并不是“核心”但却可能影响核心业务执行效率的业务我们完全可以通过异步化来提升系统核心流程的响应效率从而提升系统的吞吐量。

当然,异步化的方式有多种,如果是系统内部的调用,我们可以考虑多线程,也就是开启一个新的线程来执行任务,或者将这个多线程任务丢给线程池统一调度执行。但是对于跨系统之间的调用,比如前面说的新用户注册赠送积分,可能用户注册的逻辑是在用户服务,而发放积分是在积分服务,这个时候消息中间件无疑就是一个很好的选择。也就是说,当用户完成注册之后,发送一个用户注册完成的消息到mq消息中间件,积分服务通过消费这条消息,然后给当前用户发放指定的积分

2.2、高并发下流量削峰

在分布式场景下,我们往往同时也会面临着高并发的压力。比如一个服务实例只能支撑200个并发请求,这个时候如果同时涌入大量的请求,由于服务器处理的压力可能有些请求就会失败影响用户业务。

这时候可以通过引入MQ来进行请求的缓冲。用户业务请求过来,首先会发送对应MQ消息到消息队列,而不是直接打到后端服务,这个时候后端服务可以基于自己的处理能力,陆续从MQ中拉取消息慢慢进行消费,这样只要保证消息中间件的内存和磁盘的合理承受能力,即使再大的流量洪峰也能应对。

工作中比较常见的场景比如“秒杀”。经常是前端发起秒杀请求后进入轮询等方式等待秒杀结果,而后端接收到前端的秒杀请求后是先发送一条消息到MQ,然后消费端逐个进行消费并反馈“秒杀”结果

2.3、跨进程数据传输

工作中,我们在实现进程数据传输一般会采用HTTP调用或者RPC调用。其实MQ在跨进程数据传输领域也是有它的重要价值的,比如kafka在数据处理等大数据领域的使用是非常广泛的,甚至有人把它当作一个“数据库”在用,经常和spark、flink一起去实现实时计算和离线计算

3、消息中间件的五大核心组成

3.1、协议

所谓协议,就是指定义生产者、消费者和MQ之间的通讯方式,比如数据传输采用什么方式、数据采用何种编解码方式、消息格式如何定义等等,核心的目的就是要求mq和生产者、消费者之间彼此能够“识别”,而不能出现“鸡同鸭讲”的情况

所以协议是计算机之间通信时需要共同遵守的一组约定规范,只有通信双方都遵守同一协议两者才能正常交流,是对数据格式和数据交换时必须遵守的规则描述。

协议三要素:

  • 语法

数据与控制信息的结构或格式

  • 语义

即需要发出何种控制信息,完成何种动作以及做出何种响应

  • 时序

即事件实现顺序的详细说明

比如HTTP协议:

语法:规定了请求报文和响应报文的格式

语义:客户端主动发起的操作统称为请求

时序:一个请求对应一个响应

消息中间件常用的协议:

  • AMQP:

高级消息队列协议,特点是对事务的支持和持久化的支持,最早出现在金融领域,在可靠消息处理上具有天然优势,比如RabbitMQ和ActiveMQ

  • MQTT:

消息队列遥测传输协议,是一个物联网即使通讯协议,特点是轻量化、结构简单、传输快,但是没有对事务的支持和相关的持久化设计,主要适用于计算能力有限、低带宽和网络不稳定的场景下,比如移动设备、传感器指标采集等。

  • OpenMessage:

由阿里等一众公司共同发起的分布式消息中间件、流式处理领域的应用开发标准,特点是结构简单、解析快、而且支持事务、有持久化设计方案,如Rocket MQ

  • kafka

基于tcp的二进制协议,消息内部通过长度来分割,由一些基本数据类型组成。特点是结构简单、解析快、无事务设计(kafka的高版本通过一个事务协调者来进行协调事务状态和管理事务日志)、但是有持久化设计方案。主要在大数据领域广泛应用

为什么消息中间件一般不用http协议呢?主要有几点:首先就是http协议比较重,属于应用层协议,定义了请求头请求体和响应头响应体等,其次http协议一个请求对应一个响应,比如出现网络超时的情况就会出现消息丢失

3.2、持久化机制

消息的持久化机制很好理解,简单地说就是消息不能像java里边的普通的queue存储在内存是“一次性”的。因为消费者可能并不是无时无刻在监听着消息,必须要考虑消息的持久化存储,不能因为服务器重启而数据丢失,要保证消费者在需要的时候能够拿到目标消息。并且最好是能够做大可追溯,比如有相关的日志信息能够查询

常见消息中间件的持久化方式:

image-20260803160719913

3.3、消息分发机制

消息如何正确分发到目标地址也是需要重点考虑的,比如一封信,不能随便寄到一个未知的地方,而实要根据用户填写的地址来邮寄。甚至邮局还会核对地址和邮编,来校验一下收件方的地址的正确性。同样的,在消息中间件的设计的时候也需要考虑清楚一个消息发送出去后该如何路由分发最终落到正确的消费者手上

常见消息中间件对不同分发策略的支持:

image-20260803161244026

3.4、高可用性设计

从消息的角度来看,MQ本身是一个核心的中转,如果消息中间件自身经常挂掉,消息的传递肯定就会出现问题,所以必须保证消息中间件时刻“在线”并且能够正常对外提供服务。总结起来就是要求产品在规定的条件和规定的时间段内具有可执行对应功能状态的能力

为了保证服务的高可用,一般我们会采取集群化部署方案,比如kafka基于zookeeper的集群部署方案和RocketMQ基于NamedServer的集群部署方案,具体内容后续再分析

3.5、高可靠性设计

参照寄信的例子,如果邮局三天两头就会把用户的信件丢失,长此往复用户还会信任地将重要的信件交给邮局来派送吗?我们知道现在社会,一般重要的邮件(比如录取通知书)都是通过邮政来邮寄的,其中一个重要原因就是他们号称在中国的国土范围内,只要是人能到的地方,邮政都能给你派送到,这就是它的可靠性保证。

同样地,如果要设计一个消息中间件,必须要保证消息的可靠性投递。比如如何保证消息可靠地发送到mq、mq如何稳定可靠地存储和分发这些消息、消费者如何可靠地消费这些消息等等,并且这过程中如果出现异常情况,有没有兜底策略。

当然,并不是说必须要完全解决过程中的这些问题,因为使用场景不一样可能要求的侧重点也会不一样,而且可能基于成本和现实情况可能对某一方面也没有强要求,比如消息消费失败后是否需要重新投递,可能有些场景下就不需要。但是有些功能可能暂时用不到,但设计的时候可靠性保障方案必须要考虑

除此之外,消息中间件的高可靠还要求在高并发场景下,系统自身不崩溃、不出错、或者报错的概率非常非常低,可以无故障地稳定运行并提供服务。

总体来说,消息中间件的可靠性主要体现在以下两个方面:

消息传输的可靠性:通过协议来保证系统之间数据解析的正确性

消息存储的可靠性:通过持久化来保证消息的存储可靠性

4、目前主流的消息中间件

4.1、ActiveMQ

比较老了,不作介绍,有需要的可以到apache官网自己学习:

https://activemq.apache.org/

4.2、RabbitMQ

4.3、Kafka

4.4、RocketMQ

4.5、Apache Pulsar

5、使用消息中间件时需要注意的事项

  • 消息的顺序性

在特殊场景下,需要考虑消息消费的顺序性,不同的消息中间件可能对消息的消费顺序有不同的支持,需要结合应用场景进行MQ的合理选型

  • 消息的幂等性

部分消息场景需要考虑消息的幂等性,也就是说如果一个消息消费一次和消费两次产生的影响会不一样,则需要考虑幂等性而不能出现重复消费的情况,比如订单支付赠送积分,如果多次重复发送了赠送积分的消息,那么在消费端如果不做任何校验直接给用户添加积分,则可能出现一个订单重复赠送积分的情况。这个时候我们可以基于订单号的唯一性,在消费端维护一张本地消息表,如果后续同一的订单的消息过来先判断这张本地消息表中的对应订单的状态,如果已经赠送过,则不做处理。

  • 消息的可靠性

消息的可靠性体现在多个环节,比如:

生产者发送消息:比如Rabbit MQ生产者发送消息的时候采用confirm模式发送事务类型消息,这样只要消息发送成功就代表broker一定成功接收到了来自生产者的消息,反之就时发送失败,生产者可以在失败的时候进行重发

MQ本身的消息处理:mq本身的高可用和高可靠性保障,比如集群化部署以及消息的持久化方案的选择等

消费者对消息的消费:比如Rabbit MQ的手动ack模式,消费者可以在消费成功之后手动进行ack,因为上面表格也可以看大Rabbit MQ是支持消息重发的,如果消费失败,对于没有ack的消息消费者在后续还可以继续进行消费

  • 消息堆积

消息中间件不仅考验服务器的压力,同时也会考考验消费端的消费能力。如果消费不及时或者消费能力跟不上,则可能出现MQ服务器上出现大量的消息积压,如果不能及时解决消息积压的问题,有可能会严重影响mq的消息处理能力,而且大量的消息占用内存和磁盘及网络带宽,也会对上下游正常业务产生严重的影响。

最后更新时间: 9/19/2026, 5:28:30 AM