Skip to content

分布式服务的接口幂等性

一、什么是接口幂等性?

幂等性是指:同一个接口被多次调用,对业务状态产生的影响和结果,与只调用一次时完全一致。简单说,就是“重复调用不会造成数据异常”。

二、为什么要做接口幂等性?

在分布式/微服务场景中,以下情况都可能导致接口被重复调用:

  • 用户重复点击提交按钮(网络波动、页面卡顿)
  • MQ消息重复投递
  • 接口超时重试(调用方自动重试机制) 如果接口不具备幂等性,重复调用可能导致订单重复创建、支付重复扣款、库存多次扣减等问题。

三、常见请求方式的幂等性分析

请求方式幂等性说明示例
GET查询操作,天然幂等多次查询同一用户信息,结果不变
POST新增操作,非幂等重复提交订单,会生成多条订单
PUT绝对更新(如set money=500)是幂等;增量更新(如money+500)非幂等重复执行update t set a=1 where id=1结果不变
DELETE根据唯一标识删除,幂等重复删除同一订单,第二次操作不影响数据

四、常见幂等性实现方案

1. 数据库唯一索引

通过数据库的唯一约束,防止重复插入数据,适用于新增类接口。

  • 原理:给业务唯一字段(如订单号、用户ID+商品ID)添加唯一索引,重复插入时数据库会抛出异常,从而避免脏数据。
  • 适用场景:新增订单、用户注册等操作。

2. Token + Redis 机制

适用于提交订单、支付、转账等敏感操作。

  • 流程:
    1. 客户端先向服务端申请一个唯一Token,服务端生成Token并存入Redis(设置过期时间),返回给客户端。
    2. 客户端携带Token提交业务请求,服务端验证Token是否存在。
    3. 若Token存在,处理业务并删除Redis中的Token;若不存在,直接拒绝请求。
  • 特点:Token一次性使用,确保请求只被处理一次。

3. 分布式锁

适用于并发修改类接口,如库存扣减、秒杀抢购。

  • 原理:使用Redis或ZooKeeper实现分布式锁,同一时间只允许一个请求执行业务逻辑,其他请求直接返回失败。
  • 示例(Redisson实现):
java
public void saveOrder(Item item) throws InterruptedException {
    RLock lock = redissonClient.getLock("orderLock");
    // 尝试获取锁
    boolean isLock = lock.tryLock(10, TimeUnit.SECONDS);
    try {
        if (!isLock) {
            throw new RuntimeException("提交请求失败,请稍后重试");
        }
        // 执行业务逻辑(如扣减库存、创建订单)
    } finally {
        lock.unlock();
    }
}
  • 特点:控制锁的粒度,避免重复操作,支持快速失败机制。

五、面试相关问题

  1. 问:什么是接口幂等性?为什么要实现?答: 接口幂等性指同一个接口被多次调用,业务结果和单次调用完全一致。在分布式场景中,用户重复点击、消息重复投递、接口重试等都可能导致重复调用,实现幂等性可以避免重复下单、重复扣款等问题,保证数据一致性。

  2. 问:项目中是如何实现接口幂等性的?答: 项目中根据不同场景采用了多种方案:新增订单使用Token+Redis机制,支付接口结合分布式锁控制并发,数据库关键表添加唯一索引兜底,确保所有写操作接口都具备幂等性。

  3. 问:Token+Redis实现幂等的流程是什么?答: 客户端先获取一次性Token,服务端将Token存入Redis;提交请求时携带Token,服务端验证Token存在则处理业务并删除Token,不存在则拒绝请求,确保请求只被处理一次。

  4. 问:分布式锁实现幂等需要注意什么?答: 需要控制锁的粒度,避免锁粒度过大影响性能;设置合理的锁超时时间,防止死锁;同时配合快速失败机制,避免无效等待。


需要我把这些内容整理成一份面试背诵版的精简笔记吗?

Powered by VitePress 1.6.4 | 持续更新中