在分布式系统中,幂等是一个非常重要的概念,常常与“重试”一起出现。当调用一个远程服务发生超时,调用方并不知道请求是否执行成功,这就是典型的“第三态”问题。对于这个问题最常见的解决方案便是进行主动重试,假如该操作是一个数据库插入操作,重试将对系统产生副作用(创建多条记录),这时我们常常会说,被调用接口需要保障幂等。
幂等可以简单定义如下:任意多次执行所产生的影响均与第一次执行的影响相同。
【注】从幂等定义上看,重心放在了操作之后的影响,及多次操作不会破坏内部状态。但在实际工作当中,除了内部状态外,接口的返回值也是一个重要要素,多次重复操作返回相同的结果往往更符合使用者的预期。
举个例子,在订单系统中,用户使用优惠券下单后会调用冻结接口对优惠券进行冻结操作,站着订单系统的视角,当进行冻结重试时你期望:
大家可以思考下两种方案在下游使用时的异同,当然最好提供两种机制,由使用方根据场景进行定制。
在不同的场景下,幂等保护的方案是不同的,常见幂等处理策略有:
由于其他策略与场景强绑定,idempotent 重心放在方案4上,已覆盖更多的业务场景。
快速为非幂等接口增加幂等保护。
首先,引入 lego starter,在 maven pom 中添加如下信息:
- <groupId>com.geekhalo.lego</groupId>
- <artifactId>lego-starter</artifactId>
- <version>0.1.15-idempotent-SNAPSHOT</version>
然后,以 JpaRepository 为例实现对 IdempotentExecutorFactory 的配置,具体如下:
- @Configuration
- public class IdempotentConfiguration extends IdempotentConfigurationSupport {
- @Bean("dbExecutorFactory")
- public IdempotentExecutorFactory redisExecutorFactory(JpaBasedExecutionRecordRepository recordRepository){
- return createExecutorFactory(recordRepository);
- }
- }
其中,
IdempotentConfigurationSupport 已经提供 idempotent 所需的很多 Bean,同时提供 createExecutorFactory(repository) 方法,用以完成 IdempotentExecutorFactory 的创建。
使用 Jpa 需要调整 EnableJpaRepositories 相关配置,具体如下:
- @Configuration
- @EnableJpaRepositories(basePackages = {
- "com.geekhalo.lego.core.idempotent.support.repository"
- }, repositoryFactoryBeanClass = JpaBasedQueryObjectRepositoryFactoryBean.class)
- public class SpringDataJpaConfiguration {
- }
其中,
com.geekhalo.lego.core.idempotent.suppor