Spring Cloud Gateway 限流实战
这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos
本篇概览
本文是《Spring Cloud Gateway 实战》系列的第八篇,经过前面的学习,咱们对过滤器已了解得差不多,今天来补全过滤器的最后一个版块:限流(RequestRateLimiter )
默认的限流器是基于 redis 实现的,限流算法是大家熟悉的令牌桶(Token Bucket Algorithm),关于令牌捅的原理就不在此展开了,聪明的您看一眼下图应该就懂了:装令牌的桶容量有限,例如最多 20 个,令牌进入桶的速度恒定(注意,这里是和漏桶算法的区别),例如每秒 10 个,底部每个请求能拿到令牌才会被处理:
RequestRateLimiter 基本套路
使用 RequestRateLimiter 过滤器的步骤非常简单:
准备可用的 redis
maven 或者 gradle 中添加依赖 org.springframework.boot:spring-boot-starter-data-redis-reactive
确定按照什么维度限流,例如按照请求中的 username 参数限流,这是通过编写 KeyResolver 接口的实现来完成的
配置 application.yml 文件,添加过滤器
以上就是使用 RequestRateLimiter 过滤器的套路了
,简单么?接下来,咱们先编码再验证
源码下载
本篇实战中的完整源码可在 GitHub 下载到,地址和链接信息如下表所示(https://github.com/zq2599/blog_demos):
| 名称 | 链接 | 备注 |
| :-- | :-- | :-- |
| 项目主页 | https://github.com/zq2599/blog_demos | 该项目在 GitHub 上的主页 |
| git 仓库地址(https) | https://github.com/zq2599/blog_demos.git | 该项目源码的仓库地址,https 协议 |
| git 仓库地址(ssh) | git@github.com:zq2599/blog_demos.git | 该项目源码的仓库地址,ssh 协议 |
这个 git 项目中有多个文件夹,本篇的源码在 spring-cloud-tutorials 文件夹下,如下图红框所示:
spring-cloud-tutorials 文件夹下有多个子工程,本篇的代码是 gateway-requestratelimiter,如下图红框所示:
准备工作
为了更好的演示 Gateway 的效果,在服务提供者 provider-hello 的代码(Hello.java)中新增一个 web 接口,可以接受一个入参:
@GetMapping("/userinfo")
public String userInfo(@RequestParam("username") String username) {
return Constants.HELLO_PREFIX + " " + username + ", " + dateStr();
}
后面的测试咱们就用上述接口;
编码
在父工程 spring-cloud-tutorials 之下新增子工程 gateway-requestratelimiter,其 pom.xml 内容如下,重点是 org.springframework.boot:spring-boot-starter-data-redis-reactive:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-cloud-tutorials</artifactId>
<groupId>com.bolingcavalry</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>gateway-requestratelimiter</artifactId>
<dependencies>
<dependency>
<groupId>com.bolingcavalry</groupId>
<artifactId>common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
</dependencies>
</project>
配置文件 application.yml,请注意 RequestRateLimiter 的几个参数,已经用中文添加了详细的注释:
server:
#服务端口
port: 8081
spring:
application:
name: circuitbreaker-gateway
redis 配置
redis:
host: 192.168.50.43
port: 6379
cloud:
gateway:
routes:
id: path_route
predicates:
Path=/hello/**
filters:
name: RequestRateLimiter
args:
令牌入桶的速度为每秒 100 个,相当于 QPS
redis-rate-limiter.replenishRate: 100
桶内能装 200 个令牌,相当于峰值,要注意的是:第一秒从桶内能去 200 个,但是第二秒只能取到 100 个了,因为入桶速度是每秒 100 个
redis-rate-limiter.burstCapacity: 200
每个请求需要的令牌数
redis-rate-limiter.requestedTokens: 1
指定限流维度的代码 CustomizeConfig.java,这里是根据请求参数 username 的值来限流的,假设真实请求中一半请求的 username 的等于 Tom,另一半的 username 的等于 Jerry,按照 application.yml 的配置,Tom 的请求 QPS 为 10,Jerry 的 QPS 也是 10:
package com.bolingcavalry.gateway.config;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;
import java.util.Objects;
@Configuration
public class CustomizeConfig {
@Bean
KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("username"));
}
}
毫无营养的启动类 RequestRateLimiterApplication.java:
package com.bolingcavalry.gateway;
import org.springframework.boot.SpringApplication;
评论