接口幂等性设计
2021年某支付平台的退款接口被用户恶意利用:用户抓住退款请求,在1秒内提交了20次同样的退款申请。
系统没有做幂等处理,20次退款申请全部被处理,用户退了20倍的钱。
这次事件导致平台损失了约8万元。
接口幂等性是分布式系统中最基础也最重要的设计之一。
【面试官手记】
接口幂等性是生产环境最常见的安全问题之一。我面试过的候选人里,能说清楚"幂等性实现方案"的不超过40%,能说出"防重复提交"具体实现的不超过20%。幂等性的关键是理解幂等的场景和选择合适的方案。
一、幂等性的四个场景 🔴
1.1 四大场景
1.2 幂等性等级
1.3 面试追问
面试官:接口幂等性怎么实现?
候选人:四种方案:
一是基于唯一键:订单号、请求ID作为唯一索引
二是基于Token:提交前获取Token,提交时校验
三是基于状态机:订单状态只能正向流转
四是基于防重表:用Redis或数据库记录已处理的ID
【面试官心理】
幂等性的追问通常很务实。能回答出四种方案的候选人,说明知道全貌;能说出各方案适用场景的候选人,说明有实战经验。
二、唯一键幂等 🔴
2.1 原理
2.2 代码实现
三、Token幂等 🟡
3.1 原理
3.2 代码实现
四、状态机幂等 🟡
4.1 原理
4.2 代码实现
五、防重表幂等 🟡
5.1 原理
5.2 代码实现
六、生产避坑 🟡
6.1 幂等性的五大坑
坑1:Token校验后不删除
坑2:唯一键冲突不回滚
坑3:超时导致重复执行
坑4:分布式环境下唯一键不可靠
坑5:状态机流转判断不严谨
七、真实面试回放 🟡
面试官:支付接口怎么保证幂等性?
候选人(小张):三种方案:
一是基于订单号。支付请求携带订单号,数据库设置唯一索引。重复支付时唯一键冲突,直接返回。
二是基于支付流水号。第三方支付回调时携带流水号,用流水号做幂等。
三是基于状态机。订单状态只有"待支付"才能支付,其他状态直接返回幂等成功。
面试官:第三方支付回调怎么保证幂等?
小张:两个步骤:
一是查支付流水表。如果流水号已存在,说明已处理,直接返回成功。
二是插入防重记录。用第三方返回的支付流水号做唯一键,插入数据库。
面试官:前端重复提交怎么防止?
小张:用Token方案。
用户点击提交时,先请求后端获取Token。提交时携带Token,后端用Redis的SETNX原子校验并删除。
如果Token已存在(被删除过),说明已提交过,拒绝。
【面试官手记】
小张这场面试的亮点:
知道幂等性的三个实现方案:唯一键、状态机、Token
知道第三方回调的幂等处理
知道Token的Redis原子操作
幂等性是P6工程师必备技能,能完整回答的候选人,说明有实际项目经验。
接口幂等性的核心是根据场景选择合适方案。记住四个要点:
- 唯一键:创建类操作,用数据库唯一索引
- Token:表单提交,用Redis原子操作
- 状态机:状态流转,用状态判断
- 防重表:复杂业务,用防重表记录
幂等性是系统安全的基础,不能心存侥幸。