千家信息网

Spring Cloud Gateway中是如何实现限流功能的

发表于:2025-11-07 作者:千家信息网编辑
千家信息网最后更新 2025年11月07日,这篇文章主要讲解了"Spring Cloud Gateway中是如何实现限流功能的",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Spring Clou
千家信息网最后更新 2025年11月07日Spring Cloud Gateway中是如何实现限流功能的

这篇文章主要讲解了"Spring Cloud Gateway中是如何实现限流功能的",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Spring Cloud Gateway中是如何实现限流功能的"吧!

前言

在一个分布式高并发的系统设计中,限流是一个不可忽视的功能点。如果不对系统进行有效的流量访问限制,在双十一和抢票这种流量洪峰的场景下,很容易就会把我们的系统打垮。而作为系统服务的卫兵的网关组件,作为系统服务的统一入口,更需要考虑流量的限制,直接在网关层阻断流量比在各个系统中实现更合适。Spring Cloud Gateway的实现中,就提供了限流的功能。

回顾限流算法

限流的实现方式有多种,下面先回顾下几种常见的实现算法

计数器/时间窗口法

这种限流算法最简单,也是最容易实现的,通过在单位时间内设置最大访问数就可以达到限流的目的。比如某个系统能够承载的一般qps为60,那我们就可以使用计算器法,在单位时间一秒内,限制接口只能被访问60次即可。但是这个算法实现,正如其功能描述一样,有个缺陷,假如在时间窗的前1%的时间内流量就达到顶峰了,那么在时间窗内还有99%的时间系统即使能够继续提供服务,还是会被限流算法的这种缺陷阻断在门外,这种缺陷也被称为"突刺效应"

漏桶法

漏桶法不同于计算器法,它有效的避免了计数器法限流的"突刺效应"缺陷,实现也不复杂,通过固定大小的队列+定时取队列元素的方式即可实现。如其名漏桶,就像一个盛水的容器,漏桶法只限制容器出水的速率,当进水的速率过大时,将会填满容器造成溢出,溢出部分的流量也就是拒绝的流量。比如,容器大小为100,出水速率为每秒10/s,当桶为空时,最大的流量可以到达100/s,但是即使这样,受限于固定的流出速率,后端处理的也只能是最大每秒10个,其余的流量都会被缓冲在漏桶中。这个也这是漏桶法的缺陷,没法真正处理突发的流量洪峰,效率不高。

令牌桶法

令牌桶法也是基于桶的原型,但是和漏桶算法截然不同的时,没有出水口。令牌桶通过令牌的产生速率+令牌桶的容积来控制流量,有效的解决了漏桶效率不高的问题。如,容积为100的桶,令牌产生速率为50/s,那么就代表当桶中令牌已满的时候,最大能够承载100的流量,后面如果流量一直居高不下,也会以每秒50个流量的速度恒速处理请求。令牌桶的这种特性有效的处理了洪峰流量也能做到不被洪峰压垮,是目前限流比较常见的实现方法。比较著名的实现有谷歌guava中的RateLimiter。然后下面将要分析的Spring Cloud Gateway中也是使用的令牌桶算法实现的限流

guava的文档:https://github.com/google/guava/wiki

Spring Cloud Gateway中的令牌桶

Spring网关中是基于令牌桶+redis实现的网关分布式限流,具体的实现见下面两个代码:

lua脚本地址:resources/META-INF/scripts/request_rate_limiter.lua

RedisRateLimiter:gateway/filter/ratelimit/RedisRateLimiter.java

try {                        Listkeys = getKeys(id);                        // The arguments to the LUA script. time() returns unixtime in seconds.                        ListscriptArgs = Arrays.asList(replenishRate + "",                                        burstCapacity + "", Instant.now().getEpochSecond() + "", "1");                        // allowed, tokens_left = redis.eval(SCRIPT, keys, args)                        Fluxflux = this.redisTemplate.execute(this.script, keys,                                        scriptArgs);                        // .log("redisratelimiter", Level.FINER);                        return flux.onErrorResume(throwable -> Flux.just(Arrays.asList(1L, -1L)))                                        .reduce(new ArrayList(), (longs, l) -> {                                                longs.addAll(l);                                                return longs;                                        }).map(results -> {                                                boolean allowed = results.get(0) == 1L;                                                Long tokensLeft = results.get(1);                                                Response response = new Response(allowed,                                                                getHeaders(routeConfig, tokensLeft));                                                if (log.isDebugEnabled()) {                                                        log.debug("response: " + response);                                                }                                                return response;                                        });                }

上面博主截取了Spring网关限流部分的关键代码,可以看到,最关键的地方在于,使用reids执行了一段lua脚本,然后通过返回值【0】是否等于1来判断本次流量是否通过,返回值【1】为令牌桶中剩余的令牌数。就上面这段代码没有看到任何令牌桶算法的影子对吧,所有的精华实现都在lua脚本里面,这个脚本最初是由Paul Tarjan分享出来的,源码地址戳我。脚本如下:

local tokens_key = KEYS[1]local timestamp_key = KEYS[2]local rate = tonumber(ARGV[1])local capacity = tonumber(ARGV[2])local now = tonumber(ARGV[3])local requested = tonumber(ARGV[4])local fill_time = capacity/ratelocal ttl = math.floor(fill_time*2)local last_tokens = tonumber(redis.call("get", tokens_key))if last_tokens == nil then  last_tokens = capacityendlocal last_refreshed = tonumber(redis.call("get", timestamp_key))if last_refreshed == nil then  last_refreshed = 0endlocal delta = math.max(0, now-last_refreshed)local filled_tokens = math.min(capacity, last_tokens+(delta*rate))local allowed = filled_tokens >= requestedlocal new_tokens = filled_tokenslocal allowed_num = 0if allowed then  new_tokens = filled_tokens - requested  allowed_num = 1endredis.call("setex", tokens_key, ttl, new_tokens)redis.call("setex", timestamp_key, ttl, now)return { allowed_num, new_tokens }

感谢各位的阅读,以上就是"Spring Cloud Gateway中是如何实现限流功能的"的内容了,经过本文的学习后,相信大家对Spring Cloud Gateway中是如何实现限流功能的这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

流量 令牌 算法 系统 功能 时间 速率 缺陷 脚本 最大 有效 容器 网关 洪峰 处理 限制 代码 学习 服务 关键 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 网络数据库安全性论文 博雅数据库南开 关于网络安全的团小组会 陈酿数据库寻找小花梅 报考计算机网络技术专业的理由 模拟山羊中世纪时代的服务器在哪 有个软件开发的软件叫什么 阿里云服务器网卡驱动安装 软件开发大赛一等奖案例 有关网络安全建设的论文 网络安全的主要作用 数据库表损坏的原因 泰州服务器工控机应用案例 tcga系列基因突变数据库 重庆前端软件开发需要多少钱 网络安全设备哈尔滨分公司 云南软件开发学校排名 服务器和显示器属于哪种辐射 购宇智能网络安全 服务器操作系统的管理维护 就搜软件开发职业规划树形图 智斓软件开发有限公司 scum怎么不用服务器联机 武汉微思墩网络技术有限公司 蓟州区技术软件开发供应 阿里云服务器网卡驱动安装 滴滴软件开发岗位工资多少 服务器每分钟自动重启 网络安全教育 网络安全专家王凤娇
0