共计 1981 个字符,预计需要花费 5 分钟才能阅读完成。
背景与痛点
在微服务架构中,服务间的调用往往通过网络进行,这就不可避免地会遇到网络不稳定、超时等问题。当客户端未收到响应时,通常会进行重试,这就可能导致接口被重复调用。如果接口不具备幂等性,就会引发资损问题。

典型的场景包括:
- 订单支付接口被重复调用,导致用户被多次扣款
- 库存扣减接口被重复调用,导致库存超卖
- 优惠券领取接口被重复调用,导致用户获取多张优惠券
这些问题不仅影响用户体验,还可能给企业带来直接的经济损失。因此,确保接口的幂等性是微服务设计中必须考虑的要点。
幂等性解决方案对比
常见的幂等性解决方案主要有以下几种:
- Token 机制
- 客户端在调用接口前先获取一个唯一 Token
- 服务端校验 Token 有效性后执行操作
- 优点:实现简单,适用于大多数场景
-
缺点:需要额外的 Token 存储和校验
-
状态机
- 通过业务状态流转控制操作是否可执行
- 优点:与业务逻辑紧密结合
-
缺点:实现复杂,需要完整的状态设计
-
唯一索引
- 通过数据库唯一索引防止重复数据
- 优点:实现简单
-
缺点:仅适用于创建类操作,不能覆盖所有场景
-
乐观锁
- 通过版本号控制并发修改
- 优点:性能较好
- 缺点:需要额外字段,不适用于所有场景
综合比较后,Token 机制因其普适性和易于实现的特点,成为大多数场景下的首选方案。
核心实现方案
1. 分布式 Token 服务
使用 Open Code Skill 构建的 Token 服务主要包含以下组件:
- Token 生成器:负责生成全局唯一 Token
- Token 存储器:使用 Redis 存储 Token 及其状态
- Token 校验器:验证 Token 有效性并执行相应操作
2. Spring Boot 拦截器实现
以下是核心代码实现:
/**
* 幂等性拦截器
*/
public class IdempotentInterceptor implements HandlerInterceptor {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 从请求头中获取 Token
String token = request.getHeader("Idempotent-Token");
if (StringUtils.isEmpty(token)) {throw new BusinessException("缺少幂等 Token");
}
// 使用 Lua 脚本保证原子性操作
String luaScript = "if redis.call('get', KEYS[1]) == ARGV[1] then" +
"return redis.call('del', KEYS[1])" +
"else return 0 end";
Long result = redisTemplate.execute(new DefaultRedisScript<>(luaScript, Long.class),
Collections.singletonList(token),
"1");
if (result == 0) {throw new BusinessException("重复请求或 Token 已失效");
}
return true;
}
}
3. Redis 原子操作
为了保证并发安全,我们使用 Lua 脚本实现原子操作:
-- 检查并删除 Token 的 Lua 脚本
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end
性能考量
- Token 有效期
- 有效期过短会增加 Token 获取频率
- 有效期过长会占用更多 Redis 内存
-
建议:根据业务特点设置合理有效期(通常 30 秒 - 5 分钟)
-
Redis 集群部署
- 单节点 Redis 可能成为性能瓶颈
- 建议使用 Redis 集群提高吞吐量
- 考虑使用 Redis 分片减轻单节点压力
避坑指南
- 网络超时处理
- 客户端超时后应查询业务状态而非直接重试
-
服务端应提供状态查询接口
-
Token 池耗尽问题
- 实现 Token 回收机制
- 采用动态调整的 Token 生成策略
- 监控 Token 使用率,提前预警
思考题
在秒杀等高并发场景中,Token 生成可能成为性能瓶颈。可以考虑以下优化方案:
- 预生成 Token 池,减少实时生成压力
- 使用本地缓存 +Redis 多级缓存
- 优化 Token 生成算法,提高生成效率
期待您在评论区分享更多优化思路和实践经验!
总结
通过 Open Code Skill 实现的幂等性解决方案,我们有效解决了微服务架构中的重复请求问题。该方案具有以下特点:
- 实现简单,易于集成
- 性能良好,可扩展性强
- 适用于大多数业务场景
在实际应用中,还需要根据具体业务需求进行适当调整和优化。希望本文能为您的微服务架构设计提供有价值的参考。
