—— 一位被幂等坑过的工程师
在高并发与分布式系统中,“重复请求”“消息重放”“定时任务重复执行”都是常态。
如果处理不当,轻则数据错乱,重则「重复扣款」「订单多生成」「库存为负」😱
这时,我们需要的就是——幂等性设计(Idempotency Design)。
本文将系统梳理 7 种常见的幂等性模式,从请求到事件总线,带你一步步掌握系统级防重的最佳实践。
🧩 一、什么是幂等性?
幂等性(Idempotency)指:
一次或多次执行操作,结果保持一致。
换句话说,即使你多点几次按钮、接口多重发几次、消息被多消费几次——系统结果依然正确。
例如:
✅ 点击「支付确认」两次,不会重复扣款
✅ 消息队列重试 3 次,仍只入库一次
✅ 定时任务触发两次,只更新一次状态
🧱 二、幂等性设计的 7 种常见模式
下面从请求入口 → 业务逻辑 → 数据存储 → 消息事件四个层面,看实际工程中常用的幂等性设计手段。
① 请求级:Idempotency Key(请求幂等键)
📦 典型场景: 用户重复点击「提交订单」或「支付」。
💡 做法:
客户端为每次操作生成一个唯一请求 ID(如 UUID),放在请求头或参数中:
POST /api/orderHeaders:Idempotency-Key: 7f5c9b2c-6f7d-4d9e-a1b3-xxxxxx
服务端逻辑:
检查该 Key 是否已处理(查 Redis / 数据库);
若已存在 → 直接返回之前的结果;
若不存在 → 执行逻辑并记录 Key 结果。
🧠 优点: 通用、跨语言、业务无侵入。
⚠️ 注意: Key 存储需带 TTL,防止无限增长。
② 数据级:唯一约束(Unique Constraint)
📦 典型场景: 创建订单、注册用户、发放优惠券。
💡 做法:
依赖数据库层唯一索引来保证物理幂等:
CREATE UNIQUE INDEX idx_order_no ON orders(order_no);
当重复插入同一订单号时,数据库报 Duplicate Key 错误,业务捕获后返回已有结果。
🧠 优点: 简洁高效、数据库原生支持。
⚠️ 注意: 仅适用于“确定性唯一”的场景(如订单号、业务号)。
③ 状态机约束(State Transition Check)
📦 典型场景: 防止订单状态反复更新,如 CREATED → PAID → DONE。
💡 做法:
在更新时检查当前状态是否允许转换:
if (order.getStatus() == PAID) {return; // 已支付,无需重复}
⚠️ 注意: 要用分布式锁,状态必须落地存储,避免多节点状态不一致。
④ 幂等日志表(Idempotent Log Table)
📦 典型场景: 处理第三方回调(如支付平台通知)、Webhook、MQ 消息。
💡 做法:
建立一张幂等日志表,记录业务操作的唯一 ID:
CREATE TABLE idempotent_log (id VARCHAR(64) PRIMARY KEY,biz_type VARCHAR(32),processed_at TIMESTAMP);
处理逻辑:
收到请求,先查表是否存在此 ID;
若存在 → 忽略;
若不存在 → 执行逻辑并插入日志。
🧠 优点: 可追溯、通用性强。
⚠️ 注意: 表需定期清理,避免日志膨胀。
⑤ 消息级:去重消费(Exactly-once-like)
📦 典型场景: 消息队列(Kafka / RocketMQ / RabbitMQ)重复投递。
💡 做法:
记录已消费的 messageId 或 offset,重复消息直接跳过。
Kafka 还支持 事务性生产 + 幂等消费:
Producer 端带事务 ID,Consumer 提交 offset 时保证“生产消费一致性”。
🧠 优点: 在消息系统内部实现端到端幂等。
⚠️ 注意: 实际效果通常为 “At-least-once + 幂等消费”,完全的 Exactly-once 成本极高。
⑥ 缓存控制:去重 + TTL(Redis 防抖锁)
📦 典型场景: 高频点击、接口防抖、防重复下单。
💡 做法:
利用 Redis 原子操作实现短期幂等:
SETNX order:lock:123 true EX 30
若返回 OK → 首次执行;
否则说明已有操作在执行。
🧠 优点: 性能高、实现简单。
⚠️ 注意: Redis 宕机会失效,仅适合临时控制。
⑦ 事件总线级:事件幂等(Event Idempotency)
📦 典型场景: 微服务间事件驱动架构中,事件重放或重试。
💡 做法:
为每个事件附加全局唯一 eventId,在事件消费者端记录处理状态(数据库 / Redis)。
消费者逻辑:
收到事件,检查 eventId 是否已处理;
若已处理 → 跳过;
若未处理 → 执行业务并标记完成。
🧠 优点: 事件重放、补偿场景下保持一致性。
⚠️ 注意: 事件幂等要与事件溯源机制配合使用(Event Sourcing)。
|
|
|
|
|
|
|---|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
🧭 四、总结
幂等性不是一个功能点,而是一种系统稳定性设计哲学。
它存在于:
请求入口的「防重复提交」
数据存储的「唯一约束」
消息流通的「去重机制」
乃至事件总线的「一致性重放」
真正的架构师,应该在系统设计的每个环节都考虑幂等性。
💬 写在最后
在真实的分布式世界中,失败与重试是常态,幂等是优雅地应对混乱的艺术。

