消息队列基础
消息队列,即Message Queue,简称MQ
是什么
就是一个用于服务间通信的中间件,包含生产者和消费者两个角色,生产者向队列生产消息,消费者从队列消费消息,从而实现了通信。
有什么用
主要用途:
- 解耦
- 异步
- 削峰
解耦
生产中可能有如下痛点:系统内上下游服务直接耦合,扩展难、维护难。
举例:
a、d是上游服务,b、c、e是下游服务
不使用消息队列时系统架构如下:
即接口调用,上游服务调用下游服务接口
痛点:
若增加了新的下游服务或下游服务提供的接口发生变动,则上游a、d就必须修改代码。
使用消息队列时系统架构如下:
即上游服务生产消息,下游服务消费消息、执行逻辑处理
此时,再新增下游服务或下游服务接口有变动,不会影响到上游a、d,上游服务只管生产消息,而下游服务消费消息、执行逻辑处理即可,上下游通过MQ解耦。
异步
生产中可能有如下痛点:
接口的调用链路很长,可能需要调用非常多的服务,若同步调用,则接口响应慢,用户体验不好,且会降低系统的吞吐量。
场景举例:
一个用户的下单操作,会经过如下链路:
- 调用订单服务,更新订单状态
- 调用库存服务,扣减库存
- 调用消息服务,发送消息触达用户
- 调用积分服务,增加用户积分
- ...
可以看到调用链路很长,如果同步调用,则用户的下单操作响应会很慢,另外用户下单时核心业务逻辑就是更新订单的状态,其他操作不需要同步且实时性要求没那么高,完全可以异步执行,此时就可以使用消息队列实现异步处理:
订单服务处理完订单状态后,向消息队列发送一个消息,然后直接返回;库存服务、消息服务、积分服务等下游服务分别消费消息、执行相应的逻辑处理。
削峰
生产中有如下痛点:
某时间段服务的访问量非常高,远大于服务集群的处理能力,可能会打挂服务。
可以把请求扔到消息队列里,服务从消息队列中取出请求进行处理,有消息队列在前面缓冲,就避免了大流量打挂服务。
其他应用场景
- 数据采集,比如,收集业务日志、监控数据、用户行为等数据。
一定要使用消息队列吗
使用消息队列有好处,也有坏处,好处如上所述,坏处有:
- 系统可用性降低。使用了消息队列,系统就会增加依赖,若消息队列挂了,可能导致系统不可用
- 系统复杂度增加。使用了消息队列,需要考虑额外的问题,比如:消息丢失、消息重复、消息堆积、消费失败等问题。
主流的几种MQ
MQ协议
- JMS
- AMQP
- STOMP
- MQTT
不是所有的MQ产品都会实现以上协议,有些是自定义协议
消息队列的数据流图
在大多数MQ产品中,存储消息的服务器叫做broker,说白了就是消息队列服务端
消息模型
- 点对点模型
- 发布/订阅模型
点对点模型
一个消息只能由一个消费者消费。
缺点:不能满足多个消费者都消费全量消息的需求。
发布/订阅模型
在发布/订阅模型中:
一个消息必须属于一个topic,topic对消息进行分类;
生产者就是发布者,向topic发布消息;
消费者就是订阅者,订阅topic,从而消费topic的消息;
topic的每个订阅者都能消费该topic的全量消息。
优点:
能满足多个消费者都消费全量消息的需求。
消费模式
消费模式是消费者获取消息的方式,有:
- push模式:MQ主动给消费者推消息
- pull模式:消费者主动从MQ拉消息(会轮询)
对比:
-
push模式:
-
优点:实时性好。
-
缺点:
- 若生产者生产速度快于消费者消费速度,则消费者会来不及消费,导致消费者进程内存占满,甚至崩溃。
- 因为是MQ主动,所以MQ的负担较重。
- 无反馈机制,无法知道消息是否消费成功。
-
-
pull模式:
-
优点:
- 消费者可以控制消费速度。
- MQ的负担轻。
- 有反馈,若消息消费失败会重新入队。
-
缺点:实时性不行。
-
消息队列常见的一些问题
- 消息丢失
- 消息重复
- 消费失败,重试消费
- 消息堆积
后续详细介绍