相信很多人都听说过“幂等”这个词,什么是幂等?百度得到诸如一下的解释:
一次和多次请求某一个资源 对于资源本身应该具有同样的结果
就是针对一个操作,不管做多少次,产生效果或返回的结果都是一样的
看完有一种似懂非懂的感觉?继续google一番,得到如下结果:
“幂等”最早应该是用于描述http协议中的put请求方法,它指出:
put请求具有幂等的属性,一个幂等方法意味着, 对该方法的多次相同的调用,不会影响其一次成功调用造成的结果。put适用于更新资源的属性,只要请求更新的内容不变,多次调用的结果与一次成功调用造成的结果相同(实体的某个属性变成了b)
post请求不具备幂等的属性,post适用于创建一个资源,或者处理请求体中的数据,具有比较广泛的语义
幂等的这种特性是很有用的,我们经常对需要网络调用的接口存在这样的诉求:对于下游,在响应丢失或者请求重发时,即使用了相同的请求重新请求一次,结果还是与只请求一次相同,不用担心对上游造成其他影响/副作用(side-effects)。
一个单纯修改资源属性的PUT方法,天然就具有幂等的特性,这很容易达到。但现实中的接口,大多是意图复杂的“post”接口,这些接口能不能也改造成具有幂等的属性呢?显然是可以的,只是可能在改造之后,接口的语义也会发生改变。
我们逐个比较幂等描述中的三个关键点:相同的调用、相同的响应、副作用(side-effects)在PUT接口中、与在我们的接口时有什么区别,如何在我们的接口中实现这三个特性。
- 相同的调用
对于PUT的语义,请求的全部信息相同被判断为相同的调用。那么对于我们的复杂接口,是否也必须“请求的全部信息相同”才能判断为相同的调用呢?应该说,前者只是一个充分条件。是否是相同的调用,可以由接口双方来约定,我们可以约定请求的部分信息作为一个幂等键(Idempotency key),幂等键相同则判断为相同的调用。
- 相同的响应
如同PUT在相同的调用中的表现,PUT对于相同调用的相同响应也是“完全相同”的,但我们在实现接口的幂等性时,不必要是“完全相同”的,但至少需要格式上是相同的,这样下游可以很方便地用同样的方式进行解析,也属于幂等的部分意义。
- 副作用(side-effects)
"不产生副作用"是幂等的意义所在,副作用即超出调用者调用接口意图的作用。调用者在调用一个发送手机短信接口时,是希望发送一条短信,重复调用时,如果这是一个幂等的短信接口,那么因为重复调用而产生的另一条短信码即是一种副作用。"不产生副作用"也可以换一种说法“对于一个幂等接口,使用相同的请求信息,调用一次与调用无数次的结果相同”
如何在我们的接口中实现这三个特性
在google中,找到美团的和airbnb的幂等解决方案,经过一番的比较,个人比较喜欢airbnb的解决方案,对幂等实现的步骤比较容易理解,同时总结出接口幂等实现的一个基本流程框架:
幂等实现 | ProcessOn免费在线作图,在线流程图,在线思维导图 |www.processon.com![eadedb322152aaa2308793529f9c08ac.png](https://i-blog.csdnimg.cn/blog_migrate/898e8f5cdb5f3c8ff3286aa42f9d1006.jpeg)
对这个流程进行一些细化,即考虑避免并发导致的这个流程中的竞态条件,为这个流程加入一些互斥性保障:
幂等实现基本流程之二 | ProcessOn免费在线作图,在线流程图,在线思维导图 |www.processon.com![eadedb322152aaa2308793529f9c08ac.png](https://i-blog.csdnimg.cn/blog_migrate/898e8f5cdb5f3c8ff3286aa42f9d1006.jpeg)
锁住幂等键的实现有多种:数据库行级锁、分布式锁(zookeeper、redis),考虑并发这种比较短暂的场景,这里假设使用分布式锁,锁住幂等键一段时间即可。继续对这个流程进行细化,考虑流程中每一步失败(尤其涉及网络的步骤)时,是否会导致错误,这里标记出失败时可能导致的错误
幂等实现基本流程之三 | ProcessOn免费在线作图,在线流程图,在线思维导图 |www.processon.com![eadedb322152aaa2308793529f9c08ac.png](https://i-blog.csdnimg.cn/blog_migrate/898e8f5cdb5f3c8ff3286aa42f9d1006.jpeg)