一:限速路由器的过滤器
1.1 限速在高并发场景中比较常用的手段之一,可以有效的保障服务的整体稳定性,Spring Cloud Gateway 提供了基于 Redis 的限流方案。
所以我们首先需要添加对应的依赖包spring-boot-starter-data-redis-reactive
1.2 修改 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.springcloud</groupId>
<artifactId>springcloud-hx</artifactId>
<version>1.0-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>eureka-gateway-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>eureka-gateway-client</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Greenwich.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<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-web</artifactId>
</dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
增加了spring-boot-starter-data-redis-reactive的依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
1.3 修改 application-predicate-mehtod.yml 文件,需要添加 Redis 地址和限流的相关配置,代码如下:
server:
port: 8769
#--- #三个横线表示再创建一个配置文件
spring:
#profiles: predicate-method #配置文件名 和 spring.profiles.active 相对应
#配置程序名为eureka-gateway-client
application:
name: eureka-gateway-client
#redis 配置
redis:
host: localhost
password: 123456
port: 6379
cloud:
#设置路由规则
gateway:
discovery:
locator:
#是否与服务注册于发现组件进行结合,通过 serviceId 转发到具体的服务实例。
#默认为 false,设为 true 便开启通过服务中心的自动根据 serviceId 创建路由的功能
enabled: true
##表示将请求路径的服务名配置改成小写 因为服务注册的时候,向注册中心注册时将服务名转成大写的了
lower-case-service-id: true
routes:
#我们自定义的路由 ID,保持唯一性
- id: predicate_path
#代表从注册中心获取服务,且以lb(load-balance)负载均衡方式转发
uri: lb://eureka-client/
#uri: http://localhost:8762
#断言
predicates:
#表示GET请求,都会被路由到uri
- Method=GET
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
key-resolver: '#{@ipKeyResolver}'
# 配置了RequestRateLimiter的限流过滤器,该过滤器需要配置三个参数replenishRate,burstCapacity,key-resolver
# redis-rate-limiter.replenishRate:允许用户每秒处理多少个请求
# redis-rate-limiter.burstCapacity:令牌桶的容量,允许在一秒钟内完成的最大请求数
# key-resolver:使用 SpEL 按名称引用 bean (RateLimiterConfig 类中的bean)
logging:
level:
org.springframework.cloud.gateway: debug
eureka:
client:
#服务注册地址
serviceUrl:
#注意: Eureka Server 的注册地址
#将服务提供者注册到三个Eureka Server中去
#defaultZone: http://peer1:8001/eureka/,http://peer2:8002/eureka/,http://peer3:8003/eureka/
#defaultZone: http://peer1:8001/eureka/
defaultZone: http://localhost:8761/eureka/
增加了这部分的代码
- filter 名称必须是 RequestRateLimiter
- redis-rate-limiter.replenishRate:允许用户每秒处理多少个请求
- redis-rate-limiter.burstCapacity:令牌桶的容量,允许在一秒钟内完成的最大请求数
- key-resolver:使用 SpEL 按名称引用 bean
1.4 在eureka-gateway-client 项目中设置限流的策略,创建 RateLimiterConfig 类。
package com.example.eurekagatewayclient.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;
@Configuration
public class RateLimiterConfig {
/**
* 根据请求参数中的 user 字段来限流
*
* @return
*/
/*@Bean
public KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
}*/
/**
* 获取请求地址的uri作为限流key。
* @return
*/
/*@Bean
KeyResolver apiKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getPath().toString());
}*/
/**
* 根据请求 IP 地址来限流
*
* @return
*/
@Bean
public KeyResolver ipKeyResolver() {
System.out.println("##############ipKeyResolver########################");
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}
}
这样网关就可以根据不同策略来对请求进行限流了。
1.5 启动 eureka-serve, eureka-client (8762,8763 端口),eureka-gateway-client 服务,浏览器访问 http://localhost:8761/
用jmeter进行压测,配置10thread去循环请求lcoalhost:8769/HiController/aaa,循环间隔1s。从压测的结果上看到有部分请求通过,由部分请求失败。通过redis客户端去查看redis中存在的key。如下:
从结果中可以看出 filter 生效了。