SpringCloud实战之路 | 应用篇(三)服务熔断器Hystrix工作流程及高级应用
文章内容输出来源:拉勾教育Java高薪训练营;
Hystrix介绍
Hystrix,宣言“defend your app”是由Netflix开源的一个延迟和容错库,用于隔离访问远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。Hystrix主要通过以下几点实现延迟和容错。
- 包裹请求:使用HystrixCommand包裹对依赖的调⽤逻辑。 自动投递微服务方法(@HystrixCommand 添加Hystrix控制)
- 跳闸机制:当某服务的错误率超过一定的阈值时,Hystrix可以跳闸,停止请求该服务一段时间。
- 资源隔离:Hystrix为每个依赖都维护了一个小型的线程池(舱壁模式)(或者信号量)。如果该线程池已满, - 发往该依赖的请求就被立即拒绝,而不是排队等待,从而加速失败判定。
- 监控:Hystrix可以近乎实时地监控运行指标和配置的变化,例如成功、失败、超时、以及被拒绝的请求等。
- 回退机制:当请求失败、超时、被拒绝,或当断路器打开时,执行回退逻辑。回退逻辑由开发人员自行提供,例如返回一个缺省值。
- 自我修复:断路器打开一段时间后,会自动进入“半开”状态
具体实现
引入maven依赖坐标
<!--熔断器Hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
启动类添加熔断器开启注解@EnableCircuitBreaker
@SpringBootApplication
@EnableDiscoveryClient // 开启服务发现
@EnableCircuitBreaker // 开启熔断
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application .class, args);
}
/**
* 注⼊RestTemplate
* @return
*/
@Bean
// Ribbon负载均衡
@LoadBalanced
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
}
定义服务降级处理方法,并在业务方法上使用@HystrixCommand的fallbackMethod
属性关联到
服务降级处理方法
@RestController
@RequestMapping("/test")
public class TestController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/test/{id}")
@HystrixCommand(
// 线程池标识,要保持唯一,不唯一的话就共用了
threadPoolKey = "findResumeOpenStateTimeoutFallback",
// 线程池细节属性配置
threadPoolProperties = {
@HystrixProperty(name="coreSize",value = "2"), // 线程数
@HystrixProperty(name="maxQueueSize",value="20") // 等待队列长度
},
// commandProperties熔断的一些细节属性配置
commandProperties = {
// 每一个属性都是一个HystrixProperty @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="2000")
// hystrix高级配置,定制工作过程细节
,
// 统计时间窗口定义
@HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds",value = "8000"),
// 统计时间窗口内的最小请求数
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "2"),
// 统计时间窗口内的错误数量百分比阈值
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "50"),
// 自我修复时的活动窗口长度
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "3000")
},
fallbackMethod = "myFallBack" // 回退方法
)
public Integer test(@PathVariable Long id) {
// 使用ribbon不需要我们自己获取服务实例然后选择一个那么去访问了(自己的负载均衡)
String url = "http://server/test/" + id; // 指定服务名
Integer forObject = restTemplate.getForObject(url, Integer.class);
return forObject;
}
/*
定义回退方法,返回预设默认值
注意:该方法形参和返回值与原始方法保持一致
*/
public Integer myFallBack(Long id) {
return -123333; // 兜底数据
}
}
注意
降级(兜底)方法必须和被降级方法相同的方法签名(相同参数列表、相同返回值)
测试
当请求超时时候返回直接返回降级方法结果
结果:
-123333
Hystrix工作流程
- 在调用出现问题时,会开启一个时间窗(默认为10s)
- 在这个时间窗内,统计请求次数是否达到了最小的请求数
如果未达到最小的请求数,则重置统计信息回到第一步(因为在请求数过少的情况下,有可能是偶尔出现的调用问题,后面就不会采取跳闸,或者切断的措施,要达到一定数量的统计才有意义)
如果达到最小的请求数,则统计请求失败的数量占所有请求数量的百分比是否达到阈值,
如果未达到阈值则重置统计信息回到第一步(原因同最小请求数)
如果达到阈值,跳闸(不在请求对应服务) - 如果跳闸,会打开一个新的活动窗口(默认5s),会每隔5s,Hystrix放行一个请求,到达问题服务,看是否调用成功,如果成功,则认为该服务恢复正常,重置断路器回到第1步,如果失败,回到第3步。
其中的参数通过配置可以定制修改
- execution.isolation.thread.timeoutInMilliseconds: 降级处理超时时间
- metrics.rollingStats.timeInMilliseconds : 统计时间窗口定义
- circuitBreaker.requestVolumeThreshold : 统计时间窗口内的最小请求数
- circuitBreaker.errorThresholdPercentage: 统计时间窗口内的错误数量百分比阈值
- circuitBreaker.sleepWindowInMilliseconds: 自我修复时的活动窗口长度
@GetMapping("/test/{id}")
@HystrixCommand(
// commandProperties熔断的一些细节属性配置
commandProperties = {
// 每一个属性都是一个HystrixProperty
//降级处理超时时间
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="2000"),
// hystrix高级配置,定制工作过程细节
// 统计时间窗口定义
@HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds",value = "8000"),
// 统计时间窗口内的最小请求数
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "2"),
// 统计时间窗口内的错误数量百分比阈值
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage",value = "50"),
// 自我修复时的活动窗口长度
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds",value = "3000")
},
fallbackMethod = "myFallBack" // 回退方法
)
public Integer test(@PathVariable Long id) {
// 使用ribbon不需要我们自己获取服务实例然后选择一个那么去访问了(自己的负载均衡)
String url = "http://server/test/" + id; // 指定服务名
Integer forObject = restTemplate.getForObject(url, Integer.class);
return forObject;
}
/*
* 定义回退方法,返回预设默认值
* 注意:该方法形参和返回值与原始方法保持一致
*/
public Integer myFallBack(Long userId) {
return -1; // 兜底数据
}
Hystrix舱壁模式(线程池隔离策略)
默认情况下,Hystrix有一个线程池(10个),所有加了@HystrixCommand注解的方法共用这一个线程池,如果这些方法接受的请求超过了10个,其他请求就会等待或者拒绝连接。
如果不进行设置,所有熔断方法将会公用一个Hystrix线程池(10个线程),如果方法1有把10个线程都占用了,方法2请求处理时不会去访问B服务,因为无线程可用。
为了处理由于请求过多而导致服务无法访问,hystrix不是采用增加线程数,而是可以为每一个方法单独开启一个线程池,这种模式叫做舱壁模式,也是线程隔离的⼿段。
配置方式:
@HystrixCommand(
// 线程池标识,要保持唯一,不唯一的话就共用了
threadPoolKey = "test",
// 线程池细节属性配置
threadPoolProperties = {
@HystrixProperty(name="coreSize",value = "1"), // 线程数
@HystrixProperty(name="maxQueueSize",value="20") // 等待队列长度
},
// commandProperties熔断的一些细节属性配置
commandProperties = {
// 每一个属性都是一个HystrixProperty
//降级处理超时时间
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="2000")
}
)
@GetMapping("/test/{id}")
public Integer test(@PathVariable Long id) {
// 使用ribbon不需要我们自己获取服务实例然后选择一个那么去访问了(自己的负载均衡)
String url = "http://server/test/" + id; // 指定服务名
Integer forObject = restTemplate.getForObject(url, Integer.class);
return forObject;
}