理解幂等技术,其实就是这么简单
Posted 技讯
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了理解幂等技术,其实就是这么简单相关的知识,希望对你有一定的参考价值。
幂等(idempotent)是一个数学与计算机学概念,常见于抽象代数中。
在编程中,一个幂等操作的特点是,其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。幂等函数可以改变系统的状态。例如,setTrue()就是一个幂等函数,因为无论执行多少次,其结果都是一样的。
幂等的场景有很多,例如:
前端重复提交选中的数据,后台只产生对应这个数据的一个反应结果;
我们发起一笔付款请求,应该只扣用户账户一次钱,当遇到网络重发或系统bug重发,也应该只扣一次钱;
发送消息,也应该只发一次,同样的短信发给用户,用户会崩溃;
创建业务订单,一次业务请求只能创建一个,创建多个就会出大问题。
幂等的技术手段
幂等并不是并发场景下的特有问题。幂等处理的是多次执行的问题,而并发仅仅是多次执行的一种形式。不管是依次执行,还是并发执行,都需要做好幂等。有些技术人员将解决并发问题的技术手段,例如悲观锁、乐观锁和分布式锁,当成幂等的技术手段,这是不对的。
再次强调,幂等的核心是确保唯一性。
唯一索引
在数据库中建立唯一索引,用作幂等记录,可以防止插入重复的数据。 在幂等函数中,先执行一次查询操作,如存在幂等记录则返回第一次执行的结果,如不存在幂等记录则继续执行。在并发场景下,可能存在多个线程同时插入幂等记录,这时候唯一索引可以确保只有一个线程插入成功,其它线程抛出异常。
除了插入幂等记录,应该还要插入其它的业务数据,这个时候务必使用事务。在实际工作中,幂等记录与事务经常同时出现,如影相随。
唯一数据
使用redis、memcache和zookeeper都可以实现唯一数据,这里仅用redis的SETNX举例。笔者从redis的官方文档摘抄了SETNX的用法,如下所示。
SETNX key value 将 key 的值设为 value ,当且仅当 key 不存在。 若给定的 key 已经存在,则 SETNX 不做任何动作。 SETNX 是『SET if Not eXists』(如果不存在,则 SET)的简写。 可用版本: >= 1.0.0 时间复杂度: O(1) 返回值: 设置成功,返回 1 。 设置失败,返回 0 。复制代码
在幂等函数中,将唯一标识作为key,任取value,调用SETNX。如果返回1,说明当前是第一次执行,继续执行幂等函数;如果返回0,取出第一次执行的结果并返回给调用方。在并发场景下,可能因尚未完成第一次执行而取不到结果,这时候可以稍作等待。
除了redis、memcache和zookeeper,还有其它手段可以实现唯一数据,读者可自行探索。只要可以实现唯一数据,就可以用来做幂等。
状态机约束
在单据相关的业务,或者是任务相关的业务,基本会涉及到状态机。业务单据上面有个状态,这个状态根据一个有限状态机进行跳转。如果状态机已经处于下一个状态,这时候是不能往回跳转到上一个状态的。通过状态机的跳转约束,可以做到有限状态机的幂等。
幂等的场景
幂等经常与事务同时出现,而事务适合小任务场景、不适合大任务场景,因此笔者将幂等场景分为以下两类进行介绍。为了方便描述,我们假设bizId可以唯一标识一笔业务。
小任务场景
这个场景的处理方式很简单,可以追求强一致性。在幂等函数中,先判断幂等记录是否存在。如果存在,直接返回;如果不存在,开启一个事务。在事务中,采用任务名+bizId作为幂等组合字段,插入幂等记录和业务数据。它的流程图如下。
大任务场景
在大任务场景下,需要将大任务拆成多个小任务分别执行。在每个小任务中,都可以有事务。但是,没有事务保证所有的小任务同时成功。因此,存在部分成功的场景。针对部分成功的场景,可以利用重试机制做到最终一致性。重试机制意味着多次执行,回到了幂等问题。这里只介绍需要幂等的场景。如果同时存在需要幂等和不需要幂等的场景,请加入一个判断标。
同步执行小任务
同步执行小任务的流程图如下。各小任务依次执行,中间的小任务不返回结果,仅在最后一个小任务或之后返回结果。
异步执行小任务
异步执行小任务的流程图如下。各小任务单独执行,互相不感知,也没有地方返回结果。
幂等字段
不管是同步执行小任务,还是异步执行小任务,都需要为每个小任务设置一个幂等字段或幂等组合字段。笔者推荐采用小任务名+bizId作为幂等组合字段。一方面,bizId可以标识这一批小任务属于同一笔业务;另一方便,小任务名可以区分不同的小任务。
以上是关于理解幂等技术,其实就是这么简单的主要内容,如果未能解决你的问题,请参考以下文章