Valentine 转载请标明出处。
在我们现在的分布式架构里面,大部分的架构都是属于SOA化和微服务化,即一个系统是由多个子模块或者多个子系统组成的。那么这就会存在各个子系统相互调用的场景。这个调用无非是利用RPC去进行通信,那通信就会存在一些问题,这个问题在我们以前集中式的架构,单一进程里面不会出现的,在单一进程里面我们完成一个方法的调用只存在两种状态,一种是成功一种是失败;
但是在分布式架构里面,因为涉及到远程通信,它就会涉及到第三种状态,就是未知状态,未知状态可能表示超时、网络延迟、数据包丢失等等。那么这个数据的未知状态会导致我们调用端对这个结果是未知的,如果在这个未知的场景下,调用端或客户端再次重试去发起请求,也许这个请求对于服务端来说收到并且已经处理了,但是客户端不知道,所以它再次尝试发送多一次请求,那服务端就会收到两次请求,如果服务器端不做处理的话就会导致数据做了两次累加或者两次更新,这样就会发生非常大的影响。
比如支付场景:如果用户对同一个订单发起两次支付操作,那么这个时候服务端不去做相应的处理的话,它就会完成两笔扣款记录,那么这个地方就会造成用户的资金损失,这种情况是绝对不允许在互联网产品上出现的。
还有绝大部分消息中间件都可能存在消息发送多次的情况,那怎么保证在消息多发的情况下(基于broker发送到消费者)的数据安全性,这也是我们必须要解决的场景。
幂等性就是用来解决这样的场景的,幂等性简单来说就是用户对同一个操作发起多次请求以后,对于数据的影响的结果是不变的,一次请求跟N次请求的结果是一样的。
在这里我简单地说说两种方式的解决方案:
1、可以使用数据库的唯一约束,对某一个关键的数据设置一个唯一索引,第二次请求过来的时候它没有办法正常入库,这时会抛出一个重复的异常,服务端可以捕获到这个异常,然后不作处理;
2、状态机幂等,状态机实际上在很多开源中间件、软件里面都有提到和涉及到。那么什么是状态机呢?它是一种特殊的组织代码,它能够确保你的对象随时都知道自己所处的状态以及可以在这个状态下做出相应的可以做的事情。简单来说就是对于一个数据会存在一个不同的状态,而且这个状态是可变的。下面一个例子:
发起支付的时候这个状态是支付中,后面有已支付和支付失败,状态随着业务的驱动而变化,那它是怎么实现幂等的呢?
如果请求的是修改操作,那么 update xxxx where status = 1,这就是说只有这个状态等于1的情况下才能修改,也说明当前的修改操作是因为某一场景才触发的,比如说原来的等待支付变成支付中,意味着这个支付中的状态必须是在等待支付的状态下才能去修改的,它的前置条件就是等待支付,这个就是使用状态机的方式去实现幂等。