什么是幂等性?

  • 幂等性:就是用户对于同一操作发起的一次请求或者多次请求结果是一致的,不会因为多次点击而产生了副作用。
  • 在增删改查4个操作中,尤为注意就是增加或者修改,查询对于结果是不会有改变的,删除只会进行一次,用户多次点击产生的结果一样,修改在大多场景下结果一样,增加在重复提交的场景下会出现。

解决幂等性的方案有:

1. mysql中设置业务ID,并设置为主键,且唯一
2. 使用redis或者zk的分布式锁

1. 什么是幂等性?

幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。
在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。例如,“setTrue()”函数就是一个幂等函数,无论多次执行,其结果都是一样的。

  • 在HTTP/1.1规范中的幂等性定义:
    Methods can also have the property of “idempotence” in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request.
    一次和多次请求某一个资源对于资源本身应该具有同样的结果(网络超时等问题除外)。也就是说,其任意多次执行对资源本身所产生的影响均与一次执行的影响相同。
    幂等不仅仅只是一次(或多次)请求对资源没有副作用(比如查询数据库操作,没有增删改,因此没有对数据库有任何影响)。
    幂等还包括第一次请求的时候对资源产生了副作用,但是以后的多次请求都不会再对资源产生副作用。
    幂等关注的是以后的多次请求是否对资源产生的副作用,而不关注结果。
    幂等性是系统服务对外一种承诺(而不是实现),承诺只要调用接口成功,外部多次调用对系统的影响是一致的。声明为幂等的服务会认为外部调用失败是常态,并且失败之后必然会有重试。

2.产生幂等性的场景

  • 幂等性问题在我们开发中,分布式、微服务架构中是随处可见的,因网络波动就可能重复请求。
  • 用户重复操作,用户在使用产品的时候可能无意多次点击,或者没有响应而导致多次下单或者交易。
  • 应用了超时或者失败重试机制。
  • 第三方平台的接口,因为异常导致多次异步回调
  • 中间件、应用服务根据自身特性,也有可能进行重试。
  • 用户双击提交按钮。 页面重复刷新
  • 使用浏览器后退按钮重复之前的操作,导致重复提交表单。等等。

3.如何解决幂等性

  • 唯一索引,防止新增脏数据。如新增用户数据,一般用户名是唯一的。所以会在用户名字段添加唯一索引

  • token机制,防止页面重复提交。
    分为两个阶段,获取token和使用token。每次接口请求前先获取一个token,然后再下次请求的时候在请求的header体中加上这个token,后台进行验证,如果验证通过删除token,下次请求再次判断token。

  • 悲观锁(并发高的话慎用) Synchronized(单机环境适用)/数据库悲观锁

  • 乐观锁 (可能循环时间长开销大) Lock(单机环境适用)/数据库乐观锁

  • 分布式锁(适用分布式系统)

  • ZooKeeper是一个为分布式应用提供一致性服务的开源组件,它内部是一个分层的文件系统目录树结构,规定同一个目录下只能有一个唯一文件名。基于ZooKeeper实现分布式锁的步骤如下:
    (1)创建一个目录mylock; (2)线程A想获取锁就在mylock目录下创建临时顺序节点;
    (3)获取mylock目录下所有的子节点,然后获取比自己小的兄弟节点,如果不存在,则说明当前线程顺序号最小,获得锁;
    (4)线程B获取所有节点,判断自己不是最小节点,设置监听比自己次小的节点;
    (5)线程A处理完,删除自己的节点,线程B监听到变更事件,判断自己是不是最小的节点,如果是则获得锁。
    这里推荐一个Apache的开源库Curator,它是一个ZooKeeper客户端,Curator提供的InterProcessMutex是分布式锁的实现,acquire方法用于获取锁,release方法用于释放锁。
    优点:具备高可用、可重入、阻塞锁特性,可解决失效死锁问题。 缺点:因为需要频繁的创建和删除节点,性能上不如Redis方式。

基于 Redis 实现分布式锁

使用 Redis 做分布式锁的思路大概是这样的:在 Redis 中设置一个值表示加了锁,然后释放锁的时候就把这个 Key 删除。
推荐一个redis官方推荐的redis锁的框架Redisson
原文链接

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐