上文我们已经成功实现了请求重试与请求限流,接下来我们开始实现熔断与服务降级。 熔断与服务降级,在SpringCloud中设计到的就是我们的hystrix,这里我们也将会考虑配合hystrix来实现熔断与服务降级。 如果不了解hystix的可以先进行一下了解。
依赖引入
由于这里我是用的是基于hystrix的熔断降级,所以首先需要将服务整合hystrix
c
<hystrix.core.version>1.5.12</hystrix.core.version>
<hystrix.javanica.version>1.5.12</hystrix.javanica.version>
<hystrix.metrics.version>1.5.12</hystrix.metrics.version>
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-core</artifactId>
<version>${hystrix.core.version}</version>
</dependency>
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-metrics-event-stream</artifactId>
<version>${hystrix.metrics.version}</version>
</dependency>
<dependency>
<groupId>com.netflix.hystrix</groupId>
<artifactId>hystrix-javanica</artifactId>
<version>${hystrix.javanica.version}</version>
</dependency>
引入如上的依赖之后,我们就可以开始基于hystrix编写如何进行熔断限流了。 我先贴出一套代码来大致介绍一下如何使用hystrix实现熔断降级。
java
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandKey;
import com.netflix.hystrix.HystrixCommandProperties;
import com.netflix.hystrix.HystrixThreadPoolProperties;
public class MyHystrixCommand extends HystrixCommand<String> {
private final String fallbackValue;
protected MyHystrixCommand(String fallbackValue) {
super(Setter
.withGroupKey(HystrixCommandGroupKey.Factory.asKey("MyGroup"))
.andCommandKey(HystrixCommandKey.Factory.asKey("MyCommand"))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withExecutionTimeoutInMilliseconds(1000)) // 设置超时时间
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()
.withCoreSize(10) // 设置线程池大小
);
this.fallbackValue = fallbackValue;
}
@Override
protected String run() throws Exception {
// 执行你的业务逻辑
return "Result of the actual operation";
}
@Override
protected String getFallback() {
// 执行降级逻辑
return fallbackValue;
}
}
上述代码中,我创建了一个自定义的 MyHystrixCommand 类,继承自 HystrixCommand 类。在该类的构造函数中,你可以配置Hystrix的一些属性,如组、命令名称、执行超时等。然后,你需要实现 run 方法来执行实际的业务逻辑,以及 getFallback 方法来执行降级逻辑。
接下来,你可以在应用中使用这个自定义的Hystrix命令:
java
String result = new MyHystrixCommand("Fallback Value").execute();
通过调用 execute 方法,你可以执行Hystrix命令,如果发生熔断,将会执行降级逻辑,返回降级值。
这种方式允许你更细粒度地控制熔断和降级的行为,但需要手动配置Hystrix的属性,如超时时间、线程池大小等。你可以根据具体需求进行定制。 所以,根据上面的情况,我们就已经大概知道了如何基于hystrix实现一套熔断降级的逻辑了。
服务降级
那么接下来我们来编写具体的实现代码。 首先,我们需要在配置中心的配置中添加出来对hystrix的配置。
java
"hystrixConfigs":[{
"path":"/http-server/ping",
"timeoutInMilliseconds":5000,
"threadCoreSize":2,
"fallbackResponse":"熔断超时"
}]
之后,我们知道我们的具体执行逻辑是走过滤器的,所以我们需要在我们的路由过滤器这里添加额外的对hystrix的配置,来监测我们最后转发请求的时候,如果这个请求处理失败或者超时时,要让他进行熔断降级的逻辑。
java
@Override
public void doFilter(GatewayContext gatewayContext) throws Exception {
//首先获取熔断降级的配置
Optional<Rule.HystrixConfig> hystrixConfig = getHystrixConfig(gatewayContext);
//如果存在对应配置就走熔断降级的逻辑
if (hystrixConfig.isPresent()) {
routeWithHystrix(gatewayContext, hystrixConfig);
} else {
route(gatewayContext, hystrixConfig);
}
}
/**
* 获取hystrix的配置
*
* @param gatewayContext
* @return
*/
private static Optional<Rule.HystrixConfig> getHystrixConfig(GatewayContext gatewayContext) {
Rule rule = gatewayContext.getRule();
Optional<Rule.HystrixConfig> hystrixConfig =
rule.getHystrixConfigs().stream().filter(c -> StringUtils.equals(c.getPath(),
gatewayContext.getRequest().getPath())).findFirst();
return hystrixConfig;
}
可以看到,我上面的代码就是从配置中心中获取到hystrix的配置,然后判断如果存在熔断降级的配置就走熔断降级的逻辑。 原先的没有熔断降级时候的route逻辑不用改变,我们需要额外创建一个方法,当存在熔断降级逻辑时走这个方法。 这里就按照我们上一节提到的代码的编写方式,进行代码的编写和配置即可。
java
/**
* 根据提供的GatewayContext和Hystrix配置,执行路由操作,并在熔断时执行降级逻辑。
* 熔断会发生在:
* 当 Hystrix 命令的执行时间超过配置的超时时间。
* 当 Hystrix 命令的执行出现异常或错误。
* 当连续请求失败率达到配置的阈值。
* @param gatewayContext
* @param hystrixConfig
*/
private void routeWithHystrix(GatewayContext gatewayContext, Optional<Rule.HystrixConfig> hystrixConfig) {
HystrixCommand.Setter setter = //进行分组
HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(gatewayContext.getUniqueId()))
.andCommandKey(HystrixCommandKey.Factory.asKey(gatewayContext.getRequest().getPath()))
//线程池大小设置
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()
.withCoreSize(hystrixConfig.get().getThreadCoreSize()))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
//线程池
.withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.THREAD)
//超时时间
.withExecutionTimeoutInMilliseconds(hystrixConfig.get().getTimeoutInMilliseconds())
.withExecutionIsolationThreadInterruptOnTimeout(true)
.withExecutionTimeoutEnabled(true));
// 创建一个新的HystrixCommand对象,用于执行实际的路由操作。
new HystrixCommand<Object>(setter) {
@Override
protected Object run() throws Exception {
// 在Hystrix命令中执行路由操作,这是实际的业务逻辑。
route(gatewayContext, hystrixConfig).get();
return null;
}
@Override
protected Object getFallback() {
// 当熔断发生时,执行降级逻辑。
// 设置网关上下文的响应信息,通常包括一个降级响应。
gatewayContext.setResponse(hystrixConfig.get().getFallbackResponse());
gatewayContext.written();
return null;
}
}.execute(); // 执行Hystrix命令。
}
效果演示
上面的代码编写完毕之后,我们就已经完成了熔断降级了。 接下来我们来看看具体的效果。 启动后端服务,并且让后端服务进行长时间的阻塞。 那么此时就会触发一个超时的异常,此时就会出现熔断降级,