springcloud gateway熔断限流配置
熔断限流的概念(引用)
熔断
在分布式系统中,网关作为流量的入口,大量请求进入网关,向后端远程系统或服务发起调用,后端服务不可避免的会产生调用失败(超时或者异常),失败时不能让请求堆积在网关上,需要快速失败并返回回去,这就需要在网关上做熔断、降级操作。
限流
网关上有大量请求,对指定服务进行限流,可以很大程度上提高服务的可用性与稳定性,限流的目的是通过对并发访问/请求进行限速,或对一个时间窗口内的请求进行限速来保护系统。一旦达到限制速率则可以拒绝服务、排队或等待、降级。
一、网关熔断
1.引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>${gateway.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2.添加熔断处理器
@Slf4j
@RestController
public class FallbackHandler {
@RequestMapping("/defaultfallback")
public Map<String,String> defaultfallback(HttpServerRequest request) {
String uri = request.uri();
log.warn("网关熔断,url:{}",uri);
Map<String,String> map = new HashMap<>();
map.put("code","5001");
map.put("msg","服务异常,请稍后重试");
map.put("data","null");
return map;
}
}
3.修改配置
- id: api-product
uri: lb://api-product
predicates:
- Path=/api-product/**
filters:
- StripPrefix=1
#熔断过滤器
- name: Hystrix
args:
name: defaultfallback
fallbackUri: forward:/defaultfallback
4.添加测试方法
@RestController
@RequestMapping("/test")
@Api
@Slf4j
public class TestController {
@GetMapping("/getName")
public ResponseInfo<String> getName(){
try {
Thread.sleep(10000);
log.warn("sleep ................");
} catch (InterruptedException e) {
e.printStackTrace();
}
return ResponseInfo.ok();
}
}
5.测试效果
报错
服务请求超时之后,仍然没有返回对应的fallback信息,gateway的提示信息如下
随后仔细查看defaultfallback接口,发现接口参数的HttpServerRequest造成的,然后把参数去掉再试一下,下面是改过之后的defaultfallback
@Slf4j
@RestController
public class FallbackHandler {
@RequestMapping("/defaultfallback")
public Map<String,String> defaultfallback() {
Map<String,String> map = new HashMap<>();
map.put("code","5001");
map.put("msg","服务异常,请稍后重试");
map.put("data","null");
return map;
}
}
测试通过!!!
二、限流
令牌桶算法介绍:
限流的算法有很多,这里采用令牌桶的算法进行限流

令牌桶算法(Token Bucket)是目前应用最广泛的一种限流算法,它的基本思想由两部分组成:生成令牌 和 消费令牌。
生成令牌:假设有一个装令牌的桶,最多能装 M 个,然后按某个固定的速度(每秒 r 个)往桶中放入令牌,桶满时不再放入;
消费令牌:我们的每次请求都需要从桶中拿一个令牌才能放行,当桶中没有令牌时即触发限流,这时可以将请求放入一个缓冲队列中排队等待,或者直接拒绝;仔细思考就会发现,令牌桶算法有一个很关键的问题,就是桶大小的设置,正是这个参数可以让令牌桶算法具备处理突发流量的能力。譬如将桶大小设置为 100,生成令牌的速度设置为每秒 10 个,那么在系统空闲一段时间的之后(桶中令牌一直没有消费,慢慢的会被装满),突然来了 50 个请求,这时系统可以直接按每秒 50 个的速度处理,随着桶中的令牌很快用完,处理速度又会慢慢降下来,和生成令牌速度趋于一致。这是令牌桶算法和漏桶算法最大的区别,漏桶算法无论来了多少请求,只会一直以每秒 10 个的速度进行处理。当然,处理突发流量虽然提高了系统性能,但也给系统带来了一定的压力,如果桶大小设置不合理,突发的大流量可能会直接压垮系统。
1.引入依赖
<!--限速路由器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
2.添加限流器
限流的维度可以有很多,比如针对用户、请求路径、IP,下面是针对IP的限流
@Configuration
public class RequestRateLimiterConfig {
/**
* @Author gzy
* @Description 根据IP进行路由限制
* @Date 15:35 2020/12/11
* @Param []
* @return org.springframework.cloud.gateway.filter.ratelimit.KeyResolver
**/
@Bean("ipKeyResolver")
KeyResolver ipKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
}
/**
* 接口限流
* 获取请求地址的uri作为限流key
* @return
*/
@Primary
@Bean("apiKeyResolver")
public KeyResolver apiKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getPath().value());
}
/**
* 用户限流
* 使用这种方式限流,请求路径中必须携带userId参数,请求路径中未携带userId会导致限流失效
* @return
*/
@Bean("userKeyResolver")
public KeyResolver userKeyResolver() {
return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
}
}
3.添加配置
- id: facade-product
uri: lb://facade-product
predicates:
- Path=/api-product/**
filters:
- StripPrefix=1
# 熔断过滤器
- name: Hystrix
args:
name: defaultfallback
fallbackUri: forward:/defaultfallback
# 限速路由器
- name: RequestRateLimiter
args:
# 限流策略
key-resolver: "#{@ipKeyResolver}"
# 每秒允许处理的请求数量,令牌桶每秒填充平均速率
redis-rate-limiter.replenishRate: 10
# 令牌桶的容量,允许在一秒钟内完成的最大请求数
redis-rate-limiter.burstCapacity: 10
4.测试
使用jmeter或者postman进行测试
(1)1秒内10个线程并发访问一个接口,访问全部通过
(2)1秒内100个线程并发访问一个接口,大部分的访问被拦截,通过率只有20%(存在一定的误差),被拦截的请求返回的header携带Response message:Too Many Requests
虽然存在一定的误差,但是限流已经成功。不过gateway官方提供的限流只能使用一种限流策略,也就是你只能针对IP或者接口选择一种方式进行限流,无法做到同时即限制IP又限制接口的策略,存在一定的局限性。如果想要同时做到多规则限流的小伙伴可以关注我看下一篇自定义多规则限流篇