好的,阿杰,我帮你系统整理 接口幂等性在高并发场景下的实现思路,这是腾讯面试常问的后台技术题。内容包括概念、方法、具体实现示例和注意点。


🔑 接口幂等性面试解析

1️⃣ 什么是接口幂等性?

  • 定义:同一个请求 无论调用多少次,对系统的影响结果都是相同的。
  • 特点
    1. 多次请求只会产生一次有效结果
    2. 不会因为网络重试或重复提交导致业务数据异常
  • 举例
    • 充值接口
      • 用户请求充值 100 元,无论请求多少次,账户只增加 100 元
    • 查询接口
      • GET 请求自然幂等,重复调用不会改变结果

2️⃣ 如何保证接口幂等性?

2.1 通过 唯一请求标识(Idempotency Key)

  • 客户端生成一个唯一请求 ID(UUID / 业务单号)
  • 服务端校验该请求是否处理过:if requestId exists in Redis: return cached response else: process request store requestId in Redis
  • 适用于 支付、下单、转账等业务

2.2 通过 数据库约束

  • 唯一索引
    • 利用数据库唯一索引保证重复数据无法插入
    • 示例:CREATE TABLE orders ( order_id VARCHAR(50) PRIMARY KEY, user_id INT, amount DECIMAL(10,2) );
    • 重复提交的 order_id 会被数据库拒绝
  • 乐观锁
    • 通过版本号或时间戳判断是否重复更新
    • 示例:UPDATE account SET balance = balance + 100, version = version + 1 WHERE user_id = 1 AND version = 1;

2.3 幂等操作设计

  • GET 请求:天然幂等,不修改状态
  • PUT 请求:更新资源时使用完整资源覆盖,保证幂等
  • DELETE 请求:重复删除结果相同

3️⃣ 高并发下实现接口幂等性

高并发场景需要考虑 原子性和线程安全,常用方法:

3.1 分布式锁(Redis / Zookeeper)

  • 在处理请求前,加锁保证同一时间只有一个请求处理:
# Redis 分布式锁示例(Python)
lock_key = "order_123_lock"
if redis.setnx(lock_key, 1):
    redis.expire(lock_key, 5)
    try:
        process_order()
    finally:
        redis.delete(lock_key)
else:
    return "请求处理中,请稍后"

  • 注意释放锁和设置过期时间,防止死锁

3.2 Redis 原子操作

  • 使用 SETNX / GETSET / Lua 脚本保证请求只被处理一次
# Lua 脚本保证原子性
if redis.call("exists", KEYS[1]) == 0 then
    redis.call("set", KEYS[1], ARGV[1])
    return 1
else
    return 0
end

3.3 数据库唯一索引 + 重试

  • 高并发场景下,通过 唯一索引+异常捕获 防止重复插入
  • 结合幂等请求号处理逻辑

3.4 幂等结果缓存

  • 将处理过的请求结果缓存(Redis / Memcached)
  • 避免重复计算,减少 DB 压力

4️⃣ 注意点

关注点说明
幂等性设计尽量将接口设计成幂等操作(PUT / DELETE / GET)
请求标识客户端生成唯一 requestId,服务端幂等存储
高并发结合分布式锁、Redis 原子操作、数据库唯一索引
缓存对处理结果缓存,避免重复操作
重试网络重试、超时重发时,保证重复请求安全

5️⃣ 面试答题模板(参考)

“接口幂等性指同一请求调用多次对系统影响一致。实现方式可以通过客户端生成唯一请求 ID,在服务端存储处理状态;或者通过数据库唯一索引防止重复数据插入;高并发场景下,可以使用分布式锁、Redis 原子操作、或幂等结果缓存来保证请求只被处理一次。设计接口时也应尽量遵循幂等原则,如 PUT / DELETE / GET 操作天然幂等。”