浅析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/rate
local ttl = math.floor(fill_time*2)
local last_tokens = tonumber(redis.call("get", tokens_key))
if last_tokens == nil then
  last_tokens = capacity
end
local last_refreshed = tonumber(redis.call("get", timestamp_key))
if last_refreshed == nil then
  last_refreshed = 0
end
local delta = math.max(0, now-last_refreshed)
local filled_tokens = math.min(capacity, last_tokens+(delta*rate))
local allowed = filled_tokens >= requested
local new_tokens = filled_tokens
local allowed_num = 0
if allowed then
  new_tokens = filled_tokens - requested
  allowed_num = 1
end
redis.call("setex", tokens_key, ttl, new_tokens)
redis.call("setex", timestamp_key, ttl, now)
return { allowed_num, new_tokens }

下面逐行分析下这段脚本。首先解释下,从应用中入参进来的这几个属性的具体含义:

tokens_key:当前限流的标识,可以是ip,或者在spring cloud系统中,可以是一个服务的serviceID

timestamp_key:令牌桶刷新的时间戳,后面会被用来计算当前产生的令牌数

rate :令牌生产的速率,如每秒产生50个令牌

capacity :令牌桶的容积大小,比如最大100个,那么系统最大可承载100个并发请求

now :当前时间戳

requested:当前请求的令牌数量,Spring Cloud Gateway中默认是1,也就是当前请求

主要逻辑分析

-- 计算填满桶需要多长时间
-- 得到填满桶的2倍时间作为redis中key时效的时间,避免冗余太多无用的key
-- 这里和令牌桶的实现没有太大的关系
-- 获取桶中剩余的令牌,如果桶是空的,就将他填满
-- 获取当前令牌桶最后的刷新时间,如果为空,则设置为0
-- 计算最后一次刷新令牌到当前时间的时间差
-- 计算当前令牌数量,这个地方是最关键的地方,通过剩余令牌数 + 时间差内产生的令牌得到当前总令牌数量
-- 设置标识allowad接收当前令牌桶中的令牌数是否大于请求的令牌结果
-- 设置当前令牌数量
-- 如果allowed为true,则将当前令牌数量重置为通中的令牌数 - 请求的令牌数,并且设置allowed_num标识为1
-- 将当前令牌数量写回到redis中,并重置令牌桶的最后刷新时间
-- 返回当前是否申请到了令牌,以及当前桶中剩余多少令牌

以上就是浅析Spring Cloud Gateway中的令牌桶限流算法的详细内容,更多关于pring Cloud Gateway令牌桶限流算法的资料请关注我们其它相关文章!

(0)

相关推荐

  • 解决springcloud-gateway限流遇到的问题

    场景: 最近在研究spring cloud组件gateway 限流的实现,看官网spring cloud操作下去,决定采用redis的方式去实现这个限流,因为系统架构是分布式的,方便以后的迭代升级,所以就用redis了,之后就出现了下面的异常!!! 异常信息: java.lang.IllegalArgumentException: Unable to find GateWayFilterFactory with name RequestRateLimiter 我的开发环境是离线的状态,maven

  • 详解Spring Cloud Gateway 限流操作

    开发高并发系统时有三把利器用来保护系统:缓存.降级和限流. API网关作为所有请求的入口,请求量大,我们可以通过对并发访问的请求进行限速来保护系统的可用性. 常用的限流算法比如有令牌桶算法,漏桶算法,计数器算法等. 在Zuul中我们可以自己去实现限流的功能 (Zuul中如何限流在我的书 <Spring Cloud微服务-全栈技术与案例解析>  中有详细讲解) ,Spring Cloud Gateway的出现本身就是用来替代Zuul的. 要想替代那肯定得有强大的功能,除了性能上的优势之外,Spr

  • Spring Cloud Gateway不同频率限流的解决方案(每分钟,每小时,每天)

    SpringCloud Gateway 简介 SpringCloud Gateway 是 Spring Cloud 的一个全新项目,该项目是基于 Spring 5.0,Spring Boot 2.0 和 Project Reactor 等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的 API 路由管理方式. SpringCloud Gateway 作为 Spring Cloud 生态系统中的网关,目标是替代 Zuul,在Spring Cloud 2.0以上版本中,没有对新版本的Zuu

  • spring cloud gateway 限流的实现与原理

    在高并发的系统中,往往需要在系统中做限流,一方面是为了防止大量的请求使服务器过载,导致服务不可用,另一方面是为了防止网络攻击. 常见的限流方式,比如Hystrix适用线程池隔离,超过线程池的负载,走熔断的逻辑.在一般应用服务器中,比如tomcat容器也是通过限制它的线程数来控制并发的:也有通过时间窗口的平均速度来控制流量.常见的限流纬度有比如通过Ip来限流.通过uri来限流.通过用户访问频次来限流. 一般限流都是在网关这一层做,比如Nginx.Openresty.kong.zuul.Spring

  • 浅析Spring Cloud Gateway中的令牌桶限流算法

    目录 前言 回顾限流算法 计数器/时间窗口法 漏桶法 令牌桶法 主要逻辑分析 前言 在一个分布式高并发的系统设计中,限流是一个不可忽视的功能点.如果不对系统进行有效的流量访问限制,在双十一和抢票这种流量洪峰的场景下,很容易就会把我们的系统打垮.而作为系统服务的卫兵的网关组件,作为系统服务的统一入口,更需要考虑流量的限制,直接在网关层阻断流量比在各个系统中实现更合适.Spring Cloud Gateway的实现中,就提供了限流的功能,下面主要分析下Spring Cloud Gateway中是如何

  • spring cloud gateway整合sentinel实现网关限流

    这篇文章主要介绍了spring cloud gateway整合sentinel实现网关限流,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 说明: sentinel可以作为各微服务的限流,也可以作为gateway网关的限流组件. spring cloud gateway有限流功能,但此处用sentinel来作为替待. 说明:sentinel流控可以放在gateway网关端,也可以放在各微服务端. 1,以父工程为基础,创建子工程 2,添加pom依赖

  • ASP.NET Core中使用令牌桶限流的实现

    在限流时一般会限制每秒或每分钟的请求数,简单点一般会采用计数器算法,这种算法实现相对简单,也很高效,但是无法应对瞬时的突发流量. 比如限流每秒100次请求,绝大多数的时间里都不会超过这个数,但是偶尔某一秒钟会达到120次请求,接着很快又会恢复正常,假设这种突发的流量不会对系统稳定性带来实质性的影响,则可以在一定程度上允许这种瞬时的突发流量,从而为用户带来更好的可用性体验.这就是令牌桶算法的用武之地. 该算法的基本原理是:有一个令牌桶,容量是X,每Y单位时间会向桶中放入Z个令牌,如果桶中的令牌数超

  • Java中4种经典限流算法讲解

    目录 限流是什么? 常见的限流算法 固定窗口限流算法 滑动窗口限流算法 漏桶算法 令牌桶算法 最近,我们的业务系统引入了Guava的RateLimiter限流组件,它是基于令牌桶算法实现的,而令牌桶是非常经典的限流算法.本文将跟大家一起学习几种经典的限流算法. 限流是什么? 维基百科的概念如下: In computer networks, rate limiting is used to control the rate of requests sent or received by a net

  • spring cloud gateway中如何读取请求参数

    spring cloud gateway读取请求参数 1. 我的版本: spring-cloud:Hoxton.RELEASE spring-boot:2.2.2.RELEASE spring-cloud-starter-gateway 2. 请求日志 import lombok.extern.slf4j.Slf4j; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springfram

  • Spring Cloud Alibaba使用Sentinel实现接口限流

    最近管点闲事浪费了不少时间,感谢网友 libinwalan 的留言提醒.及时纠正路线,继续跟大家一起学习Spring Cloud Alibaba. Nacos作为注册中心和配置中心的基础教程,到这里先告一段落,后续与其他结合的内容等讲到的时候再一起拿出来说,不然内容会有点跳跃.接下来我们就来一起学习一下Spring Cloud Alibaba下的另外一个重要组件:Sentinel. Sentinel是什么 Sentinel的官方标题是:分布式系统的流量防卫兵.从名字上来看,很容易就能猜到它是用来

  • Spring Cloud Alibaba之Sentinel实现熔断限流功能

    微服务中为了防止某个服务出现问题,导致影响整个服务集群无法提供服务的情况,我们在系统访问量和业务量高起来了后非常有必要对服务进行熔断限流处理. 其中熔断即服务发生异常时能够更好的处理:限流是限制每个服务的资源(比如说访问量). spring-cloud中很多使用的是Hystrix组件来进行限流的,现在我们这里使用阿里的sentinel来实现熔断限流功能. sentinel简介 这个在阿里云有企业级的商用版本 应用高可用服务 AHAS:现在有免费的入门级可以先体验下,之后再决定是否使用付费的专业版

  • Spring Cloud Gateway整合sentinel 实现流控熔断的问题

    目录 一.什么是网关限流: 二.gateway 整合 sentinel 实现网关限流: 三.sentinel 网关流控规则的介绍: 3.1.网关流控规则: 3.2.API 分组管理: 四.sentinel 网关流控实现的原理: 五.网关限流了,服务就安全了吗? 六.自定义流控异常消息: 一.什么是网关限流: 在微服务架构中,网关层可以屏蔽外部服务直接对内部服务进行调用,对内部服务起到隔离保护的作用,网关限流,顾名思义,就是通过网关层对服务进行限流,从而达到保护后端服务的作用. Sentinel

随机推荐