gateway默认给我们提供了限流实现,也就是网关拦截器RequestRateLimiter。
6.1 令牌桶限流算法 RequestRateLimiter底层实现是令牌桶算法;
令牌桶内存储令牌,令牌桶需要设置令牌容量,也就是系统最大的并发大; 以一定的速率生成令牌(具体速率根据系统性能设置),放到令牌桶,如果桶慢了,则丢弃; 客户端来一个请求,则先去令牌桶获取令牌,拿到令牌,则处理请求,否则 丢弃或者返回失败;
令牌桶算法的优点: (1)通过恒定的速率生成令牌桶,能够让请求处理更均匀,不会出现短时间大量的请求处理; (2)比较友好的控制高并发;
6.2 Gateway网关限流实例
Spring Cloud Gateway官方提供了 RequestRateLimiterGatewayFilterFactory 过滤器工厂,使用Redis 和 Lua 脚本实现了令牌桶,来实现网关限流; 添加下Redis依赖:
<!-- spring boot redis 缓存引入 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <!-- lettuce pool 缓存连接池 --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency>
6.2.1 URI限流
配置类:
package com.java1234.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; /** * 限流规则配置类 * @author java1234 */ @Configuration public class KeyResolverConfiguration { @Bean public KeyResolver pathKeyResolver(){ /*return new KeyResolver() { @Override public Mono<String> resolve(ServerWebExchange exchange) { return Mono.just(exchange.getRequest().getURI().getPath()); } };*/ return exchange -> Mono.just(exchange.getRequest().getURI().getPath()); // URI限流 } }
yml配置:
spring: application: name: gateway-server cloud: gateway: routes: - id: rateLimiter uri: http://localhost:8080/ predicates: - Path=/product/** filters: - name: RequestRateLimiter # 限流过滤器 args: redis-rate-limiter.replenishRate: 1 # 令牌桶每秒填充速率 r redis-rate-limiter.burstCapacity: 2 # 令牌桶总容量
redis-rate-limiter.requestedTokens: 1 # 一个请求需要消费的令牌数
key-resolver: "#{@pathKeyResolver}" redis: # redis配置 host: 192.168.0.103 # IP port: 6379 # 端口 password: # 密码 connect-timeout: 10s # 连接超时时间
lettuce: # lettuce redis客户端配置 pool: # 连接池配置 max-active: 8 # 连接池最大连接数(使用负值表示没有限制) 默认 8
max-wait: 200s # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
max-idle: 8 # 连接池中的最大空闲连接 默认 8 min-idle: 0 # 连接池中的最小空闲连接 默认 0
访问过多之后,报429错误;
6.2.2 参数限流 配置类:
package com.java1234.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; /** * 限流规则配置类 * @author java1234 */ @Configuration public class KeyResolverConfiguration { @Bean public KeyResolver parameterKeyResolver(){ /*return new KeyResolver() { @Override public Mono<String> resolve(ServerWebExchange exchange) { return Mono.just(exchange.getRequest().getQueryParams().getFirst("token")); } };*/ return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("token")); // 参数限流 } }
请求带一个参数:http://localhost/product/32?token=fdafa
6.2.3 IP限流 配置类:
package com.java1234.config;
import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; /** * 限流规则配置类 * @author java1234 */ @Configuration public class KeyResolverConfiguration { @Bean public KeyResolver ipKeyResolver(){ /*return new KeyResolver() { @Override public Mono<String> resolve(ServerWebExchange exchange) { return Mono.just(exchange.getRequest().getRemoteAddress().getHostName()); } };*/ return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName()); // IP限流 } }