springcloud gateway基于redis令牌桶算法进行微服务的限流保护
先上pom.xml
<?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>mall-cloud</artifactId>
<groupId>com.zmg</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>zmg-gateway</artifactId>
<packaging>jar</packaging>
<dependencies>
<!-- log related -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<!-- exclude掉spring-boot的默认log配置 -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency> <!-- 引入log4j2依赖 -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency> <!-- 加上这个才能辨认到log4j2.yml文件 -->
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
</dependency>
<dependency> <!-- 引入log4j-web -->
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-web</artifactId>
</dependency>
<!-- end of log related -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- 基于filter限流 监控依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 基于filter限流 redis依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<!-- 基于sentinel限流
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
</dependency> -->
<dependency>
<groupId>org.isomorphism</groupId>
<artifactId>token-bucket</artifactId>
<version>1.7</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>com.zmg</groupId>
<artifactId>zmg-basic</artifactId>
<version>1.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</exclusion>
<exclusion>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
</exclusion>
<exclusion>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
</exclusion>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.zmg</groupId>
<artifactId>zmg-auth</artifactId>
<version>1.0-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>3.0.0</version>
</dependency>
</dependencies>
<profiles>
<profile>
<id>dev</id>
<properties>
<profileActive>dev</profileActive>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>sit</id>
<properties>
<profileActive>sit</profileActive>
</properties>
</profile>
<profile>
<id>test</id>
<properties>
<profileActive>test</profileActive>
</properties>
</profile>
<profile>
<id>prd</id>
<properties>
<profileActive>prd</profileActive>
</properties>
</profile>
</profiles>
<build>
<finalName>zmg-gateway</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
主要引入spring-boot-starter-data-redis-reactive这个坐标
application.yml的配置
spring:
profiles:
active: @profileActive@
application:
name: zmg-gateway
redis:
database: 10
host: ${REDIS_HOST:localhost}
port: ${REDIS_PORT:6379}
password: zmg*123
timeout: 2000
jedis:
pool:
max-active: 20
sleuth:
enabled: true
http:
legacy:
enabled: true
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
# zmg系统服务模块
- id: zmg-sys
uri: lb://zmg-sys
order: 2001
predicates:
- Path=/api/zmg/sys/**
filters:
- name: RequestRateLimiter
args:
key-resolver: '#{@pathKeyResolver}'
redis-rate-limiter.replenishRate: 200
redis-rate-limiter.burstCapacity: 600
# RequestRateLimiter springcloud gateway限流过滤器
# 参数 key-resolver 使用SpEL 从request中提取限流的key
# 参数 replenishRate 向令牌桶中每秒填充的速率
# 参数 burstCapacity 令牌桶 容量
eureka:
instance:
statusPageUrlPath: /actuator/info
healthCheckUrlPath: /actuator/health
home-page-url-path: /
# docker 部署开启后将IP修改为部署所在服务器的外网IP
prefer-ip-address: true
ip-address: 127.0.0.1
instance-id: zmg-gateway
client:
serviceUrl:
# defaultZone: http://localhost:7001/eureka/
# docker 部署开启
defaultZone: http://${EUREKA_HOST:localhost}:${EUREKA_PORT:7001}/eureka/
client:
healthcheck:
enabled: true
主要是配置 redis 及 RequestRateLimiter 路由过滤器,RequestRateLimiter 过滤器的键值解析器 pathKeyResolver 采用的是访问路径进行限流。过滤器参数如下:
- key-resolver 使用SpEL 从request中提取限流的key
- replenishRate 向令牌桶中每秒填充的速率
- burstCapacity 令牌桶容量
pathKeyResolver的相关代码
/**
* Description:
*
* @author jacky
* @create 2019/11/01
**/
@Configuration
public class KeyResolverConfiguration {
/**
* 基于路径
* @return
*/
@Bean
public KeyResolver pathKeyResolver(){
return exchange -> Mono.just(
exchange.getRequest().getPath().toString());
}
}
开启redis客户端进行监控
启动相关微服务
访问测试
redis监控数据如下:
如果要看限流效果,可以将replenishRate和burstCapacity 改小,如改成 1 和3,重启服务后,在测试页面狂按f5刷新就会报错,如下图,即是限流保护的效果。