Message Queue

Overview

大致解释一下什么是消息队列,为什么使用消息队列,并以QMQ为基础解释一下消息队列的实现


  • Message Queue
  • Overview
  • 消息队列使用场景
  • 解耦
  • 一致性
  • 强一致性
  • 最终一致性
  • 广播
  • 错峰与流控
  • 延时
  • 消息队列的特点
  • 消息队列的本质


消息队列使用场景

消息队列,顾名思义,是一个由消息组成的队列数据结构,是一种常见的异步RPC手段
存在的意义一般在于业务解耦、最终一致性、广播、错峰流控
如果你需要强一致性,RPC是更好的选择

解耦

语义的重点在于通知,而不是执行

举个例子, 用户购买机票, 支付之后, 系统有以下流程
1. 更改流水和订单状态
2. 通知代理商出票
3. 发送短信通知用户购买的行程

可想而知, 发送短信这个行为, 是典型的非核心, 并发能力低, 响应耗时长的服务.
用户支付完成之后, 需要保证快速, 并且一定为用户更新订单状态, 并开始出票. 但是短信不是, 用户晚个半分钟收到短信并不会造成什么影响, 但是订单状态晚半分钟才更新, 显然就会对用户造成很不好的影响.
这个时候, 我们如果使用消息队列来通知短信服务, 主流程就顺利进行下去, 就实现了完美的业务解耦.

一致性

所有跨VM的一致性问题,从技术角度来说,都只有强一致性(分布式事务)最终一致性(记录、补偿)两种解决方案

比如经典的转账案例,就有可能有多种意外发生

1.A扣钱成功, B加钱失败
2.A扣钱成功, B加钱成功, 结果回传时网络异常
3.A扣钱成功, B加钱失败, A想回滚但是down机

强一致性

分布式事务

最终一致性

最终一致性的大多实现方式都属于 记录+补偿
在做不确定的事情之前,先记录下
不确定的事情成功完成之后,删除记录,否则由task补偿性地重新触发这件事,直到成功为止

比如转账的例子
1. A基于本地事务扣钱和记录“通知B”,失败就一起回滚,然后再RPC将这个通知落地到broker,成功才删除“通知B”这个记录,否则定时任务扫描重试
2. broker通知B(推送, 或者由B主动拉取)
3. consumer消费成功, 通知A才删除落地记录,否则重试

这个操作显然也可以由RPC来实现,但是如果将其抽象出来,就变成了Message Queue
通过消息的两次落地+补偿, 可以确保consumer一定收到消息. 当然, 这种方式不可避免需要提到去重的问题.
为什么要使用broker,后面会解释

广播

从通知的语义来分析, 消息队列需要把消息通知到对应的目标, 常见的就是两种通知方式: 点对点, 广播.
点对点: 顾名思义, 只对目标推送消息, 这种应用场景极少, 就不细说了.
广播则也是MQ的一大核心特点和优势,把消息队列中的所有消息推送给所有可接收消息的目标, 当新接入下游的时候,我们就只需要关注消息是否成功推送到了发送队列,而不用在乎哪些下游需要订阅
将对消息的依赖转移到了下游

我们还是用转账这个例子, 假设A扣钱之后, 原本只需要通知到转账业务, 为B加钱, 现在增加需求, 需要给A发送扣钱成功的短信. 那么我们只需要把这个短信业务注册为下游去消费消息就行了, 并不需要改动到上游或者消息队列.

但是广播也有一些问题, 现在大家的服务器都是集群了, 那么如何需要保证一个集群, 只有一个服务器收到消息并消费呢? 如何控制某台服务器一定要收到消息呢?
这一点, 在QMQ中, 通过Group的方式获得了解决.

  1. Consumer以Group的方式注册
  2. Broker向每个Group中选择一台服务器推送消息
  3. Consumer希望保证收到消息, 可以在Group处留白, 默认注册为独一无二的group
    总结为一句话, 就是组内单播, 组间广播

错峰与流控

前端的最大QPS显然远远高于数据库的处理能力,MQ就可以扮演一个漏斗的角色
如果没有MQ,使用RPC来实现,就需要上游或者下游自己处理请求的存储、拥塞、定时等问题,而且每增加这么一组上下游处理能力有差距的服务,就需要单独开发一套逻辑, 而且上下游耦合太过严重
如果没有Broker, 转储和解耦更像是无稽之谈.
1. 我们需要broker来转储消息, 并在合适的时间, 投递给合适的Consumer
2. 我们需要把provider和consumer解耦, provider只需要把消息投递到消息队列, 完全不需要关注consumer的存在.

延时

有些业务场景, 需要用到延时, 消息队列显然也是不错的选择
当然, 这也是Broker的一大作用.

消息队列的特点

消息队列的本质

一次RPC变N次消息转储选择合适的时间投递

  1. provider消息投递到broker
  2. broker消息投递到consumer
  3. consumer消费确认, 通知broker