在构建复杂的微服务架构时,服务间的通信和解耦是至关重要的环节。Apache RocketMQ 作为一款高性能、高可靠、分布式、开源的消息中间件,在微服务生态系统中扮演着举足轻重的角色。本文将详细讲解 RocketMQ 在微服务中的作用、核心概念以及常见应用场景。

1. 异步解耦 (Decoupling)

首先,了解,在没有异步解耦的情况下,订单服务是如何完成的呢

以订单服务为例,一个完整的订单服务包含,通知厨房减库存,增加会员积分,发送下单成功的短息。

同步调用的方法,非常繁琐,系统中有三个任务。它需要线性的依次完成他们,才算成功。

先减库存,然后等待它的完成,然后再增加积分,等待它完成后,再进行发送短信。

三件事前全部完成后,才会现实订单服务的完成。

这会导致什么问题(痛点)?

  • 响应极慢:三个任务排队,不能同时进行

  • 一挂全挂(单点故障):因为这是一个线性工程

  • 牵一发而动全身(耦合度极高):点餐员必须认识后厨、认识收银台、认识客服。如果明天老板说“下单还要增加抽奖功能”,点餐员又要去认识抽奖员。

引入 RocketMQ 后: 订单服务只需完成核心的“创建订单”逻辑,然后向 RocketMQ 发送一条“订单已创建”的消息,就可以立即响应用户“下单成功”。库存服务、短信服务、积分服务作为消费者 (Consumer),从 RocketMQ 订阅该消息并各自异步执行

2. 削峰填谷 (Peak Shaving and Valley Filling)

双十一中,订单数量巨大,并且它的峰值和低估值相差巨大,峰值肯能会冲爆服务器。

但是为了几个可能冲垮服务器的峰值,升级服务器的性能,明显是不划算的。

RocketMQ能够解决这个问题。

首先所有服务的消息,都会先发送到这个MQ中。所有服务也是从这个MQ中获取消息。

RocketMQ的抗压能力很强,能够承受高峰,相当于一个缓冲池。

各个服务会从里面匀速的拉取自己的消息。

从而避免了被高峰冲垮的可能。

当理解了最基础的概念后,你可以再去了解:消息队列和负载均恒。

也可以了解单服务器与集群服务器再负载均衡中的差异

3. 数据最终一致性 (事务消息)

了解它之前,应该先了解事务--强一致性,和分布式事务--最终一致性。

单体架构中,所有的业务逻辑(比如:扣减账户余额、增加用户积分)都连着同一个数据库。我们只需要利用关系型数据库(如 MySQL)自带的事务机制(@Transactional),就能保证这两步操作要么一起成功,要么一起回滚。这叫做强一致性。 

  • 强一致性:要求任何时刻,所有节点的数据都是绝对同步的。在分布式系统中,这需要极高的协调成本,会导致系统在协调期间被“锁死”,严重拖慢性能。(在著名的 CAP 定理中,为了追求可用性和性能,通常需要放弃强一致性)。                   

微服务架构中,系统被拆分了:“资金服务”有自己的数据库,“积分服务”也有自己的数据库。 此时,一个业务流程(如用户下单付款)需要跨越多个服务、调用多个数据库。这就是分布式事务问题。

  • 最终一致性:允许系统在短暂的时间内,数据处于“不一致”的状态。但是经过一段时间的自动重试或补偿后,最终所有服务的数据都会达到一致的目标状态。

为了实现最终一致性:RocketMQ引入了“半消息 (Half Message)”“事务回查 (Transaction Check)”机制。
具体流程如下:

  1. 发送半消息:A 服务先向 RocketMQ 发送一条“我要给 B 服务加积分”的消息。此时这条消息是 “半消息”(意思是 MQ 收到了,但在 A 服务确认之前,B 服务绝对看不见它)。

  2. MQ 回复 OK:RocketMQ 告诉 A 服务:“半消息我收到了,你可以去扣余额了”。

  3. 执行本地事务:A 服务执行本地数据库操作,扣减用户余额。(消息的异步解耦,它没有得到B服务的确认)

  4. 提交消息:A 服务扣减成功后,向 RocketMQ 发送“提交(Commit)”指令。

  5. 消费者可见:RocketMQ 收到 Commit 后,将“半消息”转换为“普通消息”。此时,B 服务(积分服务)终于看到了这条消息,开始执行增加积分的操作。

过程不同于强一致性。

分布式事务的。

真正的分布式痛点在于网络异常或宕机。如果第 3 步执行完,还没来得及执行第 4 步(告诉 MQ 提交),A 服务突然断网了、或者服务器重启了,怎么办?

如果用其他普通 MQ:这条消息就永远丢失了(或者停留在不可见状态),结果是 A 扣了钱,B 却没有加积分。用户会疯狂投诉。

RocketMQ 的解决方案:事务回查! 如果 RocketMQ 迟迟没有收到 A 服务的 Commit 或 Rollback 指令,它会主动出击

  1. 发起回查:RocketMQ 会主动联系 A 服务(集群中的任意一台存活的机器),询问:“兄弟,刚才那条‘半消息’对应的本地事务,你到底执行成功了没有?”

  2. 查询本地状态:A 服务收到回查请求后,去查一下本地数据库,看看那笔订单/扣款有没有落库。

  3. 根据结果答复

    • 如果数据库里显示扣款成功了,A 告诉 MQ:“提交(Commit)”。

    • 如果数据库里没这笔账,A 告诉 MQ:“回滚(Rollback)”。

  4. MQ 执行后续动作:根据 A 的答复,决定是让 B 服务去消费,还是直接丢弃这条消息。

更多推荐