网关层限流
前面一节我们学习了如何在网关层对服务调用异常做统一封装,这一节我们来了解一下Gateway的另一个用法——限流。
前面的小节我们都是采用的基于Java代码的路由规则,这次我们换个路子,用基于yml 的配置方式配置路由规则,这两种式只是配置形式不同,但效果是一样的,而且Gateway中可以同时使用这两种方式做配置,在yml和Java中的配置规则都会生效。
1、网关限流三步走
这里采用令牌桶计数的方式做限流,问: 把客户请求放到令牌桶,总共分几步? 三步
1.1)准备工作
我们的Best Practice是基于Redis来实现限流,因此要保证本地启动了Redis服务,同时将下列配置加入到Gateway的配置文件中:
spring:
application:
name: gateway-service
redis:
host: localhost
port: 6379
database: 0
这里是配置Redis连接信息的,假如你不配置的话,Gateway也会尝试用默认配置项来连接Redis,但如果你在Redis配置信息中提供了错误的IP或者Potr的话,调用方法时依然会成功,不过限流功能就失效了,因为底层的Netty服务无法连接到Redis,也就无法提供限流支持。但GateWay为了保证服务可用性,限流功能的异常并不会阻碍正常的方法调用。
1.2)Key Resolver
Gateway的限流组件要求定义一个Key Resolver用来对每次路由请求生成一个Key,这Key就是一个限流分组的标识,每个Key相当于一个令牌桶。假如我们限定了一个服务每秒只解被调用3次,这个限制会对不同的Key单独计数、我们把调用方机器的Host Name作为限流Key,那么来自同一台机器的调用将落到同一个Key下面,也就是说在这个场景下,每台机器都独立计算单位时间调用量。
创建Key Resolver的方式很简单:
@Bean
public KeyResolver remoteAddrKeyResolver() {
return exchange -> Mono.just(
exchange.getRequest().getRemoteAddress().getHostName());
}
上面的例子创建了基于Host Name的今牌生成器,我们可以根据自己的业务来选择合适的Key,比如说可以在接口层面做限流(使用接口的Path作为Key),还可以从Request中提取业务字段作为Key (比如用户ID等)。
1.3)配置过滤器
spring:
cloud:
gateway:
routes:
- id: feignapi
uri: lb://FEIGN-SERVICE-PROVIDER
predicates:
- Path=/feign-api/**
filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
key-resolver: '#{@remoteAddrKeyResolver}'
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
在上面的限流配置中,我们主要关注最后3行中的属性:
- **key-resolver:**这里注入的就是在上一步中我们定义的Key Resolver,它使用SpEL表达式从Spring上下文中获取指定Bean;
- **replenishRate:**今牌桶每秒的平均填充速度;
-
burstCapacity:
今牌桶总量