今天继续来学习下 Spring Cloud Gateway
的熔断与降级。
在分布式系统中,网关做为流量的入口,所以会有大量的请求进入网关,向其余服务发起调用,其余服务不可避免的会出现调用失败(超时、异常),失败时不能让请求堆积在网关上,需要快速失败并返回给客户端,想要实现这个要求,就必须在网关上作熔断、降级操作。
fallback
(退路)错误处理信息。这样,虽然提供的是一个有损的服务,但却保证了整个系统的稳定性和可用性。在 Spring Cloud
框架里,熔断机制通过 Hystrix
实现。Hystrix
会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒内20次调用失败,就会启动熔断机制。
应用场景:微服务架构中,多个微服务相互调用处使用
需要考虑问题:
服务熔断是应对系统服务雪崩的一种保险措施,给出的一种特殊降级措施。而服务降级则是更加宽泛的概念,主要是对系统整体资源的合理分配以应对压力。
服务熔断是服务降级的一种特殊情况,他是防止服务雪崩而采取的措施。系统发生异常或者延迟或者流量太大,都会触发该服务的服务熔断措施,链路熔断,返回兜底方法。这是对局部的一种保险措施。
服务降级是对系统整体资源的合理分配。区分核心服务和非核心服务。对某个服务的访问延迟时间、异常等情况做出预估并给出兜底方法。这是一种全局性的考量,对系统整体负荷进行管理。
上述相关概念来自:服务降级与服务熔断区别 - 知乎 (zhihu.com)
了解完相关概念后,接下来我们看一下如何在 Spring Cloud Gateway
实战中配置熔断降级。
1、pom.xml
文件中添加 Hystrix
依赖
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-hystrixartifactId>
dependency>
这里需要注意下,Spring Cloud 版本的问题,版本不同可能引入不成功。我这里是
Hoxton.SR6
版本
2、application.yml
配置
server:
port: 8080
spring:
application:
name: api-gateway
cloud:
gateway:
routes:
- id: cloud-gateway
uri: http://localhost:8080
predicates:
- Path=/ytb/**
filters:
- StripPrefix=1
# 降级配置
- name: Hystrix
args:
name: testOne
# 降级接口的地址
fallbackUri: forward:/fallback
# 针对全局配置
hystrix:
command:
default:
execution:
timeout:
enabled: true
isolation:
thread:
timeoutInMilliseconds: 3000
# 对单独的 Hystrix 的 commandKey 设置超时时间
testOne:
execution:
isolation:
thread:
timeoutInMilliseconds: 3000
配置中有一个可选参数fallbackUri
,当前只支持forward
模式的URI
。如果触发熔断,请求会被转发到该URI
对应的控制器。控制器可以是自定义的fallback
接口;也可以是自定义的Handler
,需要实现接口org.springframework.web.reactive.function.server.HandlerFunction
。
还设置了接口超时时间,也就是接口响应超过这个时间就会触发熔断。
3、fallbackUri
配置的降级地址接口
@RestController
public class FallbackController {
@GetMapping("/fallback")
public Map<String, Object> fallback() {
Map<String, Object> map = new HashMap<>();
map.put("code", "error");
map.put("msg", "服务暂时不可用");
return map;
}
}
4、测试接口
@RestController
public class TestController {
@GetMapping("/timeout")
public String timeout(){
try {
Thread.sleep(5000);
System.out.println("模拟接口超时");
} catch (InterruptedException e) {
e.printStackTrace();
}
return "请求成功";
}
}
Thread.sleep(5000)
用来模拟接口调用超时。
然后就可以启动项目,访问这个地址 localhost:8080/ytb/timeout
会得到以下返回结果:
因为我们设置的超时时间是 3 秒,接口睡眠 5 秒,所以就触发了降级熔断。
此时我们 application.yml
中修改一下超时时间为 6 秒,再次访问
这次就没有触发降级熔断了。
5、自定义 Handler
方式
前文提到控制器可以是自定义的fallback
接口;也可以是自定义的Handler
。我再贴上 Handler
方式的代码
路由配置:
@Configuration
public class RouterFunctionConfiguration
{
@Autowired
private HystrixFallbackHandler hystrixFallbackHandler;
@SuppressWarnings("rawtypes")
@Bean
public RouterFunction routerFunction()
{
return RouterFunctions
.route(RequestPredicates.path("/fallback").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)),
hystrixFallbackHandler);
}
}
自定义 Handler
:
@Component
public class HystrixFallbackHandler implements HandlerFunction<ServerResponse>
{
private static final Logger log = LoggerFactory.getLogger(HystrixFallbackHandler.class);
@Override
public Mono<ServerResponse> handle(ServerRequest serverRequest)
{
Optional<Object> originalUris = serverRequest.attribute(GATEWAY_ORIGINAL_REQUEST_URL_ATTR);
originalUris.ifPresent(originalUri -> log.error("网关执行请求:{}失败,hystrix服务降级处理", originalUri));
return ServerResponse.status(HttpStatus.INTERNAL_SERVER_ERROR.value()).contentType(MediaType.APPLICATION_JSON)
.body(BodyInserters.fromValue(JSON.toJSONString("{"error":"服务已被降级熔断"}")));
}
}
启动网关服务GatewayApplication.java
,访问localhost:8080/ytb/timeout
再进行测试,会发现返回服务已被降级熔断
。
至此,本文结束。后续可能会有补充