架构师必备:限流方案选型(使用篇)

news/2025/10/27 8:44:17/文章来源:https://www.cnblogs.com/toplist/p/19137497

大家好,我是Java烘焙师。为了避免突增流量引起服务雪崩,需要对接口、存储资源做限流保护,根据系统负载情况设置合适的限流值。下面结合笔者的经验和思考,对主要限流方案的选型做一下总结,本篇先看如何使用,下一篇再看背后的原理。

下面介绍几种常见限流方案的使用方法、优缺点:

  • 单机限流:Guava RateLimiter
  • 同时支持单机限流、集群限流:Sentinel
  • 分布式限流:Redisson RateLimiter

1. 单机限流:Guava RateLimiter

使用

官网API文档:https://guava.dev/releases/snapshot-jre/api/docs/com/google/common/util/concurrent/RateLimiter.html

Guava是Google开源的Java类库,提供了很多实用的工具,包括集合、本地缓存、并发编程工具等。Guava RateLimiter就是其中的单机限流工具,核心概念如下:

  • 每秒允许通过的最大permits:
    • 当请求获取1个permit时,就相当于是qps限流
    • 当请求获取多个permits时,代表该请求需要消耗多少资源,比如想限定更新DB的SQL qps为1000,则需获取1000 permits
  • 支持预热:在预热期内逐步支持到最大permits,适用于需要预热缓存资源的场景
  • 允许突发流量:每次请求是否被限流,不取决于该次请求permits的多少,而是取决于前一次请求,前一次请求的permits越多,则后续请求需等待的时间越长
    • 比如有一个空闲的RateLimiter,第一次请求无论是获取1 permit、还是10000 permits,都能立刻成功,但是会计算出下一次permits可用的时间。那么第一次请求是10000 permits时,第二次请求即使只需10 permits也可能要长时间等待

如下分别是阻塞、非阻塞方式,使用Guava RateLimiter的示例。

    // 创建一个每秒允许10个permits的限流器RateLimiter rateLimiter = RateLimiter.create(10.0);// 1. 阻塞的方式long startTime = System.currentTimeMillis();// 获取5 permits;如果充足,则获取成功,否则阻塞等待rateLimiter.aquire(5);long endTime = System.currentTimeMillis();// 打印阻塞等待的时间System.out.println("Processing business logic. Waiting time ms: " + (endTime - startTime));// 2. 非阻塞的方式// 尝试获取1 permitif (rateLimiter.tryAcquire()) {// 如果能获取到令牌,则继续处理业务逻辑System.out.println("Processing business logic...");} else {// 否则快速失败,返回友好提示或执行降级逻辑System.out.println("Too many requests.");}

优点

  • 性能极高:纯计算,无网络开销
  • 实现简单

缺点

  • 无法跨实例协同,从整体层面控制限流

2. 同时支持单机限流、集群限流:Sentinel

使用

官网文档:https://sentinelguard.io/zh-cn/docs/introduction.html

Sentinel是阿里开源的流量治理组件,在国内使用较广泛。核心概念如下:

  • 资源:可以是接口(调入、调出均可),也可以是任何一段代码逻辑。可通过sentinel注解、或者sentinel API包装成受保护的资源
  • 规则:围绕资源的实时状态设定的规则,包括流量控制规则、熔断降级规则以及系统保护规则,所有规则都可以动态实时调整。
    • 常见的流量控制规则:
      • 限流阈值类型:支持QPS、线程数模式,默认是按QPS来限流
      • 流控效果:即超过限流阈值时的行为,支持直接拒绝、排队等待、慢启动模式,默认是直接拒绝
    • 常见的熔断降级规则:
      • 熔断策略:即在什么情况下熔断降级,支持慢调用比例、异常比例、异常数策略,默认是慢调用比例
      • 熔断阈值:慢调用比例模式下为慢调用的RT平均响应时间,异常比例/异常数模式下为对应的阈值
  • 集群限流:是为了解决流量在集群内各实例之间不均匀、导致触发单机限流,而达不到总QPS预期的问题。集群限流有2种模式:单机均摊、全局阈值,为了避免token server成为瓶颈,比较典型的是单机均摊。
    • 单机均摊:先设置一个集群限流阈值,然后再根据机器实例数均摊到单机上,即单机限流值=集群限流值/机器实例数
    • 全局阈值:集群流控中共有两种身份
      • Token Client:集群流控客户端,用于向所属 Token Server 通信请求 token。集群限流服务端会返回给客户端结果,决定是否限流
      • Token Server:即集群流控服务端,处理来自 Token Client 的请求,根据配置的集群规则判断是否应该发放 token(是否允许通过)

如下分别是通过sentinel注解、sentinel API方式的示例。

  • sentinel注解一般加在受保护的接口、访问存储资源的方法上
  • sentinel API更加灵活,可包住受保护的业务代码片段;更进一步,结合业务入参,可实现热点参数限流
    // 1. sentinel注解:在sentinel控制台上可针对定义的资源名配置限流规则@Service@SentinelResource(value = "protectedMethod")public String protectedMethod(Request request) {}// 2. sentinel API// 2.1 抛异常方式定义资源try (Entry entry = SphU.entry("protectedResource1")) {// 被保护的逻辑System.out.println("protected resource 1");} catch (BlockException ex) {// 处理被流控的逻辑System.out.println("blocked!");}// 2.2 返回布尔值方式定义资源if (SphO.entry("protectedResource2")) {// 务必保证finally会被执行try {// 被保护的业务逻辑} finally {SphO.exit();}} else {// 资源访问阻止,被限流或被降级// 进行相应的处理操作}// 2.3 热点参数限流try (Entry entry = SphU.entry("hotspotResource", EntryType.IN, 1, paramA, paramB)) {// 易出现热点参数的业务逻辑} catch (BlockException ex) {// 热点参数限流} finally {if (entry != null) {entry.exit(1, paramA, paramB);}}

优点

  • 易于与Java框架集成,提高应用开发效率:如Spring Cloud、Dubbo等
  • 功能强大:在控制台页面,可动态配置限流规则、熔断降级规则

缺点

  • sentinel的集群限流,在单机均摊模式下最终会换算为单机限流,当集群限流值较低、机器实例数较多时,计算出的单机限流值可能不准,无法精准控制总的集群限流
    • 例如:有100台机器,按30 qps来限流;则计算出的单机均摊qps不足1、按1处理,这样总的集群限流就变成了100 qps,大于预期的30 qps

3. 分布式限流:Redisson RateLimiter

使用

官网API文档:https://redisson.pro/docs/data-and-services/objects/#ratelimiter

Redisson是一个高性能的Redis客户端框架,提供了基于redis实现的分布式工具,如分布式集合、分布式锁、布隆过滤器等,借助Redisson RateLimiter可以实现分布式限流。核心概念如下:

  • 允许在一段时间间隔内,最多有n个permits通过
  • 通过redis lua脚本实现限流逻辑、以及原子操作

如下是使用Redisson RateLimiter的示例。

    // 使用Redisson的分布式限流器RRateLimiter limiter = redisson.getRateLimiter("myLimiter");// 限定每60秒100个permitslimiter.trySetRate(RateType.OVERALL, 100, 60, RateIntervalUnit.SECONDS);// 阻塞式获取5 permitslimiter.acquire(5);// 非阻塞式获取1 permitif (limiter.tryAcquire(1)) {// 获取到permit,执行业务逻辑} else {// 被限流}

优点

  • 基于redis实现了分布式限流,能较精准地控制低qps场景的限流
  • 与特定框架/限流组件无关

缺点

  • 引入了外部依赖,有网络开销,系统稳定性易受影响

其它分布式限流方案

笔者还了解到有一个redis模块 redis-cell 可做分布式限流。不过有以下问题,不是很建议使用:

  • 需要额外运维部署,成本较高
  • 项目由个人维护,目前已基本停滞

结论

  • Java应用开发,一般情况下,可引入Sentinel做接口、存储资源的限流控制
  • 单机任务,如手动执行或定期执行的task,可引入Guava RateLimiter做简易的限流控制
  • 低qps场景的限流、或不想接入特定框架/限流组件的服务,可引入Redisson RateLimiter来实现较精准的分布式限流控制

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/947215.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

10月第一篇

《程序员修炼之道》阅读笔记:第一阶段 程序员的“职业身份觉醒” 《程序员修炼之道:从小工到专家》开篇便抛出一个振聋发聩的命题:“你是一名专业人士,还是一个代码工人?” 这句话像一把钥匙,瞬间打开了我对 “程…

2025 年青岛点焊机厂家最新推荐榜,聚焦技术实力与市场口碑深度解析螺母/自动/螺栓/储能/汽车零部件点焊机厂家推荐

引言 当前青岛点焊机市场品牌繁杂,产品在适配性、工艺水平、智能控制及稳定性上差异显著,部分产品还存在价格虚高、售后保障不足等问题。汽车制造、家用电器、五金制品等领域企业,对高性能、高性价比的中频、螺母、…

日记12

今天聚焦 ArrayList 与 LinkedList 的底层差异,用“10万次增删查”测试验证性能区别,彻底跳出“只会用API”的误区。核心突破:搞懂了两者的本质区别—— ArrayList 基于动态数组,查询快(通过索引直接定位)但增删…

日记15

今天不再满足于“try-catch捕获异常”,而是深入理解异常体系,还动手写了第一个自定义异常,解决“业务错误无法用系统异常表达”的问题。关键收获:理清了 Checked Exception (编译时异常,如 IOException ,必须处…

Sqlite EF For ConsoleCore

SqliteEF For Asp.NetCore在跨平台开发中使用Sqlite EF 框架 1. 安装依赖包 install-package Microsoft.EntityFrameworkCore install-package EntityFrameworkCore.Sqlite install-package Microsoft.EntityFramework…

日记14

今天不再满足于“try-catch捕获异常”,而是深入理解异常体系,还动手写了第一个自定义异常,解决“业务错误无法用系统异常表达”的问题。关键收获:理清了 Checked Exception (编译时异常,如 IOException ,必须处…

日记16

今天正式进入多线程领域,用“卖票案例”重现了线程安全问题,再通过三种方案解决,终于理解了“并发”与“同步”的核心逻辑。核心实践:用三个线程模拟卖100张票,未加同步时出现“超卖”(卖出102张)和“重复卖”(…

三年级小学生日记范文

不知所云。也可以叫做补题日记(二)。 这个时候有人就要问了,“主播主播,你的《补题日记》《补题周记》《杂题不讲》《一些问题》《随便什么标题。》难道不更了吗?” 对此,我的回答是: A - JamBrains

easy-query暴打efcore(包括其他所有orm),隐式Group看我如何在子查询做到极致的性能天花板

easy-query暴打efcore(包括其他所有orm),隐式Group看我如何在子查询做到极致的性能天花板 介绍 文档地址 https://www.easy-query.com/easy-query-doc/ GITHUB地址 https://github.com/dromara/easy-query GITEE地址 …

完整教程:深入理解-自然拼读(英语)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

线程属性的相关设置详解 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

应用安全 --- 在线可执行文件分析

应用安全 --- 在线可执行文件分析https://www.unpac.me/results/556bdbc0-32f7-467f-ad28-42d5cf9112be

Git本地与远程SSH连接配置

一、查看Git用户名/密码/邮箱,及设置git配置 1、查看信息:查看用户名 :git config user.name查看密码: git config user.password查看邮箱:git config user.email2、设置信息(--global 全局设置)git config --gl…

能在0.02秒内找到最优解的华容道程序

https://www.cnblogs.com/funwithwords/p/19158097#include <stdio.h> #include <stdint.h> #include <string.h> #include <time.h> #include <immintrin.h> #include <xmmintrin.h…

Sparkle签名检查绕过漏洞分析

本文详细分析了CVE-2025-0509安全漏洞,该漏洞存在于Sparkle更新框架2.6.4之前版本,攻击者能够绕过(Ed)DSA签名检查替换已签名的更新包,构成高风险安全威胁。Sparkle签名检查绕过漏洞分析 漏洞概述 CVE-2025-0509是一…

openEuler安装Oracle踩坑

不得不说Oracle安装在Windows上就够麻烦了,到Linux上直接地狱难度. 众所周知Oracle是收费软件,所以什么从仓库一键安装就不要想了, 现在更是变本加厉,下载必须注册Oracle账号,希望大家以后都别用了吧,用"世界上最…

RPC ServiceModel.Grpc C#

RPC ServiceModel.Grpc C#RPC ServiceModel.Grpc C# 在 DogWatcher 和 HeartbeatService 中,CancellationToken 的核心作用是响应外部取消信号(如服务停止、客户端断开连接等),避免资源泄漏并确保程序优雅退出。…

通过onvif ptz 控制摄像头以及通过opencv 实时进行数据处理

通过onvif ptz 控制摄像头以及通过opencv 实时进行数据处理是一个简单玩法,主要是设计基于云边端的玩法,通过mediamtx 或者ffmpeg 对于边缘的视频进行处理,之后转发到其他流服务,之后云端或者边缘服务通过通过openc…

【GitHub每日速递 251027】14.3k star! 告别AI开发痛点!Parlant让大模型指令遵循不再是难题

原文:https://mp.weixin.qq.com/s/KjAS4gDjAzWtmHkBLoo64Q 告别AI开发痛点!Parlant让大模型指令遵循不再是难题 parlant 是一个专注于控制能力的LLM代理工具。简单讲,它让大语言模型像智能助手一样执行实际任务,快速…

百天打卡

腰悬长剑 ,阔步长安// run new Vue({el: #app,data: {habits: [{day: 01,streak: 1,time: 2025-10-27 07:51}]} })#app { margin: 0 auto; padding: 16px 0; background: rgba(255, 255, 255, 1); font-family: "…