业务设计原则--幂等设计


一 介绍

在传统的单体应用架构中,即同一个进程内,对于一个函数,或者一系列的函数调用,结果只有两种,要么成功,要么失败(我们可以通过事务的方式控制多个函数的事务调用)
但是在分布式架构系统中,服务与服务之间的调用通过网络远程RPC调用的时候,除了调用成功或者失败之外,还会出现第三个结果–超时,超时是分布式架构中,最为复杂的场景,

二 问题

我们以一个简单的示例为例,假设有一个商品促销,商品实际的库存数据总和存储在表t_goods中num字段上,现在有一个商品被购买,这个时候我们就需要通过一系列的操作,将商品表中的num数据减一。我们以商品发起扣款的服务为web,后端进行实际扣款的服务为service,中间的服务的调度为Dubbo
在这里插入图片描述
实际上,对于dubbo而言,当我们的web发起dubbo调用进行商品库存数据扣除的时候,如果调用超时,因为dubbo自身的重试机制,假设重试了3次,那么我们第4四步中的简单的数据t_goods 的num就会多次-1操作,这个显然是在分布式系统中不允许的,
这个时候,我们就需要对业务的逻辑处理进行幂等性设计

什么是幂等性

幂等性是分布式架构中对应业务涉及的一个基本原则,他的设计思路即用户对于同一个操作(这个也可以理解服务以服务之间的方法调用),发起的一次请求或者是多次请求的结果都是一致的,不会因为多次请求而产生对应的副作用

如何做幂等设计

显然,对应上面简单的商品库存容量的扣除,正是因为4的步骤不是幂等性,Dubbo调度服务的重试机制最终导致了多次的操作影响了商品的实际库存。
那么我们应该如何进行幂等设计呢?

应用程序的幂等操作

对于应用程序而言,我们还是以上面的例子为例,对于3,dubbo调用,我们在dubbo调用中,将2步骤中对于指定订单生成的orderId附带传递到service中,对应4的操作,我们首先要验证该orderId是否已经执行了商品数量扣除(日志记录),如果是,我们直接返回对应的扣除信息,如果不是,我们再执行对应的商品数扣除操作
在这里插入图片描述

通过状态机设计

涉及到资金交易的系统,通常会把交易流程分解成多个阶段,每一个阶段用不同的状态来标识。如在订单受理或初始化阶段,把订单状态设为0;开始付款时设为1,标识当前订单是处于付款中状态;支付完成后,根据实际的结果,将订单状态设为成功或者失败。
在这里插入图片描述
我们在以商品交易为准,对于订单支付的接口pay()接口实现的幂等伪代码:

//1.查询当前订单
select order_status from t_pay where order_id=#{orderId} and system_no='订单系统'
//2.1订单已经存在且状态为终态,则直接返回
if("2".equals(orderStatus)){
    return "成功";
}
if("3".equals(orderStatus)){
    return "失败";
}
//2.2订单已经存在且状态非终态
if("1".equals(orderStatus)){
    //查询下游系统or重试。
}
//2.3订单初始化
if("0".equals(orderStatus)){
    //不再入库,直接调用支付逻辑以及后续处理
}
//2.4订单不存在
if(null==orderStatus){
    //3.订单初始化入库,状态order_status=0
    insert into t_pay(order_id,order_status,account_id,amount,....) values(#{orderId},'0',#{accountId},#{amount},...)
    //3.1各种准备工作,如路由,记账等
    //3.2更新为付款中
    update t_pay set order_status='1' where order_id=#{orderId} and system_no='订单系统' and order_status='0'
    //4.调用支付
    status=doPay(accountId,amount);
    //4.1更新订单状态
    update t_pay set order_status=#{status} where order_id=#{orderId} and system_no='订单系统' and order_status='1'
    return status;
}
数据库方面的考虑

在实际生产的高并发、高复杂业务中,仅仅靠应用程序做幂等性设计是不足的。如在上例中的极限情况下,两笔相同的扣库存总数同时执行的时候,因为这个时候对应商品数量扣除记录中都不存在了当前orderId对应的扣除记录,所以这两笔还是能够同时进行扣除操作。
针对这种请求,我们可以分布式锁和数据库的唯一性索引进行约定。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值