幂等概述
- 幂等性本来是数学上的概念,即便公式:f(x)=f(f(x)) 可能成立的数学性质。用在编程畛域,则意为对同一个零碎,应用同样的条件,一次申请和反复的屡次申请对系统资源的影响是统一的。
- 幂等性是分布式系统设计中非常重要的概念,具备这一性质的接口在设计时总是秉持这样的一种理念: 调用接口产生异样并且反复尝试时,总是会造成零碎所无奈接受的损失,所以必须阻止这种景象的产生 。
- 实现幂等的形式很多,目前基于申请令牌机制适用范围较广。其核心思想是为每一次操作生成一个唯一性的凭证,也就是 token。一个 token 在操作的每一个阶段只有一次执行权,一旦执行胜利则保留执行后果。对反复的申请,返回同一个后果(报错)等。参考《幂等性浅谈》
幂等解决实现
退出依赖
<dependency>
<groupId>com.pig4cloud.plugin</groupId>
<artifactId>idempotent-spring-boot-starter</artifactId>
<version>0.0.1</version>
</dependency>
配置 Redis 链接
- 默认状况下,能够不配置。实践是反对 redisson-spring-boot-starter 全副配置
spring:
redis:
host: 127.0.0.1
port: 6379
接口
@Idempotent(key = "#key", expireTime = 10, info = "请勿反复查问")
@GetMapping("/test")
public String test(String key) {return "success";}
测试
- 10 个独立线程申请
- 执行查看后果,10 个申请只会有一个胜利
- 查看后盾异样报错,9 个异样报错满足预期
idempotent 注解阐明
- key: 幂等操作的惟一标识,应用 spring el 表达式 用 #来援用办法参数。 可为空则取以后 url + args 做申请的惟一标识
- expireTime: 有效期 默认:1 有效期要大于程序执行工夫,否则申请还是可能会进来
- timeUnit: 工夫单位 默认:s(秒)
- info: 幂等失败提示信息,可自定义
- delKey: 是否在业务实现后删除 key true: 删除 false: 不删除
幂等解决设计原理
流程设计参考
- 1. 申请开始前,依据 key 查问 查到后果:报错 未查到后果:存入 key-value-expireTime key=ip+url+args
- 2. 申请完结后,间接删除 key 不论 key 是否存在,间接删除 是否删除,可配置
- 3.expireTime 过期工夫,避免一个申请卡死,会始终阻塞,超过过期工夫,主动删除 过期工夫要大于业务执行工夫,须要大略评估下;
- 4. 此计划间接切的是接口申请层面。
- 5. 过期工夫须要大于业务执行工夫,否则业务申请 1 进来还在执行中,前端未做遮罩,或者用户跳转页面后再回来做反复申请 2,在业务层面上看,后果仍旧是不合乎预期的。
- 6. 倡议 delKey = false。即便业务执行完,也不删除 key,强制锁 expireTime 的工夫。预防 5 的状况产生。
- 7. 实现思路:同一个申请 ip 和接口,雷同参数的申请,在 expireTime 内屡次申请,只容许胜利一次。
- 8. 页面做遮罩,数据库层面的惟一索引,先查问再增加,等解决形式应该都解决下。
- 9. 此注解只用于幂等,不用于锁,100 个并发这种压测,会呈现问题,在这种场景下也没有意义,理论中用户也不会呈现 1s 或者 3s 内手动发送了 50 个或者 100 个反复申请, 或者弱网下有 100 个反复申请;
总结
- pig-mesh/pig
- pig-mesh/idempotent-spring-boot-starter