SpringCloud Gateway网关基于令牌桶限流
限流的背景
在微服务中每个服务都是独立的,当系统频繁的请求时,比如秒杀业务,如果请求量大于系统承载量的时,如果系统不做任何的限量处理,就有可能在某段时间节点涌入大量的请求从而导致系统被压垮,根据上述情况我们就可以在网关内做限流,因为所有请求都需要先经过网关,通过网关把请求路由到具体的微服务中。
常见的限流算法 1. 计数器算法以QPS(每秒查询率Queries-per-second)为100举例。从第一个请求开始计时。每次请求都会使计数器加一。当到达100以后,其他的请求都拒绝。如果1秒钟内前200ms请求数量已经到达了100,后面800ms中500次请求都被拒绝了,这种情况称为“突刺现象”
计数器算法是用来记录每秒访问量的,计数器算法不能限制单个客户端的并发请求。这样可能可能会被恶意攻击切计数器算法很难保证极限情况,这种算法的缺点是无法解决对短时间节点内的突发流量。
漏桶算法可以解决突刺现象。
和生活中漏桶一样,有一个水桶,下面有一个”漏眼”往出漏水,不管桶里有多少水,漏水的速率都是一样的。既然是一个桶,桶里装的水都是有上限的。当到达了上限新进来的水就装不了(主要出现在突然倒进来大量水的情况)。在算法上实现可以准备一个队列来保存请求,通过一个线程池从队列中获取请求并执行,可以一次性获取多个请求并执。
令牌桶算法可以说是对漏桶算法的一种改进。令牌桶算法能够在限制调用的平均速率的还允许一定程度的突发调用。在令牌桶算法中,存在一个桶用来存放固定数量的令牌,算法中存在一种机制,根据一定的速率往令牌桶中存放令牌,每请求时需要先获取令牌,只有拿到了令牌才有机会继续执行,否则选择等待可用的令牌,或者直接拒绝。
放令牌是一直持续进行的,如果令牌桶中的令牌达到了上限,就会丢弃这个令牌,例如桶中一直有大量的可用令牌,这时进来的请求就可以直接拿到令牌执行,如果QPS为100,那么限流器初始化完成一秒后桶中就已经有了100个令牌了。当服务启动完成对外提供服务时,该限流器就可以抵挡瞬时的100个请求。只有桶中没有令牌时,请求才会进行等待,相当于一定的速率执行。
在SpringCloud项目中我们可以使用Gateay中的RequestRateLimiterGateayFilterFactory实现限流,可以帮我们进行客户端的访问流量限制,他主要限制的不是上限信号量而是每个客户端时间节点内可访问的次数。例如时间节点为1秒。限制的是每个客户断在一秒内访问的次数,避免一个客户端在某段时间节点内大量请求。
RequestRateLimiterGateayFilterFactory 算法工厂由代码提供,令牌桶由Redis提供,底层逻辑由lua脚本计算。RequestRateLimiterGateayFilterFactory 中找到内部类Config中有两大属性
KeyResolver:keyResolver是实现KeyResolver接口的bean。在配置中,使用SpEL通过名称引用bean。#{@myKeyResolver}是引用名称为myKeyResolver的bean的SpEL表达式。
RateLimiter:redis实现基于Stripe所做的工作。它需要使用spring-boot-starter-data-redis-reactive Spring Boot起动器。使用的算法是令牌桶算法。
redis-rate-limiter.replenishRate是您电脑维修网希望用户每秒允许多少个请求,而没有任何丢弃的请求。这是令牌桶被填充的速率
redis-rate-limiter.burstCapacity是允许用户在一秒钟内执行的最大请求数。这是令牌桶可以容纳的令牌数。将此值设置为零将阻止所有请求。
进入redisRateLimiter中查看,这两个信息可配置到yml文件中
创建yml文件springcloud210915 .dp.springcould 1.0-SNAPSHOT 4.0.0 cloud-gateay-gateay95278 8 .springframeork.cloud spring-cloud-starter-gateay.springframeork.boot spring-boot-starter-data-redis.springframeork.cloud spring-cloud-starter-flix-eureka-client.dp.springcould cloud-api-mons1.0-SNAPSHOT .alibaba fastjson1.2.59 .springframeork.boot spring-boot-starter-testtest .springframeork.boot spring-boot-devtoolsruntime true .projectlombok lombok
server: port: 9527 spring: application: name: cloud-gateay cloud: gateay: discovery: locator: enabled: true #开启从注册中心动态创建路由的功能,利用微服务名进行路由 routes: - id: payment_routh1 #路由ID,没有固定规则但要求唯一,简易配合服务名 #uri: http://localhost:8001 #匹配后提供的路由地址 uri: lb://SPRINGCLOUD-PAYMENT-SERVICE # 注册中心服务应用名 predicates: - Path=/payment @Override public Monoresolve(ServerWebExchange exchange) { String path = exchange.getRequest().getURI().getPath(); //根据ip限流 String hostAddress = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress(); return Mono.just(hostAddress); } }
参考文献https://.springcloud./spring-cloud-greenich.html