稳定性三十六计-幂等设计

引子

群里发了一个总共1千元的拼手气红包,共10个。静儿点进去,额,抢到了0.05元。这个不甘心啊。退出来重新打开了这个红包,你猜怎样?显示我抢到了0.05元!

640?wx_fmt=png

这就是幂等(idempotence),不管多少次请求某一个资源,对资源都具有相同的影响。幂等性是系统的接口对外一种承诺,承诺只要调用接口成功,外部多次调用对系统只产生一次副作用。

 

为什么要幂等

世界上最遥远的距离是我终于鼓起勇气,对着马路对面的你大喊:“你愿意娶我吗?”我看到你面带灿烂的笑容,正回答的时候……一辆大卡车驶过,你的回答我没有听见。

因各种不可抗因素产生的没有收到响应,一个简单有效的方法就是重试。被重试的接口必须是幂等的。

幂等性是分布式系统设计中的一个重要概念,对超时处理、系统恢复等具有重要意义。

 

保证幂等的手段

保证幂等需要理清楚两件事情:幂等条件和期望结果。

大家可能听说过保证幂等的手段有token令牌、分布式锁、去重表、数据库唯一索引等。这些所谓的幂等手段实际上防重手段。防重本质是防止一个相同的请求被当成多个不同的请求来处理。幂等的条件是知道这是一个相同的请求。防重和幂等本质上是两个不同的阶段。

 

状态机幂等

在支付场景中,创建了一个支付订单,发起了一个支付请求,这个订单不论多少次重复请求,都应该保证最多只扣款一次。即

 
相同支付订单ID(幂等条件) —> 最多一次扣款(期望结果)

为了实现这个目标,可以考虑使用有限状态机。

有限状态机(Finite-state machine FSM),又称有限状态自动机,简称状态机,是表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型。用于处理复杂的状态转换。

在这个支付的例子中,为了化简,不考虑退款、取消订单等复杂的状态,只考虑未支付和已支付两种状态之间的转换。

640?wx_fmt=png

由上面的状态转换图可以看到,相同支付订单ID从未支付状态,要不就是支付不成功停留在未支付状态,要不就是支付成功,状态转移为已支付。此状态转移过程不可逆。

 

 
public enum OrderStateEnum {	
    UNPAID {	
        @Override	
        public OrderStateEnum changeState() {	
            if (doPay()) {	
                return PAID;	
            }	
            return UNPAID;	
        }	
    },	
    PAID {	
        @Override	
        public OrderStateEnum changeState() {	
            return PAID;	
        }	
    };	
    public abstract OrderStateEnum changeState();	
    public boolean doPay() {	
        //这里是逻辑伪代码,可以是发起下游调用请求支付通道等	
        return true;	
    }	
}

 

这是一个java版本的简单状态机实现。状态机里定义了一个未支付状态和其行为changeState。changeState又定义了一个未支付状态和其行为changeState。

利用状态机来实现这个幂等支付请求的设计流程图如下:

640?wx_fmt=png

参考状态机实现和上图可知,相同支付ID的请求,支付状态只能进行一次从未支付到已支付的转换。从而保证了其幂等性。

 

按目标幂等

先来回答一个小学生的问题:

定了一个会议,参加人数为10人。发现会议室的椅子只有5把。3个提前来到会议室的同学热心的去其他地方搬椅子进来。问:每人要搬几把椅子?

有人要说这不是把简单的问题复杂了吗?大家看到椅子不够就去搬,看够10把椅子了就不搬就可以了。对了,这其实是一个很好的解题思路,完全可以用在设计当中,就是按目标幂等。

 
相同会议ID(幂等条件) —> 总数10把椅子(期望结果)

利用按目标幂等来实现这个总数10把椅子请求的设计流程图如下:

640?wx_fmt=png

采用按目标的设计,相同会议ID,不管多少次请求,请求椅子的总数就是10把。多次请求不改变行为,从而实现了幂等。

 

总结

支持幂等是一个接口的基本素养

 

相关阅读

编写代码的「八荣八耻」- 以用户易用为荣,以复杂歧义为耻

稳定性「三十六计」实战和背后的逻辑

稳定性「三十六计」- 无状态化

 

关于作者

一线开发十二年,有日本东京和美国硅谷研发经验。有百余项技术发明专利,目前任美团点评技术专家。

技术公众号「编程一生」,公众号头像即为作者本人。

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值