简单讲解微服务向的RocketMQ的重要概念。
在构建复杂的微服务架构时,服务间的通信和解耦是至关重要的环节。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)”机制。
具体流程如下:
-
发送半消息:A 服务先向 RocketMQ 发送一条“我要给 B 服务加积分”的消息。此时这条消息是 “半消息”(意思是 MQ 收到了,但在 A 服务确认之前,B 服务绝对看不见它)。
-
MQ 回复 OK:RocketMQ 告诉 A 服务:“半消息我收到了,你可以去扣余额了”。
-
执行本地事务:A 服务执行本地数据库操作,扣减用户余额。(消息的异步解耦,它没有得到B服务的确认)
-
提交消息:A 服务扣减成功后,向 RocketMQ 发送“提交(Commit)”指令。
-
消费者可见:RocketMQ 收到 Commit 后,将“半消息”转换为“普通消息”。此时,B 服务(积分服务)终于看到了这条消息,开始执行增加积分的操作。
过程不同于强一致性。
分布式事务的。
真正的分布式痛点在于网络异常或宕机。如果第 3 步执行完,还没来得及执行第 4 步(告诉 MQ 提交),A 服务突然断网了、或者服务器重启了,怎么办?
如果用其他普通 MQ:这条消息就永远丢失了(或者停留在不可见状态),结果是 A 扣了钱,B 却没有加积分。用户会疯狂投诉。
RocketMQ 的解决方案:事务回查! 如果 RocketMQ 迟迟没有收到 A 服务的 Commit 或 Rollback 指令,它会主动出击:
-
发起回查:RocketMQ 会主动联系 A 服务(集群中的任意一台存活的机器),询问:“兄弟,刚才那条‘半消息’对应的本地事务,你到底执行成功了没有?”
-
查询本地状态:A 服务收到回查请求后,去查一下本地数据库,看看那笔订单/扣款有没有落库。
-
根据结果答复:
-
如果数据库里显示扣款成功了,A 告诉 MQ:“提交(Commit)”。
-
如果数据库里没这笔账,A 告诉 MQ:“回滚(Rollback)”。
-
-
MQ 执行后续动作:根据 A 的答复,决定是让 B 服务去消费,还是直接丢弃这条消息。
更多推荐
所有评论(0)