幂等性
[!info] 知识库定位 权威概念页。幂等性是 架构上保证一致性的技术 中最基础的一块——它让”重试”这件事变得安全。
[!abstract] 一句话定义 同一个操作执行一次和执行多次,对系统状态的影响完全一样——你重试一万次,结果和执行一次没区别。
为什么需要它?
分布式系统里三件事是常态:网络会超时、消息会重复、用户会手抖多点。一次”转账 100 元”如果因为网络抖动触发了重试,没有幂等性,扣的就是两次。问题不在”操作错”,而在”你分不清这次调用到底是第一次、还是重试的那一次”。幂等性把这种不确定性挡在系统边界外——它不消灭重试,而是让重试无害。
核心直觉
把它想成电梯按钮:按一次和连按十次,电梯都只来一趟,效果完全相同。
再想盖章:在卡片上盖”已付”章,盖一次和盖十次,卡片状态都是”已付”。第 N 次盖章不会变成”已付 N 次”。
幂等性的本质是给操作装上**“做过就不再做”的记性**,让副作用与次数解耦。
它是怎么工作的?
先区分两类操作:
- 天然幂等:
PUT(设绝对值x=5)、DELETE(删已删的还是已删)、纯赋值——重复执行不改变状态。 - 天然不幂等:
POST(每次追加)、x=x+1(递增)、扣款balance -= 100——每执行一次状态就变一次。
工程上要把后者变幂等,核心手段是 Idempotency Key(幂等键)+ 去重存储:客户端为每次”意图”生成一个全局唯一 ID,服务端处理前先查这个 ID 有没有处理过。
flowchart TD
A["客户端发起请求<br/>携带 Idempotency-Key: abc123"] --> B["服务端:查去重表"]
B --> C{key 已存在?}
C -->|是| D["直接返回缓存的结果<br/>不执行业务逻辑"]
C -->|否| E["执行业务逻辑"]
E --> F["写入去重表<br/>key=abc123, result=..."]
F --> G["返回结果"]
D --> G
关键细节:先查、再执行、后记录这三步必须在同一个事务里(或用唯一约束兜底),否则会出现”执行了但没记下 key”的窗口——重试时又执行一遍,幂等就破了。
关键组件 / 核心要素
| 组件 | 作用 | 类比 |
|---|---|---|
| Idempotency Key | 客户端生成的唯一请求 ID,幂等的”锚” | 快递单号 |
| 去重存储 | 记录已处理 key 及其结果 | 已签收登记簿 |
| 状态机约束 | 限制操作只在合法状态下生效 | 单程票,验过作废 |
| 数据库唯一约束 | DB 层兜底防并发重复 | 一人一座 |
| 乐观锁/版本号 | 用版本号检测并发冲突 | 文档协作的修订号 |
与相关概念的关系
[!info] vs 幂等 ≠ 每次返回相同结果 幂等保证的是状态效果相同,不是响应内容相同。第二次重复请求可能返回缓存结果、也可能返回
409 已处理——状态没变,但响应可以不同。
[!note] 依赖于 重试 与”至少一次交付” 重试是幂等性存在的理由。没有重试/重复,就不需要幂等;正因为网络层承诺不了”恰好一次”,应用层才用幂等补齐。
[!tip] 被 架构上保证一致性的技术 使用 幂等是消息队列去重、分布式事务 补偿、事件溯源 回放能成立的共同前提——任何”可能被重复触发”的环节都要幂等。
典型应用场景
- 支付/扣款——重试绝不能重复扣,靠 Idempotency Key 去重(Stripe、支付宝的标准做法)。
- 消息队列消费者——消息可能”至少一次”投递,消费端必须幂等。
- API 超时重发——客户端拿不准上次请求到没到,带 key 重试最安全。
- 微服务 RPC / Saga 补偿——补偿操作本身要能反复执行而不破坏状态。
- 数据库迁移/事件回放——重放历史事件重建状态,每条事件必须幂等。
常见误解与陷阱
[!danger] ❌ 误以为:幂等 = 每次返回相同响应 ✅ 实际上:是状态效果相同。第二次可以返回”已处理”或 409,状态没二次改变就算幂等。
[!danger] ❌ 误以为:用了 HTTP PUT 就天然安全 ✅ 实际上:PUT 是语义幂等,但你的实现未必。如果
PUT /user/1的处理逻辑里夹了login_count++,它就不幂等了——HTTP 方法救不了你的实现。
[!danger] ❌ 误以为:加了唯一键就彻底解决 ✅ 实际上:还要处理”执行了业务但没来得及写 key”的崩溃窗口。要么用事务把两者绑在一起,要么靠 DB 唯一约束兜底 + 捕获冲突。
[!danger] ❌ 误以为:幂等是免费的 ✅ 实际上:有成本——要存 key、每次请求要查 key、要清理过期 key。高 QPS 下这是一笔不小的开销。
延伸阅读
- 想深入原理 → HTTP 语义幂等性(RFC 9110 对 GET/PUT/DELETE 的定义);分布式系统的”恰好一次”为何不可达。
- 想看工程实践 → Stripe 的 Idempotent Requests 设计;消息队列的”至少一次 + 幂等消费”模式。
- 想了解前沿/关联 → 事件溯源 的事件回放幂等;Saga 模式里补偿操作的幂等约束;架构上保证一致性的技术。
关联笔记
前置知识:重试 · HTTP 语义 同族概念:架构上保证一致性的技术 · 分布式事务 · 事件溯源 · 补偿 应用场景:支付 · 消息队列消费 · API 重试 · Saga 补偿 学习来源:待补充 项目落地:待补充