幂等键
幂等键标识同一次业务意图,避免重复请求产生额外副作用。本文负责键作用域、事务边界和结果恢复。
1. 面试核心
先记住这几条,再读正文- 业务意图。 同一业务意图复用同一 key,不同意图使用新 key。
- 唯一作用域。 主体、接口与 key 组成唯一作用域,请求摘要用于检测参数冲突。
- 本地原子提交。 同库操作用事务共同提交业务变化与幂等结果。卡 · 综合题
- 外部副作用。 外部副作用需稳定下游请求号和结果核对。卡 · 外部调用的崩溃窗口
- 保留窗口。 幂等记录的保留期决定重复请求的识别窗口。
2. 幂等键的含义
客户端为一次创建、支付或退款生成唯一 key。结果未知时复用它。用户主动发起另一笔交易时使用新 key。
服务端按调用主体、接口和 key 隔离记录。同 key 的请求摘要必须一致。金额或资源不同的请求返回参数冲突。
幂等约束的是副作用。重复响应可重放首次结果,也可返回当前资源,需由接口契约定义。
3. 原子占用
记录可包含以下字段:
principal, operation, key, request_hash,
status, resource_id, response, expires_at
唯一约束决定哪个事务取得执行权。先查询再无约束插入会产生并发竞态。
冲突请求读取既有结果,或按状态返回处理中。唯一键解决执行权竞争,处理状态还需配合事务设计。
4. 与业务结果一致
业务与幂等记录在同库时,可使用一个本地事务。占用 key、修改业务和保存结果共同提交。
以 MySQL 8.0 的 RC/RR 为例,普通读取看不到未提交记录。重复插入会按数据库机制等待或冲突。提交后再读取已保存结果。
崩溃导致事务回滚时,幂等占用也回滚。另一请求可重新竞争执行权。
5. 处理中的重复请求
长任务或外部调用可先提交 PROCESSING 状态。后续请求能读到该状态,并返回状态查询入口。
这类方案需持久化工作流。执行者崩溃后,由恢复任务核对实际结果。租约过期只是接管条件,外部支付结果仍需查询。
接口可约定返回 202 与查询地址。短暂等待也应受请求总时限约束。
6. 返回结果
保存首次响应可稳定重放,但要处理敏感字段与旧 header。保存资源 ID 后重新读取,则返回资源当前状态。
参数校验失败和已发生副作用的失败应分开处理。Stripe 会保存进入执行后的结果,包括 500。参数校验失败或并发执行冲突不保存结果。其他接口需自行声明对应规则。
7. 保留时间
保留期覆盖自动重试、消息重投与人工补单窗口。记录清理后,相同 key 将被视为新请求。
长期业务唯一号可提供更长的去重边界。短 TTL 缓存适合加速,权威业务约束仍需持久化。
8. 条件状态转换
业务状态更新需检查合法前置状态。
UPDATE payment
SET status = 'CAPTURED'
WHERE payment_id = ? AND status = 'AUTHORIZED';
应用根据影响行数确认本次是否完成转换。影响 0 行时,再查询当前状态判断结果。
该更新只保护数据库内的状态推进。外部扣款仍需稳定请求号与结果核对。
9. 客户端重试
结果未知时,客户端复用原 key 并按预算重试。具体退避规则见重试。
总时限耗尽后停止自动发送,转为查询状态。修改请求参数时,应发起新的业务意图。
10. 外部调用的崩溃窗口
外部支付成功、本地结果尚未写入时,进程可能崩溃。恢复任务读到 PROCESSING,仍无法据此判断支付失败。
调用前需持久化稳定下游请求号。恢复时用该号码查结果,或按下游幂等协议重发。确认成功后,再更新本地完成状态。
下游缺少查询和幂等能力时,自动补发有重复扣款风险。此类未知结果需进入对账或人工处理。Outbox 可靠投递仍需消费者去重。
11. 常见问题
11.1 唯一索引与幂等记录
唯一索引原子阻止重复占用。幂等记录还保存摘要、状态与返回结果。业务唯一约束可与接口幂等记录共同使用。
11.2 Redis 与权威状态
Redis key 与数据库事务分开提交时,存在一侧成功的窗口。缓存淘汰也会缩短识别时间。关键写入将权威状态保存在持久存储中。
12 · 面试题卡片
12.1 如何设计一个支持安全重试的支付接口
出现公司:美团
题型:综合题
考察重点
- 理解幂等键作用域、请求摘要和原子占用。
- 理解业务事务、处理中状态和外部副作用。
- 理解TTL、状态查询与条件状态转换。
参考回答
支付接口用稳定 key 识别同一支付意图。
服务端按主体、接口与 key 建唯一记录,并校验请求摘要。同库业务与幂等结果在同一事务提交。
外部支付采用持久化状态机与稳定下游请求号。崩溃恢复先核对下游结果,再补本地状态。处理中请求返回查询入口。保留期覆盖重试与补单窗口,业务唯一号提供额外约束。
12.2 外部扣款成功后进程崩溃,PROCESSING 过期就能重新扣款吗?
出现公司:暂无已核验的公开来源(本站自测)
考察重点:外部结果未知、稳定请求号与恢复。
相关内容:外部调用的崩溃窗口。
参考回答
PROCESSING 过期后,应先核对原扣款结果,不能直接按新请求再次扣款。
过期只说明本地处理未完成,外部支付可能已经成功。
使用持久化的下游请求号查询;下游支持幂等时,也可用同一号码重发。缺少这些能力时,未知结果进入对账或人工处理。