资讯动态

后端开发中,接口幂等和重试怎么设计

发布时间:2026/10/3 12:35:57 来源:尧图企业网站定制
线上事故里最冤的一类是用户点了一次“支付”扣了两次款。你查日志前端只发了一次请求可后端处理了两遍。问题出在重试上。网络抖动、超时、负载均衡重发任何一个环节都可能让同一个请求抵达两次。幂等和重试是一对孪生问题设计不好轻则数据错乱重则资金损失。幂等不是可选项是底线幂等的定义很简单同一个请求执行一次和执行多次对系统产生的影响相同。查询天然幂等删一次和删十次结果一样。但插入和更新不是。用户下单插一条订单记录重试一次就多一条。用户支付账户扣款重试一次就多扣一笔。不是所有接口都需要幂等但涉及资金、库存、订单、状态流转的接口幂等是底线。判断标准这个操作重复执行业务上能不能接受不能接受就必须做幂等。唯一键是最简单也最可靠的方案数据库唯一索引是幂等的第一道防线。给订单号、支付流水号加唯一约束插入时重复直接报错捕获异常返回已有结果。这个方案简单、可靠、无额外依赖。数据库的唯一性约束是最后一道锁任何应用层的幂等设计都要以它兜底。缺点是高并发下频繁冲突会影响性能适合并发量不是极端的场景。如果并发极高可以在唯一键基础上加Redis做前置拦截减少数据库压力。Token机制一次一用用完即废客户端先申请一个Token服务端存起来。提交请求时带上Token服务端校验并删除。第二次带着同一个Token来校验失败直接拒绝。Token的本质是一次性凭证核心在于“校验和删除”必须原子。用Redis的SETNX或者Lua脚本保证原子性别用先查后删的写法并发下会漏。Token适合表单提交、支付确认这类用户主动触发的操作。申请Token有成本不是所有接口都值得用。状态机让重复请求无路可走订单状态从“待支付”到“已支付”这是一个单向流转。重复请求进来时先查当前状态已经是“已支付”就直接返回不再执行扣款。状态机幂等的核心是判断“这件事是否已经做过”而不是“这个请求是否来过”。它把幂等的判断从请求层提升到了业务层更贴近业务本质。设计状态机时每个状态流转都要明确前置条件不满足条件的操作一律拒绝。这个方案适合有明确状态流转的业务比如订单、工单、审批流。重试不是越多越好要有策略重试分两种客户端重试和服务端重试。客户端重试要控制次数和间隔别用固定间隔用指数退避。第一次等1秒第二次2秒第三次4秒避免瞬间打爆服务端。重试必须设上限无限重试等于自杀。服务端重试更危险尤其是跨服务的调用。A调B超时了A重试B可能已经处理成功只是响应丢了。这时候重试就产生了重复。所以服务端重试必须配合幂等没有幂等的重试是灾难。重试的前提错误可恢复不是所有错误都值得重试。网络超时、连接被拒、服务暂时不可用这些可以重试。参数错误、权限不足、业务规则拒绝重试一万次结果一样。对不可恢复的错误重试是浪费资源对可恢复的错误不重试是放弃机会。区分这两类错误是重试设计的第一步。HTTP状态码可以帮你判断5xx可以重试4xx基本不用。但429限流要等一等再重试别硬冲。幂等键让重试有据可依客户端生成一个全局唯一的请求ID每次重试带上同一个ID。服务端用这个ID做幂等判断处理过就返回缓存结果。幂等键是重试和幂等之间的桥梁它让服务端能识别出“这是同一个请求”。生成规则要保证全局唯一UUID、雪花ID都可以。存储用Redis设一个合理的过期时间比如24小时。过期之后同一个ID再来说明是新的请求正常处理。落地建议分层设计最外层用网关做限流和基础校验第二层用Redis做Token或幂等键拦截第三层用数据库唯一键兜底。应用层的幂等是优化数据库层的唯一约束是保障。只靠应用层并发下会漏只靠数据库层冲突多了性能差。两层配合既快又稳。重试策略单独配置按接口区分别搞一刀切。核心接口重试三次非核心重试一次不可恢复的直接失败。幂等和重试说到底是分布式系统里对“不确定性”的应对。网络不可靠响应可能丢服务可能挂。你不能假设一切顺利你得假设一切都会出错。幂等是防守重试是进攻两者配合系统才能既稳又活。设计的时候多问一句如果这个请求来了两次会怎样想清楚这个问题大半的坑就避开了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑