好的,阿杰,我帮你系统整理 接口幂等性在高并发场景下的实现思路,这是腾讯面试常问的后台技术题。内容包括概念、方法、具体实现示例和注意点。
🔑 接口幂等性面试解析
1️⃣ 什么是接口幂等性?
- 定义:同一个请求 无论调用多少次,对系统的影响结果都是相同的。
- 特点:
- 多次请求只会产生一次有效结果
- 不会因为网络重试或重复提交导致业务数据异常
- 举例:
- 充值接口:
- 用户请求充值 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 操作天然幂等。”
发表回复