Redisson 分布式限流 + 分布式幂等完整实现
以下代码均基于 Redisson 原生 API底层全部通过 Lua 脚本保证原子性可直接接入 Spring Boot 生产项目。一、分布式限流实现提供两种生产最常用的限流方案分别对应QPS 速率控制和并发数控制两类场景。1. 令牌桶限流RRateLimiter接口 QPS 限流首选基于令牌桶算法实现原子化完成令牌生成与消耗支持平滑限流、应对突发流量是接口级限流的最优方案。适用场景接口 QPS 限制、用户级调用频次控制、第三方接口调用限流。工程化封装注解 AOP第一步自定义限流注解Target(ElementType.METHOD) Retention(RetentionPolicy.RUNTIME) public interface ApiRateLimiter { // 限流业务key String key(); // 限流模式OVERALL全局总限流PER_CLIENT每个客户端独立限流 RateType mode() default RateType.OVERALL; // 单位时间内生成的令牌总数 long rate() default 10; // 时间单位 RateIntervalUnit timeUnit() default RateIntervalUnit.SECONDS; // 单次请求消耗令牌数 int permits() default 1; // 限流提示语 String msg() default 系统繁忙请稍后重试; }第二步AOP 切面实现Aspect Component public class RateLimiterAspect { Resource private RedissonClient redissonClient; Around(annotation(limiter)) public Object around(ProceedingJoinPoint joinPoint, ApiRateLimiter limiter) throws Throwable { // 组装限流key按用户限流可自行拼接userId String limitKey limit: limiter.key(); RRateLimiter rateLimiter redissonClient.getRateLimiter(limitKey); // 幂等初始化限流器重复调用不覆盖配置 rateLimiter.trySetRate(limiter.mode(), limiter.rate(), 1, limiter.timeUnit()); // 原子获取令牌成功则执行业务 boolean allow rateLimiter.tryAcquire(limiter.permits()); if (!allow) { throw new BusinessException(limiter.msg()); } return joinPoint.proceed(); } }业务使用示例// 示例1全局接口限流每秒最多20次下单请求 ApiRateLimiter(key order:create, rate 20, msg 下单人数过多请稍后重试) public String createOrder(OrderDTO dto) { // 下单业务逻辑 return ORD System.currentTimeMillis(); } // 示例2按用户限流每个用户每分钟最多调用5次查询接口 // 注按用户限流需将userId拼入key可在AOP中从上下文获取userId动态拼接 ApiRateLimiter(key user:query:order, rate 5, timeUnit RateIntervalUnit.MINUTES) public ListOrderVO queryOrderList(Long userId) { // 查询业务逻辑 return Collections.emptyList(); }关键说明RateType.OVERALL集群所有节点共享总速率适合全局接口限流。按用户 / 租户限流将用户 ID 拼入限流 key每个用户对应独立限流器实现隔离。令牌桶容量默认等于速率值支持突发流量一次性消耗存量令牌。2. 并发数限流RSemaphore 信号量基于分布式信号量控制同时持有许可的线程总数即同一时间最多有多少个线程执行指定业务。适用场景限制并发执行的任务数如导出、批量处理、保护下游资源数据库、第三方接口。工具类封装Component public class ConcurrentLimitUtil { Resource private RedissonClient redissonClient; /** * 尝试获取并发许可 * param resourceKey 资源标识 * param maxConcurrent 最大并发数 * return true获取成功false并发已满 */ public boolean tryAcquire(String resourceKey, int maxConcurrent) { RSemaphore semaphore redissonClient.getSemaphore(concurrent: resourceKey); semaphore.trySetPermits(maxConcurrent); return semaphore.tryAcquire(); } /** * 释放并发许可必须在finally中调用 */ public void release(String resourceKey) { redissonClient.getSemaphore(concurrent: resourceKey).release(); } }业务使用示例public void exportOrderData() { String resourceKey export:order; // 限制同时最多3个导出任务 if (!concurrentLimitUtil.tryAcquire(resourceKey, 3)) { throw new BusinessException(当前导出任务过多请稍后再试); } try { // 执行导出业务 doExportExcel(); } finally { // 必须释放许可防止泄露 concurrentLimitUtil.release(resourceKey); } }二、分布式幂等实现提供两种主流幂等方案分别对应前端表单防重和后端业务防重两类场景。1. 令牌式幂等表单 / 接口防重复提交前端进入页面前申请唯一令牌提交时携带令牌服务端原子校验并删除令牌校验通过才执行业务。适用场景表单重复提交、按钮重复点击、前端接口防重。工具类封装Component public class IdempotentTokenService { Resource private RedissonClient redissonClient; private static final String TOKEN_PREFIX idempotent:token:; private static final long TOKEN_EXPIRE_MINUTES 5; /** * 生成幂等令牌 * param bizId 业务标识如用户ID隔离不同主体 * return 令牌字符串 */ public String generateToken(String bizId) { String token UUID.randomUUID().toString().replace(-, ); RBucketString bucket redissonClient.getBucket(TOKEN_PREFIX bizId); bucket.set(token, TOKEN_EXPIRE_MINUTES, TimeUnit.MINUTES); return token; } /** * 原子校验并删除令牌 * return true校验通过false令牌无效/已使用 */ public boolean checkAndRemove(String bizId, String token) { String key TOKEN_PREFIX bizId; Long result redissonClient.getScript().eval( RScript.Mode.READ_WRITE, if redis.call(GET, KEYS[1]) ARGV[1] then return redis.call(DEL, KEYS[1]) else return 0 end, RScript.ReturnType.INTEGER, Collections.singletonList(key), token ); return result ! null result 1; } }业务使用流程// 1. 前端进入页面时获取令牌 GetMapping(/token/get) public ResultString getToken(RequestParam Long userId) { return Result.success(idempotentTokenService.generateToken(userId.toString())); } // 2. 提交接口校验令牌 PostMapping(/order/submit) public ResultString submitOrder( RequestHeader(idempotent-token) String token, RequestBody OrderDTO dto ) { boolean valid idempotentTokenService.checkAndRemove(dto.getUserId().toString(), token); if (!valid) { return Result.fail(请勿重复提交); } // 执行业务 String orderNo orderService.createOrder(dto); return Result.success(orderNo); }2. 业务唯一键幂等后端回调 / 消息防重以业务唯一标识作为幂等键原子加锁并保留有效期有效期内相同业务号直接拒绝重复处理。适用场景支付回调、MQ 消息重复消费、接口重试防重、重复下单控制。工具类封装Component public class BizIdempotentService { Resource private RedissonClient redissonClient; private static final String KEY_PREFIX idempotent:biz:; private static final long DEFAULT_EXPIRE_MINUTES 30; /** * 尝试获取幂等锁 * param bizType 业务类型如PAY_CALLBACK、ORDER_CREATE * param bizNo 业务唯一单号 * param expireMinutes 幂等有效期 * return true首次请求false重复请求 */ public boolean tryIdempotent(String bizType, String bizNo, long expireMinutes) { String lockKey KEY_PREFIX bizType : bizNo; RLock lock redissonClient.getLock(lockKey); try { // 等待时间为0立即返回结果持有时间为幂等有效期 return lock.tryLock(0, expireMinutes, TimeUnit.MINUTES); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return false; } } public boolean tryIdempotent(String bizType, String bizNo) { return tryIdempotent(bizType, bizNo, DEFAULT_EXPIRE_MINUTES); } /** * 手动释放幂等锁业务处理失败时调用允许后续重试 */ public void releaseIdempotent(String bizType, String bizNo) { RLock lock redissonClient.getLock(KEY_PREFIX bizType : bizNo); if (lock.isHeldByCurrentThread()) { lock.unlock(); } } }业务使用示例支付回调public void handlePayCallback(PayCallbackDTO callback) { // 支付流水号作为唯一键幂等有效期30分钟 boolean isFirst bizIdempotentService.tryIdempotent(PAY_CALLBACK, callback.getPayNo(), 30); if (!isFirst) { log.info(重复支付回调直接忽略流水号{}, callback.getPayNo()); return; } try { // 执行业务更新订单状态、记账、发货等 updateOrderPayStatus(callback.getOrderNo()); doFinancialAccounting(callback); } catch (Exception e) { // 业务处理失败释放幂等锁允许后续重试 bizIdempotentService.releaseIdempotent(PAY_CALLBACK, callback.getPayNo()); throw e; } }生产避坑要点幂等与分布式锁的区别分布式锁执行完立即释放控制并发幂等锁执行后保留有效期控制重复请求二者不可混用。令牌校验必须原子禁止先 GET 判断再 DEL 删除并发下会出现重复通过必须用 Lua 脚本原子执行。信号量必须释放并发限流的许可必须在 finally 中释放否则许可泄露会导致后续请求永远无法获取。幂等键唯一性业务幂等的唯一单号必须全局唯一建议前缀 业务类型 业务号组合避免不同业务冲突。

相关新闻

图形验证码接入效率与长期运维成本综合评估:自建方案与企讯通Qcaptcha等第三方服务的全链路对比

图形验证码接入效率与长期运维成本综合评估:自建方案与企讯通Qcaptcha等第三方服务的全链路对比

在互联网安全防护体系中,图形验证码始终扮演着"守门人"的关键角色。无论是账号登录、表单提交还是抢购下单,它都站在业务入口的第一线,拦截恶意攻击、暴力破解与批量请求。当前,企业在部署验证码能力时,通常…

2026/7/9 11:46:27阅读更多 →
LWC 生命周期钩子全解

LWC 生命周期钩子全解

LWC 生命周期钩子全解(Lightning Web Component) LWC 生命周期分为组件创建渲染、更新、销毁三大阶段,共 6 个核心钩子,分为父组件先执行、子组件后执行的自上而下初始化,更新时自下而上更新。 一、完整生命周期钩子列…

2026/7/9 11:46:27阅读更多 →
水利遥测终端机在水文防汛中的应用价值与发展方向

水利遥测终端机在水文防汛中的应用价值与发展方向

作为水文防汛的“数字哨兵”,水利遥测终端机的推广应用,从根本上改变了我国水文防汛监测的模式,带来了三个方面的核心价值:一是大幅提升了水雨情监测的时效性和准确性,为洪水预报预警提供了精准的基础数据,…

2026/7/9 11:46:27阅读更多 →
第十三届国际能源工程与环境工程会议(ICEEEE 2026)

第十三届国际能源工程与环境工程会议(ICEEEE 2026)

会议简介第13届能源工程与环境工程国际会议(ICEEEE 2026)将于2026年12月4日至6日在澳大利亚,珀斯举行。ICEEEE作为能源与环境领域的重要国际学术交流平台,已成功举办多届,吸引了来自全球各地的专家、学者和研究人员参与…

2026/7/9 13:01:44阅读更多 →
Linux用户管理与文件权限实操实验

Linux用户管理与文件权限实操实验

一、实验概述 本次实验主要学习Linux系统用户及用户组管理,掌握用户创建、信息修改、用户组配置、文件权限管控相关命令。理解Linux系统安全机制,学会通过 chmod 、 chown 设置文件权限,实现组内文件共享,熟悉/etc/passwd用户信息…

2026/7/9 13:01:44阅读更多 →
工业负载控制方案:TPD2017FN与PIC18F4610的智能应用

工业负载控制方案:TPD2017FN与PIC18F4610的智能应用

1. 项目概述:工业环境中的负载控制方案在工业自动化领域,精确控制电感和电阻负载是许多关键应用的基础需求。本项目采用德州仪器(TI)的TPD2017FN智能高侧开关与Microchip的PIC18F4610微控制器组合,构建了一套可靠的负载…

2026/7/9 13:01:44阅读更多 →
写小说卡文怎么办?2026最新写小说软件排行榜,第2款好用到离谱!

写小说卡文怎么办?2026最新写小说软件排行榜,第2款好用到离谱!

写小说最怕啥?卡文。还有就是花时间试了半天,结果工具完全不对路。市面上的AI写小说软件一抓一大把,但能真正在创作里帮上忙的,其实没几个。 这次我挑了10款常见的工具,从功能、体验和适合人群三个角度来聊一聊&#…

2026/7/9 13:01:44阅读更多 →
L9958与MKV46F128VLH16的电机控制方案设计与实现

L9958与MKV46F128VLH16的电机控制方案设计与实现

1. 项目概述:L9958与MKV46F128VLH16的强强联合在电机控制领域,实现高性能、高可靠性的解决方案一直是工程师追求的目标。L9958作为意法半导体(ST)推出的多通道电机驱动芯片,与恩智浦(NXP)的MKV46F128VLH16微控制器组合,能够为直流…

2026/7/9 13:01:44阅读更多 →
TLCPGMSSL协议及Wireshark抓包详解

TLCPGMSSL协议及Wireshark抓包详解

一、TLCP/GMSSL 概念 TLCP 是国家标准协议(GB/T 38636-2020/GM/T 0024-2014),非标准叫法也有叫GMSSL协议的,这个和GMSSL开源库( 实现TLCP协议的开源密码库名称)容易造成混淆,所以标准的统一名称应为 TLCP协…

2026/7/9 12:56:44阅读更多 →
从GitHub安全案例解析常见漏洞与防护实践

从GitHub安全案例解析常见漏洞与防护实践

1. 项目概述:从GitHub Trending看安全实战 最近在GitHub Trending上看到一个项目,叫 skills4/skills ,它因为一些安全漏洞案例被大家讨论。这其实是一个挺典型的场景:一个旨在展示或教授某种技能的仓库,本身却成了安…

2026/7/9 5:56:19阅读更多 →
MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

MLT 2026启示:因果推理与概率建模驱动下一代LLM应用

# MLT 2026启示:因果推理与概率建模驱动下一代LLM应用## 一、背景与挑战:从“黑箱预测”到“可信推理”2026年6月,第7届机器学习与趋势国际会议(MLT 2026)将在悉尼召开。会议议程中,“因果与可解释机器学习…

2026/7/9 9:45:20阅读更多 →
通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

通达OA SQL注入漏洞深度剖析:从手工注入到自动化利用与防御

1. 项目概述与漏洞背景最近在梳理一些历史OA系统的安全风险时,通达OA v11.6版本中的一个老漏洞又进入了我的视线。这个漏洞位于/general/bi_design/appcenter/report_bi.func.php文件中,是一个典型的SQL注入点。虽然这个漏洞的利用方式看起来并不复杂&am…

2026/7/9 2:47:07阅读更多 →
Three.js 着色器光效教程

Three.js 着色器光效教程

着色器光效 Shader Light ▶ 在线运行案例 案例合集: 三维可视化功能案例(threehub.cn)开源仓库github地址: https://github.com/z2586300277/three-cesium-examples400个案例代码: 网盘链接 你将学到什么 ShaderMaterial 自…

2026/7/9 0:04:37阅读更多 →
如何5分钟掌握CS2智能库存管理:开源工具CASEMOVE终极指南

如何5分钟掌握CS2智能库存管理:开源工具CASEMOVE终极指南

如何5分钟掌握CS2智能库存管理:开源工具CASEMOVE终极指南 【免费下载链接】casemove A dedicated desktop app that enables you to move items in and out of storage units in CS2. 项目地址: https://gitcode.com/gh_mirrors/ca/casemove 还在为CS2存储单…

2026/7/9 0:04:37阅读更多 →
GBase 8a vs MySQL 8.0:ALTER TABLE语法与限制的5点关键差异对比

GBase 8a vs MySQL 8.0:ALTER TABLE语法与限制的5点关键差异对比

GBase 8a与MySQL 8.0:ALTER TABLE语法差异深度解析与实战指南1. 两种数据库的ALTER TABLE能力全景对比在数据库架构设计和运维过程中,表结构变更(DDL操作)是不可避免的需求。GBase 8a作为国产分析型数据库代表,与开源M…

2026/7/9 0:04:37阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/9 9:45:20阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/8 13:42:39阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/8 13:42:39阅读更多 →