1. 幂等性基础
很多人刚接触 Secrets Manager 时,总觉得幂等性是个“加分项”,不是必须的。我刚开始也这么想,直到线上出了个事故——客户端超时重发了三次创建密钥的请求,结果数据库里冒出了三把完全一样的密钥。嗯,从那以后,幂等性就成了我设计 API 时的第一道防线。
什么是幂等性
说白了,幂等性就是:同一个请求,不管发一次还是发一百次,对系统产生的结果是一样的。用数学的话讲,f(x) = f(f(x))。用日常的例子来说,就是“按电梯按钮”——你按一次电梯会来,按十次电梯还是那同一趟。
幂等性不是新鲜概念。HTTP 规范里早就定义了 GET、PUT、DELETE 是幂等的,POST 不是。但在实际工程中,我们经常需要把 POST 也做成幂等的——尤其当客户端可能有重试逻辑时。
为什么 API 需要幂等性
你可能要问:为什么非要搞这么复杂?让客户端自己保证不重试不行吗?
不行。因为网络是不可靠的。你想想看,客户端发了个创建密钥的请求,服务端收到了,也处理成功了,但返回响应的那一刻网络断了。客户端没收到成功消息,它就会重试。这时候如果没有幂等性,服务端就会再创建一把密钥——这就是我说的那个事故的根因。
- 网络抖动:TCP 超时、连接重置,客户端自动重试
- 客户端 Bug:代码写错了,同一个请求发了两遍
- 用户误操作:用户手抖多点了一次“保存”按钮
- 服务端重试:服务端内部失败后重试,又对外暴露了副作用
我记得有次跟一个金融客户对接,他们要求所有写操作都要支持幂等性,并且用请求 ID 来去重。刚开始我觉得有点过度设计,后来发现他们的合规审计要求:每个操作必须能追溯且不可重复执行。这才明白,幂等性其实是一道安全锁。
幂等性与安全性的关系
很多人把幂等性和安全性分开看,其实它们纠缠得很深。我简单列几点:
| 安全问题 | 无幂等性的后果 | 有幂等性的解决方案 |
|---|---|---|
| 重复支付 | 用户请求扣费两次,多扣钱 | 幂等键去重,只扣一次 |
| 重复创建凭证 | 多把密钥泄露风险增大 | 通过幂等键返回已有密钥 |
| 重复吊销权限 | 用户被反复踢出,体验差 | 吊销操作幂等,结果一致 |
| 日志污染 | 审计日志出现重复操作,难以排查 | 幂等记录合并,日志干净 |
你看,幂等性其实是在为安全性兜底。当一个操作被重复执行时,如果没有幂等性,你就需要额外的手工对账、数据修复。我在项目中见过一个案例:某 Secrets Manager 的创建密钥接口没有幂等性,结果客户端重试导致数据库里多了 5 条相同记录。运维团队花了整整两天去清理,还差点引发密钥泄露风险。
那幂等性怎么落地呢?最常用的模式就是“请求 ID 去重”。客户端生成一个全局唯一的 Idempotency-Key(比如 UUID),服务端在收到请求时先查一下这个 Key 有没有处理过。处理过就直接返回上次的结果,没处理过就正常执行并缓存结果。这个过程我画了一张图,你一看就明白:
你看这个流程:客户端带着相同的 Idempotency-Key 发出 N 次请求,幂等性中间件只要发现 Key 已经存在,就直接返回第一次缓存的结果,不再触发实际的创建/更新/删除操作。这样不管网络怎么抖,最终数据库里的状态都是一致的。
我个人习惯是在设计每个写接口时,先问三个问题:
- 这个操作被重复执行会有什么后果? 创建密钥 → 多把密钥;更新密钥 → 版本暴增;删除密钥 → 幂等可安全重试。
- 客户端的重试行为可控吗? 不可控,必须服务端兜底。
- 幂等健(Idempotency-Key)的生命周期多长? 至少需要覆盖客户端最长超时时间,一般建议 24 小时。
说回开头那个事故。后来我补了幂等性,客户端重试时传入相同的 Idempotency-Key,服务端直接返回已有的密钥信息。从此再也没出现过重复创建。嗯,这个教训我一直记着,也希望能帮你少走弯路。