跳转至

幂等:重复执行仍然安全

单元 07|难度:中级|前置:数据库、消息队列|目标:让网络重试和重复投递不会制造重复副作用

定义

同一个业务操作执行一次或多次,最终业务状态保持一致。

幂等不是“函数被调用一次”,而是承认网络重试、MQ 重复投递、超时恢复一定会发生,并让重复执行不会产生重复副作用。

两条路线中的例子

IoT

  • 重复收到心跳,不应重复生成“上线”事件;
  • 同一个 OTA 任务重发,不应创建两份升级任务;
  • 同一条告警消息重复消费,不应生成两条告警记录;
  • “设置阀门为关闭”天然比“切换阀门状态”更容易幂等。

AI Agent

  • create_ticket 超时后重试,不应创建两张工单;
  • 任务从 checkpoint 恢复,不应重复发送邮件;
  • 模型重复选择同一工具,不应重复扣费或删除数据。

常见实现

业务幂等键

{
  "task_id": "task_123",
  "operation_id": "create_ticket:device_42:incident_88"
}

服务端先查询 operation_id 是否已执行。若已完成,直接返回之前的结果;若未执行,再开始操作。

数据库唯一约束

CREATE UNIQUE INDEX uniq_operation_id
ON tool_executions(operation_id);

唯一约束是并发条件下的最后防线,不能只靠应用层“先查再写”。

状态机

只允许合法状态迁移:

pending → running → succeeded
                  ↘ failed

已处于 succeeded 的操作再次收到执行请求时,返回已保存结果。

幂等不等于锁

  • 锁:控制同一时刻谁可以执行;
  • 幂等:即使重复执行或重复到达,业务结果仍正确。

二者经常结合,但锁过期、进程崩溃或网络分区后仍可能发生重复,所以不能用锁代替幂等。

面试表达

幂等是指同一个业务请求执行一次或多次,最终业务状态一致。分布式系统无法避免网络重试、重复投递和故障恢复,因此支付、订单、设备命令和 Agent 工具调用需要通过业务幂等键、数据库唯一约束和状态机等方式避免重复副作用。

自测

  1. 为什么锁不能代替幂等?
  2. “先查询 operation_id 不存在,再插入”在并发下有什么问题?
  3. 幂等键应该由随机重试生成,还是同一业务操作稳定复用?
  4. 哪些查询天然幂等,哪些写操作需要额外设计?

完成标准

  • 能解释重复发生的四个来源
  • 能设计稳定的业务幂等键
  • 能用唯一约束处理并发竞争
  • 能区分幂等、锁和事务

下一单元:状态机