因为调用方为了保证消息的发送是高可用的,因此会有重试机制。假若有这个场景:
服务A调用服务B,此时第一个请求,因为网络缘由,服务B延迟收到了这个请求,或者服务B回复服务A的时候,服务A没收到,致使服务A又发送了相同的请求。此时,服务B就又处理了一次请求,若是这个请求是对数据库进行操做的,好比对金额的扣减,那这麻烦可大了。
首先,咱们先看看接口是否须要幂等性。如下两个不须要保证幂等性:数据库
基本上对数据库的新增、修改、删除都须要幂等性。网络
新增的时候,惟一标识就是主键(分布式下的主键是怎么生成的?),因此尽管屡次插入,成功的只能一条数据,此时新增是幂等性的。若是此时主键是数据库生成的,那须要惟一索引避免插入重复数据,这个时候也是幂等性的。若是既须要数据库生成主键,也没有惟一索引,那这个幂等就没办法保证了。因此要保证新增的幂等,必须本身生成主键(推荐),或者建立惟一索引。并发
修改分为两种状况(这边只考虑请求重试,不考虑并发的状况,并发在分布式锁中讨论),一个是直接赋值,一个是相对赋值。分布式
# 直接赋值 update table set num=5 where id=1; # 相对赋值 update table set num=num-1 id=1;
若是是直接赋值的,无论给num赋值多少次5,结果仍是5,那若是是相对赋值的,此时就会一直减1。此时应该先从数据库查询出num,获得结果为5,服务A计算num-1,再把结果4传给服务B,服务B无论执行多少次set num=4都同样,这样就是幂等的。spa
删除也分两种状况,一个是指定值删除,一个是范围值删除。3d
# 直接赋值 delete from table where id=1; # 相对赋值 delete from table order by id desc limit 3;
若是是指定值删除,第一次删除返回1,第二次删除返回0,无论执行几回,数据库都没有id=1的信息,因此是幂等的。
若是是范围值删除,第一次执行删除3个,第二次执行又删除3个,这样就不是幂等的。方法跟上面相似,先把须要删除的id查询出来,获得10,9,8,而后把须要删除的id(10,9,8)传给服务B,服务B无论删除几回id(10,9,8),数据库都没有id(10,9,8)的信息,也没有额外多删除其余的信息,因此是幂等的。code