当前位置: 首页 > news >正文

10. 软件设计架构-经典架构问题-幂等+限流


前言

幂等性

在高并发场景的架构里,防止重复提交的幂等性是必须要保证的。

比如说支付功能,用户发起支付,如果后台没有做幂等校验,刚好用户手抖多点了几下,于是后台就可能多次受到同一个订单请求,不做幂等很容易就让用户重复支付了,这样用户体验是无法忍受的。


一、分布式接口幂等性(核心)

1. 什么是幂等

一个接口执行多次,结果和执行一次完全一致场景:重复提交、网络重试、超时重发、MQ重复消费

2. 常用4种幂等方案(流程图)

整体流转图

四种主流方案

  1. 全局Token令牌(前端拦截,最常用)

  2. 唯一业务主键(订单号、流水号 唯一索引)

  3. Redis分布式锁 + 防重标记

  4. MQ消费:消息唯一ID + 幂等表

3. 代码案例:Token令牌幂等(SpringBoot+Redis)

步骤

  1. 前端先获取唯一幂等Token

  2. 提交业务请求携带Token

  3. 接口拦截器校验Token,删除/标记

  4. 重复请求直接拦截

// 1. 生成幂等Token@RestController@RequestMapping("/idempotent")publicclassIdempotentController{@AutowiredprivateStringRedisTemplateredisTemplate;// 获取幂等Token@GetMapping("/getToken")publicRgetToken(){Stringtoken=UUID.randomUUID().toString();// 过期时间10分钟redisTemplate.opsForValue().set("idempotent:token:"+token,"1",10,TimeUnit.MINUTES);returnR.ok(token);}}

自定义注解 + 拦截器

@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public@interfaceIdempotent{}
@ComponentpublicclassIdempotentInterceptorimplementsHandlerInterceptor{@AutowiredprivateStringRedisTemplateredisTemplate;@OverridepublicbooleanpreHandle(HttpServletRequestrequest,HttpServletResponseresponse,Objecthandler){// 非注解方法直接放行if(!(handlerinstanceofHandlerMethod)){returntrue;}HandlerMethodmethod=(HandlerMethod)handler;if(!method.hasMethodAnnotation(Idempotent.class)){returntrue;}// 获取请求头TokenStringtoken=request.getHeader("idempotent-token");if(StringUtils.isEmpty(token)){thrownewRuntimeException("非法请求,缺少幂等令牌");}Stringkey="idempotent:token:"+token;// 原子操作:删除成功=第一次请求;删除失败=重复请求Booleandelete=redisTemplate.delete(key);if(Boolean.FALSE.equals(delete)){thrownewRuntimeException("请求重复提交,禁止重复操作");}returntrue;}}

业务接口使用

@PostMapping("/submit")@IdempotentpublicRsubmitOrder(){// 正常下单业务returnR.ok("下单成功");}

二、限流体系总览

限流3种实现层级

  1. 应用层单机限流:Guava RateLimiter(单机、简单)

  2. 网关层分布式限流:Nginx+Lua(全局、高性能)

  3. 分布式中间件限流:Sentinel/Redis+Lua(微服务常用)

限流核心算法


三、Guava 单机限流(令牌桶)

1. 流程图

2. 引入依赖

<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>31.1-jre</version></dependency>

3. 完整代码案例

@RestController@RequestMapping("/limit")publicclassGuavaLimitController{// 每秒放行 5 个请求:令牌桶容量=5privatestaticfinalRateLimiterRATE_LIMITER=RateLimiter.create(5.0);@GetMapping("/guava")publicRguavaLimit(){// 尝试获取令牌,非阻塞booleanacquire=RATE_LIMITER.tryAcquire();if(!acquire){returnR.error("系统繁忙,请求限流,请稍后重试");}returnR.ok("请求正常处理");}}

特点


四、Nginx + Lua 分布式限流(生产常用)

1. 架构流程图

2. 实现原理

3. Nginx + Lua 完整配置

1)Nginx 配置nginx.conf

http { # 加载lua脚本 lua_package_path "/usr/local/nginx/lua/?.lua;;"; server { listen 80; server_name localhost; location /api/ { # 执行限流lua脚本 access_by_lua_file /usr/local/nginx/lua/limit.lua; # 转发后端服务 proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; } } }

2)Lua脚本limit.lua(Redis滑动窗口限流)

-- 连接redislocalredis=require"resty.redis"localred=redis:new()red:set_timeout(1000)localok,err=red:connect("127.0.0.1",6379)ifnot okthenngx.log(ngx.ERR,"redis连接失败: ",err)returnend-- 限流参数locallimit_key="nginx:limit:api"localnow=ngx.time()localwindow=60-- 时间窗口:60秒localmax_count=100-- 单窗口最大请求数-- 1. 移除窗口外过期数据red:zremrangebyscore(limit_key,0,now-window)-- 2. 统计当前窗口请求数localcount=red:zcard(limit_key)iftonumber(count)>=max_countthen-- 触发限流,直接返回ngx.status=429ngx.say("{\"code\":429,\"msg\":\"请求过于频繁,已被限流\"}")ngx.exit(429)end-- 3. 记录当前请求red:zadd(limit_key,now,now..math.random())red:expire(limit_key,window)

4. 特点


五、三种方案横向对比(面试必背)

限流方案底层范围性能适用场景
Guava RateLimiter令牌桶单机极高单体项目、简单内部接口
Nginx+LuaRedis+滑动窗口分布式全局超高对外API、网关统一限流
Sentinel滑动窗口微服务分布式SpringCloud 微服务体系

六、面试高频总结

  1. 幂等核心:唯一标识 + 防重存储(Redis/DB)

  2. Guava局限:只能单机,集群必须用Redis分布式限流

  3. Nginx+Lua优势:网关层限流,拦截在最外层,保护后端

  4. 幂等+限流组合:先限流、后幂等,系统稳定性最强


本文的引用仅限自我学习如有侵权,请联系作者删除。
参考知识
分布式接口幂等性、分布式限流:Guava、nginx和lua限流


http://www.jsqmd.com/news/698806/

相关文章:

  • 5步解锁SillyTavern:从AI对话新手到角色扮演大师
  • 佛山粤利通市政工程:茂名可靠的沥青摊铺公司选哪家 - LYL仔仔
  • CXPatcher:Mac游戏玩家必备的CrossOver一键优化终极指南
  • 如何通过Spotify-Downloader高效管理个人音乐收藏
  • 视频孪生重构轨交数字孪生新范式|黎阳之光以自主核心技术破解落地难题
  • 嵌入式固件烧录总失败?VSCode 2026新插件已上线,自动识别芯片ID、修复Flash校验偏移、智能重试机制全解析
  • 2026年主流服装POS系统哪家强?功能、场景、适用规模全维度横评
  • Opik开源LLM应用观测平台:从追踪、评估到生产监控全链路实践
  • 互联网大厂Java面试官技术题场景与深度解析
  • 2026年养老房机构口碑推荐榜/乡村养老房,电梯养老房,居家养老房康养房,度假房 - 品牌策略师
  • 保姆级教程:手把手教你用Netplan为Ubuntu 20.04虚拟机配置双网卡(静态IP+桥接/NAT)
  • Klipper实战:5步搞定3D打印共振消除,提升打印质量90%
  • CSS选择器高级用法:精准控制样式
  • 基于Fossen模型的无人艇轨迹跟踪文献复现与仿真研究:MATLAB与Simulink仿真实践
  • 5分钟快速上手:Newtonsoft.Json完整配置指南
  • 2026年浙江网络营销与GEO推广全链路解决方案深度指南 - 优质企业观察收录
  • 单机承载200万长连接的C++ MCP网关架构(Linux内核参数/Socket选项/RAII资源治理全披露)
  • 机器学习实验系统化管理:提升效率与复现性
  • 终极指南:如何用Talebook搭建你的私人数字图书馆
  • 别只盯着界面汉化!Origin软件深度配置:从语言包原理到自定义工作区的中文化完整流程
  • 【ETestDEV5教程40】代码开发之AI功能支持
  • 神经网络训练困难解析:优化视角与实战策略
  • LFM2.5-VL-1.6B实操手册:nvidia-smi显存监控+GPU利用率实时观测技巧
  • 2026榆林德系口腔医生阿栋梁专业诊疗服务解析 - 品牌排行榜
  • LizzieYzy:围棋AI分析的终极免费工具,快速提升棋力的完整指南
  • 为什么92%的企业沙箱隔离形同虚设?MCP 2026动态策略引擎的6层上下文感知机制深度拆解
  • MAA助手:明日方舟玩家的终极自动化解决方案
  • 2026年氧化镁厂家推荐:活性氧化镁//液体氢氧化镁/氢氧化镁专业供应 - 品牌推荐官
  • 揭秘输出反灌电流ZVS反激:低成本实现软开关的工程实践
  • OpenCore Legacy Patcher技术革新指南:让旧Mac焕发新生的完整方案