业务
电商零碎三大黄金链路为:洽购、购物、退货流程。每一个流程都关涉了大量的分布式服务之间调用,其中最简单外围的就是购物流程,以下是一个简略的模仿业务:
技术
1. 散布式微服务调用
2. 分布式事务
2.1 分布式事务常见计划:
(1) XA 分布式事务: 单零碎多数据库
(2) TCC 分布式事务: 服务链式调用、解决大多数分布式事务场景,次要用于同步实时后果返回场景。 留神:对于 bytetcc 简化版本次要针对于一个接口状况, 简化版本通过不同注解代表的不同办法表明 confirm、cancel、try,针对于多个接口都须要满足 tcc 事务的话, 须要应用非简化版本的 tcc, 非简化版本应用不同的类实例实现的同一接口办法示意不同的 conform、cancel、try。
(3) 可靠消息最终一致性: 多用于耗时、异步 并且音讯必须执行胜利的场景
(4) 最大致力告诉计划: 多用于耗时、异步 并且音讯可有可无的场景;比方:短信,
分布式事务混合应用留神:在很多业务场景下,咱们的分布式事务可能是多个计划一起应用,须要将多个计划的代码拆散,防止各种计划事务烦扰。能够将接口调用拆分成多个接口。
2.2 分布式事务使用
创立订单场景(锁定库存)
(1) tcc 分布式事务: 订单的创立 (订单创立次要是: 库存核心、调度核心、wms 核心锁定库存; 可销售库存减 1、锁定库存 +1) 中订单核心跟库存核心之间须要实时同步执行 (对应上图 5.1-5.5); 订单核心出错,库存核心不能执行;订单核心胜利,库存核心出错, 库存核心本地事务回滚, 同时告诉订单核心之前操作进行 cancel。当两核心都胜利时候,才发送音讯到 MQ,告诉调度核心、WMS 核心异步进行库存锁定、出库调度。
(2)可靠消息最终一致性分布式事务: 订单创立后告诉调度核心、wms 核心出库调度和库存锁定(对应上图 5.6-5.8) 应用可靠消息最终一致性计划,如果后面 TCC 分布式事务都执行胜利的话, 发送“待确认”音讯给可靠消息服务; 可靠消息服务投递音讯到 MQ, 调度核心生产音讯直至胜利。
1、先执行第一步创立订单,第一步执行胜利后再执行第二步: 异步化锁定库存, 出库调度。库存核心会发消息给可靠消息服务,可靠消息保障音讯肯定胜利生产以及胜利解决。
2、调度外呼接口服务在正确执行完步骤之后会告知可靠消息服务,而后可靠消息服务设置音讯状态为已实现。
3、调度核心跟 wms 核心应用 tcc 分布式应用,保障一起胜利 / 失败。
领取订单场景(扣减库存)
领取订单的入口,咱们从订单中核心更改订单中状态为已领取开始;更改订单状态跟库存核心扣减库存须要绑定 tcc。
剖析以上图咱们晓得:
1、领取订单胜利之后,告诉订单核心;订单核心更新状态, 订单核心调用库存核心扣减库存须要实时放弃事务一致性, 应用 tcc 分布式事务。如果这一步失败的话,前面所有的 货色都不要去执行。(订单核心批改订单状态和库存核心扣减库存同步保障一致性,一起胜利 / 失败 — 图:9.1-9.3)
2、如果 1 执行胜利的话,订单核心须要告诉库存核心投递音讯到可靠消息服务中去,而后基于可靠消息最终一致性计划实现,库存扣减跟销售出库。
订单核心能够间接告诉可靠消息服务: 调度出库;而后调度外呼服务收到之后去调用调度服务去调度出库,而后调度核心调用 wms 核心: 创立出库单。
3、如果 2 执行胜利之后,订单核心间接告诉可靠消息服务减少回来积分音讯,会员服务生产音讯,而后减少本地数据库积分(这个也是可靠消息最终一致性计划)。
步骤 3 也执行结束的话,订单核心音讯须要发送音讯,订单核心间接发送音讯到 mq, 而后最大致力告诉服务生产音讯,而后存储音讯到本地数据库,实现音讯的发送。
tcc 分布式事务总结
tcc 分布式事务的灵便利用是保障分布式事务简洁、高效条件;须要建设在对业务模块比拟很熟的教训之上。
1、bytetcc 简化模式跟非简化模式何时应用?
对于 bytetcc 简化版本次要针对于一个接口状况, 简化版本通过不同注解代表的不同办法表明 confirm、cancel、try,针对于多个接口都须要满足 tcc 事务的话, 须要应用非简化版本的 tcc, 非简化版本应用不同的类实例实现的同一接口办法示意不同的 conform、cancel、try。
2、业务中如何分辨 tcc 中的 try,confirm,cancel?
tcc 须要灵便应用,针对于同一个办法有前后两种状态的时候, 一个办法外面做 try,confirm,cancel 逻辑判断
如果针对于一个业务多个办法时候,tcc 的三步骤会贯通各个办法中(先执行的业务办法当作 try 来准备资源和 cancel 开释资源,对于后执行的业务办法当作 confirm 来确认资源), 针对于只有单个步骤的操作,咱们的 confirm 有时候可能间接省略;try 就是执行指标操作,cancel 就是撤销指标操作(比方会员积分更改)
针对于有转账场景:
转账有转账人,被转账人之分;指标后果就是 confirm 须要实现的后果;
try 阶段: 转账人扣减金额到锁定金额
confirm 阶段: 转账人锁定金额扣减增加到被转账人金额
cancel 阶段:cancel 是对资源开释, 对 try 的反向操作, 此时执行: 转账人金额从锁定金额变动到转账人金额。
电商中库存锁定场景:
在提交订单时候, 库存核心的库存会变动, 可销售库存缩小, 锁定库存减少, 最初执行 sql 更新操作。针对于这种业务场景, 指标后果业务是一步到位的, 所以咱们须要在这个办法外面进行 tcc 操作。
提交订单简化次要工作是: 可销售库存减、锁定库存加;所以 tcc 最初指标是锁定库存加;因为
try 阶段: 可销售库存减
cancel 阶段: 可销售库存加
confirm 阶段: 锁定库存加
/**
* 更新销售库存:* try 阶段:销售存库减 * cancel 阶段:销售库存加 * @throws Exception
*/@Override
protected void updateSaleStockNum() throws Exception {
// 订单的每一个商品的可销售库存减 1
for (商品 do: 商品列表) {System.out.println("执行 try 操作:"+tccType);
do.setSaleStockNum(do.getSaleStockNum()- 购买数量);
}else if(TCCType.CANCEL.equals(tccType)){System.out.println("执行 cancel 操 作:"+tccType);
do.setSaleStockNum(do.getSaleStockNum()+ 购买数量);
}
}
}
/**
* 更新锁定库存:* confirm 锁定库存加 1 * @throws Exception
*/@Override
protected void updateLockedNum() throws Exception {
// 更新锁定库存
for (商品 do: 商品列表) {if(TCCType.CONFIRM.equals(tccType)){System.out.println("执行 confirm 操作:"+tccType);
do.setLockedStockNum(do.getSaleStockNum()+ 购买数量);
}
}
}
领取订单:
领取核心领取结束之后告诉订单核心发动领取实现告诉, 订单核心会同步通过 tcc 告诉库存核心扣减库存: 指标锁定库存减、已销售库存加。所以咱们把指标的第一步当作 tcc 的 try 阶段,confirm 阶段在第二步。
@Override
protected void updateLockedStockNum() throws Exception {for (商品 do: 商品列表) {if(TCCType.TRY.equals(tccType)){do.setLockedStockNum(goodsStockDO.getLockedStockNum()- 购买数量);
}else if(TCCType.CANCEL.equals(tccType)){do.setLockedStockNum(do.getLockedStockNum()+ 购买数量);
}
}
}
@Override
protected void updateSaledStockNum() throws Exception {for(商品 do: 商品列表){if(TCCType.CONFIRM.equals(tccType)){do.setSaledStockNum(do.getSaledStockNum()+ 购买数量);
}
}
}
会员中心:
在购物流程中, 订单领取时候,订单核心更改订单状态、库存核心更改库存、会员中心减少会员积分咱们当成一个 tcc 分布式事务。会员中的两个操作更新积分和撤销积分曾经对外提供接口,所以咱们间接能够在 tcc 的 controller 内部调用。
@RestController
@Compensable(interfaceClass = MembershipApi.class,simplified = true)
public class MembershipTccService implements MembershipTccApi {
/**
* 告诉会员中心,“领取订单”事件产生了 * @param userAccountId 用户账号 id
* @param totalOrderAmount 订单总金额
* @return 处理结果
*/ @Override
@Transactional public Boolean payOrder(@PathVariable("userAccountId") Long userAccountId,
@RequestParam("totalOrderAmount") Double totalOrderAmount) throws Exception{membershipExecutor.do(userAccountId,totalOrderAmount);
return true; }
@CompensableConfirm
@Transactional public Boolean confirmPayOrder(@PathVariable("userAccountId") Long userAccountId,
@RequestParam("totalOrderAmount") Double totalOrderAmount) throws Exception{return true;}
@CompensableCancel
@Transactional public Boolean cancelPayOrder(@PathVariable("userAccountId") Long userAccountId,
@RequestParam("totalOrderAmount") Double totalOrderAmount) throws Exception{membershipExecutor.undo(userAccountId,totalOrderAmount);
return true; }
}
2. 分布式幂等性
购物流程次要蕴含两个子流程:1、创立订单 order 流程(锁定库存) 2、领取订单(扣减库存, 销售出库)