照例附上项目github链接。
本项目实现的是将一个简单的天气预报系统一步一步改造成一个SpringCloud微服务系统的过程。本章主要讲解服务的熔断机制。
什么是服务的熔断机制
-
对该服务的调用执行熔断,对于后续请求,不再继续调用该目标服务,而是直接返回,从而可以快速释放资源。
-
有利于保护系统。
熔断机制 : 当服务过载了,或者是流量激增,超过了服务的负荷,使用熔断机制,将服务掐断,保护自己不至于崩溃的机制。
熔断机制是对系统的防护。当有非常大的请求数目来访问我们的服务的时候,若请求超出了我们的承受范围,或者是超过了我们预先设定的某个阈值,我们就将服务断掉,响应给用户一个默认的值。
这个值不是用户所请求的值,到那时这个值可能包含了一些有价值的提示性的信息,如告诉用户我们的服务已经断掉了,请稍后再访问等。
基于Hystrix的服务熔断机制原理
我们可以把熔断器想象为一个保险丝,在电路系统中,一般在所有的家电系统连接外部供电的线路中间都会加一个保险丝,当外部电压过高,达到保险丝的熔点时候,保险丝就会被熔断,从而可以切断家电系统与外部电路的联通,进而保障家电系统不会因为电压过高而损坏。
Hystrix提供的熔断器就有类似功能,当在一定时间段内服务调用方调用服务提供方的服务的次数达到设定的阈值,并且出错的次数也达到设置的出错阈值,就会进行服务降级,让服务调用方之间执行本地设置的降级策略,而不再发起远程调用。但是Hystrix提供的熔断器具有自我反馈,自我恢复的功能,Hystrix会根据调用接口的情况,让熔断器在closed,open,half-open三种状态之间自动切换。
open状态说明打开熔断,也就是服务调用方执行本地降级策略,不进行远程调用。
closed状态说明关闭了熔断,这时候服务调用方直接发起远程调用。
half-open状态,则是一个中间状态,当熔断器处于这种状态时候,直接发起远程调用。
三种状态的转换:
- closed->open:正常情况下熔断器为closed状态,当访问同一个接口次数超过设定阈值并且错误比例超过设置错误阈值时候,就会打开熔断机制,这时候熔断器状态从closed->open。
- open->half-open:当服务接口对应的熔断器状态为open状态时候,所有服务调用方调用该服务方法时候都是执行本地降级方法,那么什么时候才会恢复到远程调用那?Hystrix提供了一种测试策略,也就是设置了一个时间窗口,从熔断器状态变为open状态开始的一个时间窗口内,调用该服务接口时候都委托服务降级方法进行执行。如果时间超过了时间窗口,则把熔断状态从open->half-open,这时候服务调用方调用服务接口时候,就可以发起远程调用而不再使用本地降级接口,如果发起远程调用还是失败,则重新设置熔断器状态为open状态,从新记录时间窗口开始时间。
- half-open->closed: 当熔断器状态为half-open,这时候服务调用方调用服务接口时候,就可以发起远程调用而不再使用本地降级接口,如果发起远程调用成功,则重新设置熔断器状态为closed状态。
如何集成Hystrix
这里我们以之前的天气预报微服务系统为例,讲解如何在其中集成Hystrix。
由于在天气预报微服务系统中,天气预报微服务将会调用多个其他微服务,所以我们让该服务集成Hystrix,当其他被调用的服务挂掉的时候,将会使熔断状态进入open模式,从而向用户返回一些默认的信息。
添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
@EnableCircuitBreaker注解
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableCircuitBreaker
public class Sifoudemo02Application {
public static void main(String[] args) {
SpringApplication.run(Sifoudemo02Application.class, args);
}
}
书写回调方法
在方法前面加上@HystrixCommand注解,启用断路器,由于这个方法我们是依赖城市数据API微服务,与天气数据API微服务的,所以当这两个微服务异常之后,就会触发这个熔断机制。
fallbackMethod为我们医用熔断机制后,请求失败时默认调用的方法,该方法的返回类型要与原方法一致。
//传入城市Id得到对应城市的天气数据
@GetMapping("/cityId/{cityId}")
@HystrixCommand(fallbackMethod="defaulGetReprotByCityId")
public Weather getReportByCityId(@PathVariable("cityId")String cityId)throws Exception{
//获取城市Id列表
//由城市数据API微服务来提供数据
List<City>cityList=null;
try {
cityList=dataClient.listCity();
}catch (Exception e) {
logger.error("Exception!",e);
}
Weather weather=weatherReportService.getDataByCityId(cityId);
return weather;
}
public Weather defaulGetReprotByCityId(String cityId) {
Weather weather=new Weather();
return weather;
}
运行测试
在测试时我们将天气数据API微服务,与城市数据API微服务关闭,然后发送请求,得到的为默认返回的天气数据。也可以返回一段信息,提示用户服务不可用。