目录
2. 在eurekaconsumer项目启动类中启用Hystrix
3. 在eurekaconsumer项目中为方法定义一个断路器切面
一、什么是Hystrix断路器模式
在微服务中断路器在方法执行失败时可以优雅的处理失败,避免跨调用堆栈产生级联失败。
断路器起初会处于关闭状态,允许进行方法的调用。如果因为某种原因,方法调用失败了,断路器就会打开,就不会对失败的方法再执行调用了。此时会调用一个后备方法代替失败的方法返回结果。在调用后备方法的过程中断路器偶尔会进入半开状态,去再次尝试调用发生失败的方法:如果依然失败,断路器就恢复打开状态;如果调用成功,它会认为问题已经解决,断路器回到闭合状态。
二、本文用到的工程名列表
Eureka快速入门篇(一)中的两个项目:
eurekaserver(注册中心,server.port=8761)
eurekauser(微服务提供者,server.port=8081)
Eureka快速入门篇(二)中的项目:
eurekaconsumer(微服务消费者,server.port=8083)
三、声明使用断路器
1. 在eurekaconsumer项目中添加依赖
2. 在eurekaconsumer项目启动类中启用Hystrix
添加@EnableHystrix注解,启动Hystrix断路器。代码如下:
package com.eurekaconsumer;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
/**
* @EnableEurekaClient只适用于Eureka作为注册中心,@EnableDiscoveryClient 可以是其他注册中心。
*/
@SpringBootApplication
@EnableEurekaClient //启动Eureka客户端
@EnableHystrix //添加@EnableHystrix注解,启动Hystrix断路器
public class EurekaconsumerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaconsumerApplication.class, args);
}
/**
* 创建一个 RestTemplate 实例
* 并开启客户端负载均衡,@LoadBalanced这个注解是让 RestTemplate 开启负载均衡的能力
* 2022年5月11日14:59:09
* @return
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
3. 在eurekaconsumer项目中为方法定义一个断路器切面
任何使用@HystrixCommand注解的方法都会为其声明一个断路器切面。
使用注解:@HystrixCommand(fallbackMethod = "getDefaultJson"),并提供后备方法getDefaultJson()。代码如下:
package com.eurekaconsumer;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* 服务消费者类,消费Eureka中注册的服务
* 2022年5月11日
*/
@RestController
public class RestConsumeEureka {
@Value("${server.port}")
private String port;
private RestTemplate rest;
/**
* 构造方法注入EurekaconsumerApplication启动类中定义的@Bean(RestTemplate)
* @param rest
*/
public RestConsumeEureka(@LoadBalanced RestTemplate rest) {
this.rest = rest;
}
/**
* @HystrixCommand,为方法提供断路器,断路器为getjsonStr方法提供失败防护,一段此方法失败则访问默认的后备方法getDefaultJson
* 如果getjsonStr方法抛出了未捕获的异常,那么断路器将会捕获异常并将方法调用重定向到后备方法(getDefaultJson)上。
* @HystrixCommand注解为方法声明一个断路器切面,并指明fallbackMethod(后备方法)
* @return
*/
@GetMapping(path = "/getmyjsonStr")
@HystrixCommand(fallbackMethod = "getDefaultJson") //@HystrixCommand注解为方法声明一个断路器切面,并指明fallbackMethod(后备方法)
public String getjsonStr(){
System.out.println("消费Eureka中注册的服务。。。");
String ret=rest.getForObject("http://EUREKAUSER/jsondata/getjData",String.class);
System.out.println(ret);
return ret;
}
/**
* 断路器后备方法,getjsonStr()方法执行失败时调用
* 返回一个和getjsonStr()方法返回值格式相同的默认json数据
* @return
*/
public String getDefaultJson(){
System.out.println("getDefaultJson断路器后备方法执行。。。");
String jsonStr = "后备方法getDefaultJson()提供的响应......";
String ret=jsonStr;
System.out.println(ret);
return ret;
}
}
4. 测试断路器的运行效果
依次运行项目eurekaserver(注册中心,server.port=8761),eurekauser(微服务提供者,server.port=8081),eurekaconsumer(微服务消费者,server.port=8083)
此时在浏览器中访问eurekaconsumer项目的getjsonStr()方法,可以正常调用Rest服务得到json返回结果。如图:
现在关闭服务提供者项目eurekauser。再次在浏览器访问eurekaconsumer项目的getjsonStr()方法,此时将无法调用到Rest服务得到正确的json返回结果。而是返回后备方法getDefaultJson()的响应结果。如图:
5. 使用断路器缓解延迟
默认情况下,所有使用@HystrixCommand注解的方法都会在 1 秒 之后超时,并调用他们声明的后备方法。
默认 1 秒 的断路器超时时间也可以更改,自定义超时时间使用@HystrixCommand注解的commandProperties属性来实现。commandProperties属性是一个或多个@HystrixProperty注解所组成的数组。例如设置为 500 毫秒 超时:@HystrixCommand(fallbackMethod = "getDefaultJson", commandProperties = @HystrixProperty( name = "execution.isolation.thread.timeoutInMilliseconds", value = "500"))
也可以直接移除超时功能不使用,将execution.timeout.enabled属性设置为false。@HystrixCommand(fallbackMethod = "getDefaultJson", commandProperties = @HystrixProperty( name = "execution.timeout.enabled", value = "false"))
6. 管理断路器的阈值
默认情况下,如果断路器保护的方法调用超过 20 次,而且 50% 以上的调用在 10 秒的时间内发生失败,那么断路器就会进入打开状态。所有后续的调用都将会由后备方法处理。在 5 秒之后,断路器进入半开状态,将会再次尝试调用原始的方法。
我们可以通过设置 Hystrix 命令的属性调整失败和重试的阈值:
circuitBreaker.requestVolumeThreshold: 在给定的时间范围内,方法应该被调用的次数。
circuitBreak.errorThresholdPercentage:在给定的时间范围内,方法调用产生失败的百分比。
metrics.rollingStats.timeInMilliseconds:控制请求量和错误百分比的滚动时间周期。
circuitBreaker.sleepWindowInMilliseconds:处于打开状态的断路器要经过多长时间才会进入半开状态,进入半开状态之后,将会再次尝试失败的原始方法。如果在metrics.ollingState.timeInMilliseconds设定的时间范围内超出了circuitBreaker.requestVolumeThreshold和circuitBreaker.errorThresholdPercentage设置的值,那么断路器将会进人打开状态。在circuitBreaker.sleepWindowInMilliseconds限定的时间范围内,它会一直处于打开状态,在此之后将进入半开状态,进入半开状态之后,将会再次尝试失败的原始方法。
例如,我们调用失败的设置:将其变更为在 20 秒的时间范围内调用超过 30 次且失败率超过 25% 。代码如下:
@HystrixCommand(fallbackMethod = "getDefaultJson",
commandProperties = {
@HystrixProperty(
name = "circuitBreaker.requestVolumeThreshold",
value = "30"),
@HystrixProperty(
name = "circuitBreaker.errorThresholdPercentage",
value = "25"),
@HystrixProperty(
name = "metrics.rollingStats.timeInMilliseconds",
value = "20000"),
@HystrixProperty(
name = "circuitBreaker.sleepWindowInMilliseconds",
value = "60000"),
})
public String getjsonStr(){
......
}