微服务架构下基于Saga模式实现霸王餐长事务的最终一致性 微服务架构下基于Saga模式实现霸王餐长事务的最终一致性在高并发的外卖霸王餐业务场景中业务流程往往横跨多个服务且执行时间较长典型的“下单-返利-核销”流程就是一个典型的长事务。传统的两阶段提交2PC或Seata AT模式由于需要长时间持有数据库锁在此类场景下极易导致系统吞吐量下降甚至死锁。Saga模式作为一种长事务解决方案通过将大事务拆分为多个本地事务并配合补偿机制能够有效解决这一痛点。业务流程与Saga模式设计外卖霸王餐的核心业务流程涉及三个主要步骤订单服务 (Order Service)创建霸王餐订单状态为“待支付”。用户服务 (User Service)发放返利增加用户账户余额或积分。核销服务 (Write-off Service)在特定条件下如订单完成触发核销逻辑。这三个步骤构成一个Saga事务。如果其中任意一步失败都需要触发前面步骤的补偿操作。例如如果核销失败则需要回滚返利如果返利失败则需要取消订单。基于状态机的Saga实现Seata提供了基于状态机的Saga模式实现通过JSON文件定义业务流程和状态转换具有高灵活性和可维护性。以下是订单创建流程的状态机定义示例{Name:CreateOrderSaga,Comment:创建霸王餐订单的Saga流程,StartState:CreateOrder,Version:0.0.1,States:{CreateOrder:{Type:ServiceTask,ServiceName:orderService,ServiceMethod:createOrder,CompensateState:CancelOrder,Next:GiveRebate},GiveRebate:{Type:ServiceTask,ServiceName:userService,ServiceMethod:giveRebate,CompensateState:RefundRebate,Next:WriteOff},WriteOff:{Type:ServiceTask,ServiceName:writeOffService,ServiceMethod:writeOff,Next:End},CancelOrder:{Type:ServiceTask,ServiceName:orderService,ServiceMethod:cancelOrder},RefundRebate:{Type:ServiceTask,ServiceName:userService,ServiceMethod:refundRebate}}}服务实现与异常处理在Java代码中我们需要实现上述状态机定义的服务方法。每个服务方法应只关注自身的业务逻辑并在失败时抛出异常由Seata框架触发相应的补偿状态。首先订单服务负责创建订单。如果创建失败直接抛出异常Saga流程终止。packagecom.jumei.bdb.order.service;importcom.jumei.bdb.order.dao.OrderDao;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;/** * 订单服务实现 * author baodanbao.com.cn */ServicepublicclassOrderServiceImpl{AutowiredprivateOrderDaoorderDao;/** * 创建订单供Saga状态机调用 * param orderId 订单ID * param userId 用户ID * param itemId 商品ID * throws Exception 创建失败时抛出异常 */publicvoidcreateOrder(StringorderId,LonguserId,LongitemId)throwsException{booleansuccessorderDao.createOrder(orderId,userId,itemId);if(!success){thrownewException(订单创建失败业务ID: orderId);}}/** * 取消订单作为createOrder的补偿方法 * param orderId 订单ID */publicvoidcancelOrder(StringorderId){// 执行取消订单逻辑如更新订单状态为“已取消”orderDao.updateOrderStatus(orderId,CANCELLED);}}用户服务负责发放返利。如果返利发放失败框架会自动调用refundRebate方法进行补偿。packagecom.jumei.bdb.user.service;importcom.jumei.bdb.user.dao.UserAccountDao;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importjava.math.BigDecimal;/** * 用户服务实现 * author baodanbao.com.cn */ServicepublicclassUserServiceImpl{AutowiredprivateUserAccountDaouserAccountDao;/** * 发放返利 * param userId 用户ID * param amount 返利金额 * throws Exception 发放失败时抛出异常 */publicvoidgiveRebate(LonguserId,BigDecimalamount)throwsException{booleansuccessuserAccountDao.addRebate(userId,amount);if(!success){thrownewException(返利发放失败用户ID: userId);}}/** * 退款返利作为giveRebate的补偿方法 * param userId 用户ID * param amount 返利金额 */publicvoidrefundRebate(LonguserId,BigDecimalamount){// 执行退款逻辑如扣除用户余额记录退款流水userAccountDao.deductRebate(userId,amount);}}核销服务作为流程的最后一步如果执行失败将触发前面所有步骤的回滚。packagecom.jumei.bdb.writeoff.service;importorg.springframework.stereotype.Service;/** * 核销服务实现 * author baodanbao.com.cn */ServicepublicclassWriteOffServiceImpl{/** * 执行核销逻辑 * param orderId 订单ID * throws Exception 核销失败时抛出异常 */publicvoidwriteOff(StringorderId)throwsException{// 模拟核销业务逻辑booleansuccessperformWriteOff(orderId);if(!success){thrownewException(核销失败订单ID: orderId);}}privatebooleanperformWriteOff(StringorderId){// 具体的核销实现returntrue;}}幂等性与持久化Saga模式下补偿操作可能会被重复执行例如网络超时导致的重试因此所有业务操作和补偿操作都必须是幂等的。在数据库设计层面应利用唯一索引或状态字段来防止重复操作。例如在插入返利流水时使用全局事务IDXID或业务唯一键作为唯一索引确保同一流水不会被重复插入。此外Saga状态机的执行状态需要被持久化Seata Server会负责存储和恢复状态机实例确保在系统崩溃后能够恢复并继续执行。本文著作权归 俱美开放平台 转载请注明出处

相关新闻

最新新闻

AREX流量录制回放测试:从原理到实战,构建自动化回归防线

AREX流量录制回放测试:从原理到实战,构建自动化回归防线

1. 项目概述:从“救火”到“预防”的测试革命如果你是一名后端开发或者测试工程师,一定经历过这样的深夜:线上一个看似无关紧要的配置变更,却引发了核心交易链路的大面积报错。整个团队被紧急拉起来,在昏暗的屏幕前&am…

2026/8/26 21:41:54
三维装箱问题:从数学建模到算法实现与优化

三维装箱问题:从数学建模到算法实现与优化

1. 项目概述:从“装东西”到“算最优”三维装箱问题,听起来挺学术,但说白了,就是怎么把一堆大小、形状、重量各异的箱子,最有效率地塞进一个更大的容器里。这个“容器”可以是集装箱、卡车车厢、飞机货舱,甚…

2026/8/26 21:41:54
Android三方APK通过Socket实现高权限Shell命令执行方案详解

Android三方APK通过Socket实现高权限Shell命令执行方案详解

1. 项目概述:当APK需要执行Shell命令时 在Android应用开发中,尤其是涉及系统管理、自动化测试、深度定制或设备管理(MDM)等场景时,我们常常会遇到一个核心需求:让一个普通的第三方APK能够安全、可控地执行系…

2026/8/26 21:41:54
AREX流量录制回放:原理、部署与实战,解决线上偶现Bug难题

AREX流量录制回放:原理、部署与实战,解决线上偶现Bug难题

1. 项目概述:AREX是什么,以及它为何值得关注如果你是一名后端开发或者测试工程师,一定对线上问题排查的“玄学”时刻深有体会:用户反馈了一个偶现的Bug,你翻遍了日志,却发现事发时段的日志要么语焉不详&…

2026/8/26 21:41:54
STM32标准库工程模板搭建指南:从零构建Keil MDK开发环境

STM32标准库工程模板搭建指南:从零构建Keil MDK开发环境

1. 从零开始:为什么需要一个“标准”的工程模板?如果你刚开始接触STM32,或者刚从Arduino、51单片机转过来,第一个拦路虎往往不是写代码,而是“搭环境”。面对Keil MDK里空荡荡的界面,新建一个工程后&#x…

2026/8/26 21:41:54
PSoC电感感应实战:用普通MCU实现非接触金属检测与位置传感

PSoC电感感应实战:用普通MCU实现非接触金属检测与位置传感

前阵子做一个小项目,要在设备里加一个非接触式金属检测功能:金属块靠近时把设备从低功耗状态唤醒。当时第一反应是去找专用的电感数字转换芯片,算了下成本、面积和通道数,觉得不划算,就决定试试用PSoC 4 MCU直接做电感…

2026/8/26 21:36:54