文章

数据一致性方案设计


B2B电商订单下单场景为例,流程做一定的简化,然后梳理与多个外部系统交互可能带来数据一致性问题的场景,通过最终一致性架构设计给出轻量级解决方案,并梳理出设计要点。

01 前言

对于软件开发来说,绕不开与外围系统的对接,因网络、系统、代码设计等多种不稳定因素,经常出现各种异常情况,结果带来的是系统的不稳定和数据的不一致,在生产环境上,出现类似情况,经常要加班加点人工进行修正处理,是一件非常痛苦的事情。

那么在与外围系统对接过程中,异常避免不了的情况下,我们如何通过前期的设计来减少数据的不一致,本文从最小的成本保证数据一致性的角度来进行架构设计,网上还有很多其他方法,大家按需进行选择!

02 数据一致性场景

用户在商城选购好商品后,进行订单下单流程:

系统

数据对象

业务场景

是否阻塞主流程

单据系统

业务单据

订单下单(主流程)

库存系统(外部)

库存

消耗库存

优惠券系统(外部)

优惠券

核销优惠券

会员系统(外部)

会员权益

消耗会员权益

财务结算系统(外部)

订单结算

发起销售订单结算

单据系统

消息对象

发送短信、邮件

正向流程:

生成订单,同时消耗库存、核销优惠券、使用会员权益、异步发送结算请求、异步发送通知消息。

逆向流程:

业务代码逻辑异常或外部系统调用失败,本地事务回滚,异步定时器回滚库存、优惠券、会员权益;若回滚失败,定时器重试。

03 数据一致性设计

image-20240728102611823

设计要点:

  1. 前端用户下单做好防抖处理,后端做好分布式锁,防止同一时间产生多个相同的订单

  2. 前端用户可以在下单失败时,可以通过前端 UI 界面再次发起进行前台重试

  3. 后端外部系统调用,如果使用 FeignClient,配置FeignClient 重试时,不要进行一刀切的进行重试,按需进行配置,不一定外部系统都做好了幂等,同时做好重试次数约定

  4. 和外部系统约定好幂等 key,标记是否是同一次请求,外部系统接收多次相同请求时,返回正常处理结果

  5. 可能大部分系统只是提供接口状态查询,不支持幂等,需要调用方先查询,判断是否需要再次重试

  6. 分析业务系统对于外部系统调用,是否阻塞主流程数据一致性业务是否强要求

  7. 外部系统的调用应放在代码逻辑执行的最后,因为远程调用是非常不稳定的,可能因网络抖动、服务异常、代码异常等因素导致调用失败

  8. 可异步但是数据一致性非常重要的,比如:财务结算,可以直接插入一条任务数据到任务表,异步执行但是通过定时器保证数据的最终一致性

  9. 可异步但是数据一致性要求不高,比如:发送短信通知等,可在事务提交 After Commit 之后,启动一个异步线程去执行

  10. 如果涉及一个业务逻辑涉及调用多个同步调用的外部系统,优先将容易出错的放在前面调用,防止总是出现正常调用成功的系统要进行数据的回滚,或者人工处理保证整个流程成功

  11. 同步调用的外部系统逻辑,如果出现异常报错,重新启动一个事务,将任务数据进行保存,用于回滚其他调用外部系统成功的数据

  12. 启动一个定时器,补偿本地事务失败带来的数据一致性问题

04 附录

核心代码逻辑:

image-20240728104533690

CAP 理论:

image-20240728104917617

BASE 理论:

image-20240728104941297

分布式事务分类:

image-20240728105046292

半消息机制最终一致性:

image-20240728105300703

License:  CC BY 4.0