如何解决幂等性问题,幂等性问题产生的原因

 

我们在面试过程中,hr常问及的问题便是幂等性问题产生的原因、如何解决、运用的场景等。今天小编就带领大家一同看看什么是幂等性问题,常见的幂等性问题发生场景及解决方案有哪一些,如果有哪些地方写的不够周到的也请大家在评论区补充说明!

3beeb79390ee45278c5f0d847d49ea31.png

什么是幂等性

        幂等性是指在计算机系统中,一个操作无论执行多少次,产生的结果都是一样的,不会因为多次点击而产生副作用。比如在我们日常生活中进行银行的转账操作,如果你转账100元,且重复操作,账户会被多扣100元,导致不同的结果,这就没有保证接口幂等性。因此,设计一个幂等的转账操作尤为重要,无论你点击多少次“转账”,系统只会进行一次扣款和一次转账,避免多次转账的情况。

幂等性产生的原因

        幂等性产生的原因主要是为了应对分布式系统、网络通信、并发操作中的不确定性和故障情况。具体原因包括以下几个方面:

1. 网络不可靠性

网络通信可能会出现各种问题,比如请求丢失、超时、重复发送等。为了保证在这种情况下系统的稳定性和一致性,操作需要设计成幂等的。这样,即使请求被重复发送,系统也能保证最终结果的一致性。

2. 分布式系统中的冗余和重复

在分布式系统中,同一操作可能会被多个服务节点处理,或者因为某个节点失败后重新发送请求。这种情况下,幂等性确保重复操作不会导致数据错误或系统异常。

3. 并发操作

多线程或多进程环境下,多个操作可能同时对同一资源进行访问和修改。幂等性可以防止并发操作导致的不一致问题,确保无论多少次操作结果都相同。

4. 事务管理和故障恢复

在处理事务时,如果事务执行失败,系统需要重试操作。幂等性确保重试不会导致事务被多次应用,保证数据的一致性和完整性。

5. 外部系统调用

调用外部系统的API或服务时,如果外部系统未能及时响应,调用方可能会重复发送请求。幂等性确保重复调用不会产生副作用或错误结果。

6. 数据一致性要求

为了保证数据的一致性和完整性,尤其在金融、支付等对数据准确性要求极高的领域,幂等性可以防止因重复操作导致的数据错误或不一致。

什么场景需要进行幂等设计?

1.在线支付:当用户发起支付请求时,避免重复扣款

2.银行交易:确保同一笔交易不会因为网络重试等原因被多次执行操作

3.票务系统:在线购票平台在用户购票时,会进行检查用户所选位置是否被重复预订

4.通信服务:如短信或通话服务,系统会检查是否已为相同内容的请求计费

5.任务调度:在定时任务或批处理系统中,确保不会因为任务的重启或重试而重复执行相同的操作

6.库存扣减:确保库存扣减操作无论被执行多少次,只会扣减一次库存

幂等性的解决方案

常见的幂等性解决方案有乐观锁、去重表、redis分布式锁、幂等性token等等。

1.去重表

去重表的设计结构:

  • 唯一标识符字段(Primary Key):ID 唯一标识每条记录,可以为UUID、请求ID、事务ID、等等,类型通常为字符串或者整形,根据唯一标识符的生成方式决定
  • 状态字段(Status):记录操作的状态,如处理中,已完成、失败等
  • 操作符字段(Operation Type):记录操作的类型,如常见的创建、更新、删除等操作
  • 其他字段(Optional Fields):根据具体的业务需求按需添加即可

具体实现操作:

在执行具体业务操作之前,系统会先检查去重表是否已经存在该唯一标识的记录,如果存在,则说明该记录已经执行过,可以直接返回结果、避免重复的添加执行。

如果不存在该唯一标识符记录,则会进行插入操作,标记该操作正在处理中,这样可以防止并发操作导致的重复执行。

然后再执行具体的业务操作,如处理支付请求、消费消息等等。

再根据业务逻辑执行的结果,更新去重表中的状态字段,标记操作已完成或者失败

2.Token令牌机制

7a20ef6848194172aa48ebc66f191d10.png

利用AOP注解+拦截器+Token+redis 通过UUID生成唯一键值的 token,将token 存放到redis中,在需要进行幂等性操作的业务方法上添加aop注解

TokenService代码

5e45c6da61a44c48863de0ca36bdee00.png

拦截器代码

@Component
public class IdemponentInterceptor implements HandlerInterceptor {

    @Autowired
    private TokenService tokenService;
    @Override
    public boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {

        if (handler instanceof HandlerMethod){
            HandlerMethod hm = (HandlerMethod) handler;
            // 获取接口方法上的注解
            AutoIdempoent idempoent = hm.getMethodAnnotation(AutoIdempoent.class);
            if (idempoent == null){
                // 说明不存在幂等性的注解 即这个接口不需要幂等性处理
                return true;
            }else {
                // 说明存在幂等性的注解 即这个接口需要幂等性处理
                return tokenService.chectoken(request);
            }
        }



        return HandlerInterceptor.super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView moderAndView) throws Exception {
        HandlerInterceptor.super.postHandle(request, response, handler, moderAndView);
    }


    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }



}

当请求进来时 方法会来到拦截器获取接口方法上的注解判断是否需要进行幂等性处理,若需要则会先进行查询token令牌是否存在,如果存在lua脚本则删除token 不存在 则返回重复请求,进行相应的业务操作

RedisService代码

@Service
public class RedisService {

    @Resource
    private RedisTemplate redisTemplate;

    public boolean exists(String token) {
        return redisTemplate.hasKey(token);
    }


    public boolean delete(String token) {
        if (exists(token)){
            return redisTemplate.delete(token);
        }
        return false;
    }
    //保存token
    public void saveToken(String token) {
        redisTemplate.opsForValue().set(token, token);
    }
}

 

 

 

 

  • 31
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
分布式接口问题是指在分布式系统中,由于网络延迟、重试机制等原因,可能导致同一个请求被重复处理,从而产生重复的业务逻辑。为了解决这个问题,需要保证接口的。 保证接口的的方法有多种。一种常见的方法是使用唯一标识来标识每一次请求,比如订单id、支付流水号或者前端生成的唯一随机串。在每次请求之前,需要将唯一标识存放到数据库或者缓存中。后端服务在处理请求之前,需要先检查这个唯一标识是否存在,如果存在,则判定此次请求已经处理过,不需要进行重复处理。这样可以避免重复的业务逻辑。 在分布式场景中,由于负载均衡算法的原因,可能会导致同一个请求被多台机器处理。为了解决这个问题,可以使用分布式锁来保证只有一个机器能够处理该请求。另外,使用分布式事务也可以保证接口的。 此外,还可以通过拦截器(AOP)和注解的方式实现一个通用的解决方案,避免每次请求都写重复的代码。在设计系统时,是一个需要首要考虑的问题,特别是在涉及到金融交易等关键业务的系统中。 综上所述,保证分布式接口的可以通过使用唯一标识、分布式锁、分布式事务等方法来实现。这样可以避免重复的业务逻辑和数据不一致的问题。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* *2* [分布式环境下接口浅析](https://blog.csdn.net/ice24for/article/details/86084613)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [分布式开发(二)---接口(防止重复提交)](https://blog.csdn.net/icanlove/article/details/117652662)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值