一、保证事务一致性的3种模式:
1.可靠事件模式:
a.适合场景:微服务A完成某个业务时,需要触发微服务B、微服务C、微服务D、微服务E...。因为链路比较长,直接调用各个服务的接口时,如果当中某个服D务因为一些原因,没有收到调用会导致整个要完成的业务受到影响。如果这个服务D是个不需要回应服务A的,且不对后续其他服务执行产生影响的变更数据服务。那么可以将这个服务的调用改为由服务A发送消息事件到消息中心,服务D通过消费消息中心里对应的消息,完成自己的业务。这样可以避免因为服务D的异常,导致回滚整个链路里其他服务的所有数据。
b.实际用例:直播平台里用户给主播送一种系统限量礼物,送完后需要同步在统计中心服务记录这条数据。这中间需要触发的服务暂定为:用户中心(用于判断余额是否足够赠送指定礼物)、礼物中心(用于决定礼物仓库库存是否足够本次业务赠送)、主播中心(用于主播类型用户的升级业务集合,负责接受此次的礼物赠送)、统计中心(用于记录本次赠送礼物的动作)。
那么,可以发现在这个业务链路中,只要用户的余额和限量礼物库存足够,就可以完成这次赠送。主播中心和统计中心的业务处理,不需要回应这次礼物赠送业务。但是,如果主播中心和统计中心不能完成自己的业务,又会导致主播的损失,并且对系统统计数据分析造成影响。
因为上述情况,所以可以将主播中心和统计中心的业务触发,改为在用户中心和礼物中心符合赠送条件后,直接向消息中心发送一个赠送礼物事件消息。后续主播中心和统计中心,通过约定的消息条件获取需要处理的消息并进行消费。
2.业务补偿模式(略过,TCC模式重叠比较大):
3.TCC模式:
a.适合场景:TCC模式是try、comfirm、cancel三个操作的简写。同样微服务A完成某个业务时,需要触发微服务B、微服务C、微服务D、微服务E...。不同的是在这个业务链路中,如果整个链路不能正常完成,微服务D需要回滚数据到业务未进行的状态。此时,在链路中直接去控制微服务D回滚是一个比较麻烦的事情,而且也破坏了微服务之间解耦的初衷。那么最好的处理方式便是调整微服务D在这个业务中提供的处理接口,将原本的可能一个接口处理微服务D关联的所有业务,进行分割。分割原则便是TCC,在try接口里负责尝试拿到完成微服务A这个业务需要的资源,并记录这个资源消耗信息。在comfirm接口里则负责处理原本微服务D资源消耗成功的情况下,微服务D本身需要处理的关联业务。在cancel接口里则负责处理将try接口消耗的资源补偿回去。这样下,即便业务链路没有全部完成,针对微服务D的补偿操作,也更容易执行。此处,try接口调用异常(响应网络状态不对,如微服务D的网络抖动不可用)时,可以和重试机制处理配合。在comfirm和cancel阶段,响应状态不对时(微服务D的网络间歇不可用)则可以考虑和发送事件消息结合。
b.实际用例:还是上面的例子,直播平台里用户给主播送一种系统限量礼物。但是在调用用户中心里判断用户余额足够赠送并且将用户余额相应扣除后,调用礼物中心却发现限量礼物库存不够,这时候就需要将用户中心里刚扣除的余额数据补偿回去。
因为上述情况,所以可以将用户中心里的用户余额操作按TCC原则进行分割。链路触发时调用用户中心余额操作的try接口,在try接口里只做扣除相应余额并记录扣除的操作信息(操作Id,数值等),不处理关联的用户账单变化及其他可能的关联业务。在comfirm接口里则处理,整个链路如果都可以完成时,用户中心关联的其他业务处理。在cancel接口里则负责将try接口里扣除的余额补偿回去。
这样,整个链路开始时调用用户中心提供的try接口,尝试扣除资源,发现足够。再调用礼物中心try接口,发现不够时,礼物中心直接返回不够的信息。接到礼物中心的反馈后,就可以调用用户中心的cancel接口进行补偿操作。礼物中心反馈足够时,则调用用户中心的comfirm接口处理关联业务。然后调用礼物中心的comfirm接口,同样处理礼物中心关联的业务。
备注:外服务接口是否取用TCC模式,主要还是在于该接口业务实际情况。如果微服务提供的接口业务有更新数据的操作,且需要在外部关联业务出现异常时回滚之前的数据更新,那么开启TCC模式比较好。像上面的主播中心实际上也可以改成TCC模式,只是在第一种场景下,整个业务链只要用户余额和限量礼物余额足够就可以完成这个业务核心,如果够发消息事件通知下游业务处理。如果不够,则不会触发下游业务,也不存在补偿。