1. 前言
微服务中用到了网关的话,自然而然就会考虑网关限流的问题;
当前项目中网关使用的是gateway,而它默认的限流是选择redis的方式来实现限流;
2. 限流方式
3. 项目引入gateway限流
1.引入依赖
<!--redis 用于实现gateway的限流-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
<!--如果父项目中限定了版本的话,这里不需要再具体制定-->
<version>2.1.3.RELEASE</version>
</dependency>
2.springboot入口类中注入KeyResolver ,采用什么方式限流
@Slf4j
@EnableDiscoveryClient
@EnableCircuitBreaker
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class GatewayApplication {
public static void main(String[] args) throws UnknownHostException {
ConfigurableApplicationContext application = SpringApplication.run(GatewayApplication.class, args);
}
//注入bean
@Bean
public KeyResolver ipKeyResolver(){
return new KeyResolver() {
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
/**
* 限流条件:
* 1.用户ip地址(桶是私有)
* 2.用户用户名(桶是私有)
* 3.微服的路径(桶是共享的)
*/
//此处根据用户的id做为条件限流
return Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}
};
}
}
3.application.yml文件中配置
其实关键就是在filters中加入name,args的配置,可以对每个服务单独配置;
server:
port: 9527
spring:
application:
name: cloud-gateway
redis:
host: xxx.xx.xx.xx(填写你自己的redis所在主机的ip)
port: 6379
password: (如果你的redis配置了密码请加上,没有可省略)
cloud:
gateway:
discovery:
locator:
enabled: true
routes:
- id: payment_routh #路由的ID,没有固定规则但要求唯一,建议配合服务名
# uri: http://localhost:8001 #匹配后提供服务的路由地址
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/get/** #断言,路径相匹配的进行路由
filters:
- StripPrefix=1
- name: RequestRateLimiter #请求数限流 名字不能随便写
args:
key-resolver: "#{@ipKeyResolver}"
redis-rate-limiter.replenishRate: 1 #令牌桶每秒填充平均速率
redis-rate-limiter.burstCapacity: 5 #令牌桶总容量
# - After=2020-09-24T22:18:11.242+08:00[GMT+08:00]
# - Cookie=username,zzyy
# - Header=X-Request-Id, \d+ #请求头中要有X-Request-Id属性并且值为整数的正则表达式
# filters:
# - AddRequestHeader=X-Request-red, blue
- id: payment_routh2
# uri: http://localhost:8001
uri: lb://cloud-payment-service #匹配后提供服务的路由地址
predicates:
- Path=/payment/lb/** #断言,路径相匹配的进行路由
filters:
# - StripPrefix=1
- name: RequestRateLimiter #请求数限流 名字不能随便写
args:
key-resolver: "#{@ipKeyResolver}"
redis-rate-limiter.replenishRate: 1 #令牌桶每秒填充平均速率
redis-rate-limiter.burstCapacity: 5 #令牌桶总容量
- id: payment_routh3
uri: http://news.baidu.com
predicates:
- Path=/guonei #断言,路径相匹配的进行路由
eureka:
instance:
hostname: cloud-gateway-service
client:
service-url:
register-with-eureka: true
fetch-registry: true
defaultZone: http://eureka7001.com:7001/eureka
到这里我们就配置好了,只需要启动项目就有限流效果了,测试的时候都设置为1,然后页面我们可以访问来看到限流效果;
但在这里用专业的工具Jmeter来测试会更加能显示限流的功能之强大和控制之精准!
4. 效果测试:
这里我直接贴效果图,如果想知道具体操作,可点击我的另一篇文章具体介绍Jmeter的操作,点击传送门;
测试1:
jmeter参数如下图:
意思是1秒钟启动10个线程去发起请求,只执行一次;
redis-rate-limiter.replenishRate: 1 #令牌桶每秒填充平均速率
redis-rate-limiter.burstCapacity: 5 #令牌桶总容量
桶容量为5个,1秒钟加入一个,那么理论上用已经设置好的jemter请求参数,那就是10个请求应该有6个成功才对;
测试2:
jmeter参数如下图:
意思是3秒钟启动15个线程去发起请求,只执行一次;
redis-rate-limiter.replenishRate: 1 #令牌桶每秒填充平均速率
redis-rate-limiter.burstCapacity: 5 #令牌桶总容量
桶容量为5个,1秒钟加入1个,三秒钟就是3个,那么理论上,那就是15个请求应该有5+1*3=8个成功才对;