浅谈幂等设计 | 京东云技术团队

1 幂等性

一句话,幂等就是一个执行操作,无论执行多少次,产生的效果和返回的结果都是一样的。

2 为什么要实现幂等性?

如今随着互联网技术快速发展,业务越来越复杂,系统的高并发和关键数据的场景越来越多。

在分布式系统中,机器宕机和消息丢失也是需要重点关注的问题,其中的一个典型就是幂等性问题。

想想看,一个对外暴露的接口会面领很多次请求,如果不能保证幂等性会带来什么样的后果?

微信进行一次扣款操作,应该只扣用户一次钱,当遇到网络故障或系统bug,如果没有实现幂等性扣多了你会不会直接"C语言"投诉?

当然,有些接口是天然保证幂等性的,比如查询操作、删除操作。有些对数据的修改是一个常量,无其他操作,也是具有幂等性的。修改操作可能幂等可能不幂等。

SELECT col1 FROM tab1 WHERE col2 = 2UPDATE tab1 SET col1 = 1 WHERE col2 = 2UPDATE tab1 SET col1 = col1 + 1 WHERE col2 = 2

这三个sql只有第三个不是幂等的。

POST请求天生就不是一个幂等操作,每次调用都会在系统中产生新的资源,想要幂等就必须在业务中实现。

需要避免的是,幂等性和并发安全不是一回事。当同一笔订单即使你不停的提交支付,如果扣了不止一次钱,就说明该操作不幂等。

而有多笔订单同时进行支付,最后扣除的金额不是这么多笔金额的总和,说明该操作有并发安全问题。这是两个维度的问题,应该分开讨论解决。

3 如何实现幂等性?

(1)数据库防重

利用数据表唯一索引的特性,当并发时新增报错时,再查询一次,数据已经存在,就避免了脏数据的新增。但注意,不要将uuid作为索引字段,其大小和类型对于索引而言都会导致速度非常慢。

常见的场景,比如博客/微博系统点赞,一个用户对一个微博点赞,就把用户id与该博文id绑定,后续该用户再对该博文点赞就无法插入。再比如金融账户,可以通过在账户表中增加唯一索引来存储用户id,即使重复操作一个用户也只能拥有一个账户。

(2)token令牌机制

token机制是适用范围最广泛的一种幂等设计。虽然实现方式有很多种,但核心思想就是每次操作都生成一个唯一token凭证,服务器通过这个唯一凭证确保同样的操作不会被执行多次。

具体可以分为两个阶段,获取token和使用token。每次接口请求前先获取一个token,然后在下次请求时在请求的header体中加上这个token,后端进行校验,如果验证通过则删除token,下次请求再次判断token。如果在redis缓存的帮助下,流程图如下:

(3)分布式锁

数据库防重表可以通过分布式锁代替,相比去重表,将放并发做到了缓存中,效率更高。局限性都是同一时间只能完成一次请求。

比如某些业务处理流程很长,要求不能并发执行,可以在流程执行之前根据某个标志(用户ID+后缀等)获取分布式锁,其他流程执行时获取锁就会失败,也就是同一时间该流程只能有一个能执行成功,执行完成后,释放分布式锁。

4 幂等的优缺点

优点:

业务需要

缺点:

(1)客户端处理逻辑得以简化,但服务端控制幂等逻辑变得更加复杂;

(2)把并发执行变成改为串行执行,降低了执行效率。

5 扩展

分布式自增ID可以借鉴Snowflake算法,优点是高性能、低延迟、按时间有序;缺点是需要独立的开发和部署。

其结构如下:

  • 最高位是符号位,始终为0,不可用。
  • 41位的时间序列,精确到毫秒级,41位的长度可以使用 (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69年。时间位还有一个很重要的作用是可以根据时间进行排序。注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截) 后得到的值,这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的。
  • 10位的机器标识,10位的长度最多支持部署1024个节点。
  • 12位的计数序列号,序列号即一系列的自增id,可以支持同一节点同一毫秒生成多个ID序号,12位的计数序列号支持每个节点每毫秒产生4096个ID序号。

加起来刚好64位,为一个Long型。这个算法很简洁,但依旧是一个很好的ID生成策略。

参考文献:

1\] 分布式系统互斥性与幂等性问题的分析与解决 [zhuanlan.zhihu.com/p/22820761](https://link.juejin.cn?target=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F22820761 "https://zhuanlan.zhihu.com/p/22820761") \[2\] 高并发下接口幂等性解决方案 [blog.csdn.net/u011635492/...](https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2Fu011635492%2Farticle%2Fdetails%2F81058153 "https://blog.csdn.net/u011635492/article/details/81058153") \[3\] 幂等性问题和解决方法 [blog.csdn.net/qq_32020035...](https://link.juejin.cn?target=https%3A%2F%2Fblog.csdn.net%2Fqq_32020035%2Farticle%2Fdetails%2F105448889 "https://blog.csdn.net/qq_32020035/article/details/105448889") \[4\] 雪花算法 [www.cnblogs.com/grasp/p/123...](https://link.juejin.cn?target=https%3A%2F%2Fwww.cnblogs.com%2Fgrasp%2Fp%2F12309726.html "https://www.cnblogs.com/grasp/p/12309726.html") \[5\] 聊聊开发中幂等问题 [segmentfault.com/a/119000001...](https://link.juejin.cn?target=https%3A%2F%2Fsegmentfault.com%2Fa%2F1190000018808510 "https://segmentfault.com/a/1190000018808510") > 作者:京东零售 李泽阳 > > 来源:京东云开发者社区 转载请注明来源

相关推荐
大气层煮月亮8 分钟前
Oracle EBS ERP开发——报表生成Excel标准模板设计
数据库·oracle·excel
云和数据.ChenGuang17 分钟前
达梦数据库的命名空间
数据库·oracle
三三木木七1 小时前
mysql拒绝连接
数据库·mysql
蹦跶的小羊羔1 小时前
sql数据库语法
数据库·sql
唐古乌梁海1 小时前
【mysql】InnoDB的聚簇索引和非聚簇索引工作原理
数据库·mysql
我变秃了也没变强1 小时前
pgsql配置密码复杂度策略
数据库·postgresql
PawSQL1 小时前
企业级SQL审核工具PawSQL介绍(1) - 六大核心能力
数据库·sql·oracle
幼稚园的山代王1 小时前
NoSQL介绍
数据库·nosql
猫林老师1 小时前
HarmonyOS线程模型与性能优化实战
数据库·分布式·harmonyos
沃达德软件1 小时前
视频图像数据库基础服务
数据库·图像处理·人工智能·计算机视觉·视觉检测