文章目录
什么是幂等(Idempotence)
简单说:
一次请求和多次请求的结果是一样的,不会因为重复请求造成数据异常或重复处理。
举个例子
幂等操作
POST /order/pay?id=12345
无论你请求一次,还是网络原因请求了 3 次,只会支付一次订单,不会重复扣钱或生成多个支付记录。
非幂等操作
UPDATE account SET balance = balance - 100 WHERE id = 1;
如果这个请求执行了两次,就会多扣 100 块!
为什么分布式系统必须要幂等
在 WHAT - 事务?transaction?单个数据库事务和分布式事务 中我们介绍分布式系统中的事务(更复杂)时提及过幂等处理。
“幂等处理能力”是做分布式系统时非常关键的一个概念,尤其是在涉及重试、失败补偿、消息队列等场景中,系统必须要有能力抵抗重复请求带来的副作用。
因为在以下场景中,请求可能会被多次发送:
- 网络超时重试(调用方/中间件自动重试)
- MQ 消息重复投递
- 事务补偿机制触发多次补偿逻辑
- 客户端点击多次、刷新操作
如果处理逻辑不具备幂等性,就可能导致:
- 订单重复扣款
- 重复发货
- 积分多次增加/减少
- 资源状态错乱(库存被扣光)
幂等处理的常见方案
技术手段 | 原理描述 |
---|---|
唯一请求 ID | 每个请求生成一个 requestId ,处理过的请求不再重复处理(可存入 Redis) |
数据库唯一约束 | 插入时使用唯一键限制(如订单号) |
幂等 token | 客户端发送请求时附带一次性 token,服务端验证后即销毁 |
状态判断 | 先检查订单/业务状态,若已处理则跳过 |
乐观锁 / 版本号 | 使用 version 字段更新数据,防止重复写入 |
示例 1:通过请求唯一 ID 做幂等(Redis 实现)
const redisKey = `request:${requestId}`
const exists = await redis.get(redisKey)
if (exists) {
return { message: '重复请求' }
}
await redis.set(redisKey, 1, 'EX', 60) // 记录 60 秒内处理过
await doBusinessLogic()
示例 2:MySQL 唯一约束防止重复插入
INSERT INTO payment_record (order_id, user_id, status)
VALUES ('order123', 1, 'PAID')
ON DUPLICATE KEY UPDATE status = 'PAID';
示例 3:接口幂等 token(电商常见)
- 第一步:前端获取
POST /getIdempotentToken
- 第二步:提交订单时附带该 token
- 后端校验 token 是否被使用过 → 使用后即失效
总结
幂等性 = 系统面对重复操作时,仍能保持数据的一致性和正确性。
在分布式环境中,幂等性不是可选项,而是必须设计的核心能力。