Hystrix是什么?
在分布式环境中,许多服务依赖项中的一些必然会失败。Hystrix是一个库,通过添加延迟容忍和容错逻辑,帮助你控制这些分布式服务之间的交互。Hystrix通过隔离服务之间的访问点、停止级联失败和提供回退选项来实现这一点,所有这些都可以提高系统的整体弹性。
Hystrix解决了什么问题
复杂分布式体系结构中的应用程序有许多依赖项,每个依赖项在某些时候都不可避免地会失败。如果主机应用程序没有与这些外部故障隔离,那么它有可能被他们拖垮。
例如,对于一个依赖于30个服务的应用程序,每个服务都有99.99%的正常运行时间,你可以期望如下: 99.9930 = 99.7% 可用
也就是说一亿个请求的0.03% = 3000000 会失败
如果一切正常,那么每个月有2个小时服务是不可用的
现实通常是更糟糕
服务降级
什么是服务降级?当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理或换种简单的方式处理,从而释放服务器资源以保证核心交易正常运作或高效运作。
- pom
<!--hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--eureka client-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
- yaml
server:
port: 80
spring:
application:
name: cloud-hystrix-consumer
#将服务注册到eureka
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka/
feign:
hystrix:
enabled: true
- 主启动类加
@EnableHystrix
注解
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableHystrix
public class HystrixConsumerMain {
public static void main(String[] args) {
SpringApplication.run(HystrixConsumerMain.class,args);
}
}
- ConsumerService接口(Feign接口+注解实现服务接口调用)
@Component
@FeignClient(value = "CLOUD-HYSTRIX-PROVIDER") //调用服务提供方8001
public interface ConsumerService {
//请求会立即返回结果
@GetMapping(value = "/hystrix/provider/ok")
public String provider_OK();
//请求会延迟3秒返回结果
@GetMapping(value = "/hystrix/provider/timeout")
public String provider_TimeOut();
}
8001服务提供方ProviderService.java相应代码
/**
* 正常
* @return
*/
public String provider_OK() {
return "线程池:" + Thread.currentThread().getName() + " provider_OK" + "\t" ;
}
/**
* 超时
* @return
*/
public String provider_TimeOut() {
try {
TimeUnit.MILLISECONDS.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "线程池:" + Thread.currentThread().getName() + " 3秒provider_TimeOut" + "\t" ;
}
- ConsumerController
@RestController
@Slf4j
public class ConsumerController {
@Resource
private ConsumerService consumerService;
@GetMapping(value = "/hystrix/consumer/ok")
public String consumer_OK(){
return consumerService.provider_OK();
}
@GetMapping(value = "/hystrix/consumer/timeout")
public String consumer_TimeOut(){
try {
}catch (Exception e){
e.printStackTrace();
};
return consumerService.provider_TimeOut();
}
}
- 使用Jmeter进行压力测试
来20000个并发压死8001服务提供方,20000个请求都去访问provider_TimeOut服务
浏览器访问provider_OK服务也会出现延迟响应,正常情况不会出现延迟(http://localhost:8001/hystrix/provider/ok)
浏览器访问consumer_OK偶尔会出现超时报错(http://localhost/hystrix/consumer/ok)
OpenFeign默认等待一秒钟,超时就会报错
- 服务降级
- 第一种:一个方法一个fallbackMethod处理
@GetMapping(value = "/hystrix/consumer/timeout")
@HystrixCommand(fallbackMethod = "consumerTimeOutFallbackMethod",
commandProperties = {@HystrixProperty(name= HystrixPropertiesManager.EXECUTION_ISOLATION_THREAD_TIMEOUT_IN_MILLISECONDS,value = "2000")})//两秒超时
public String consumer_TimeOut() {
return consumerService.provider_TimeOut();
}
public String consumerTimeOutFallbackMethod() {
return "80端口请求:请求超时或者自己运行出错!";
}
- 第二种:一个类一个统一fallbackMethod处理
@RestController
@Slf4j
@DefaultProperties(defaultFallback = "commonFallbackMethod")
public class ConsumerController {
@Resource
private ConsumerService consumerService;
@HystrixCommand
@GetMapping(value = "/hystrix/consumer/ok")
public String consumer_OK(){
return consumerService.provider_OK();
}
@GetMapping(value = "/hystrix/consumer/timeout")
@HystrixCommand
public String consumer_TimeOut() {
return consumerService.provider_TimeOut();
}
public String commonFallbackMethod() {
return "80端口请求:请求超时或者自己运行出错!公共处理";
}
- 第三种:Feign客户端定义的接口添加一个服务降级处理的实现类(可实现业务解耦)
新建ConsumerFallBackService.java
@Component
public class ConsumerFallBackService implements ConsumerService{
@Override
public String provider_OK() {
return "ConsumerFallBackService-80端口:provider_OK超时或异常";
}
@Override
public String provider_TimeOut() {
return "ConsumerFallBackService-80端口:provider_TimeOut超时或异常";
}
}
ConsumerService.java@FeignClient
注解增加fallback
@Component
@FeignClient(value = "CLOUD-HYSTRIX-PROVIDER",fallback = ConsumerFallBackService.class)
public interface ConsumerService {
@GetMapping(value = "/hystrix/provider/ok")
public String provider_OK();
@GetMapping(value = "/hystrix/provider/timeout")
public String provider_TimeOut();
}
服务熔断
服务雪崩
多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C有调用其他的微服务,这就是所谓的”扇出”,如扇出的链路上某个微服务的调用响应式过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统雪崩,所谓的”雪崩效应”。
服务熔断: 熔断机制是应对雪崩效应的一种微服务链路保护机制,
当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回”错误”的响应信息。当检测到该节点微服务响应正常后恢复调用链路,在SpringCloud框架机制通过Hystrix实现,Hystrix会监控微服务见调用的状况,当失败的调用到一个阈值,缺省是5秒内20次调用失败就会启动熔断机制,熔断机制的注解是@HystrixCommand
对于熔断机制的实现,Hystrix设计了三种状态:
1.熔断关闭状态(Closed) 服务没有故障时,熔断器所处的状态,对调用方的调用不做任何限制。
2.熔断开启状态(Open) 在固定时间窗口内(Hystrix默认是10秒),接口调用出错比率达到一个阈值(Hystrix默认为50%),会进入熔断开启状态。进入熔断状态后,后续对该服务接口的调用不再经过网络,直接执行本地的fallback方法。
3.半熔断状态(Half-Open)在进入熔断开启状态一段时间之后(Hystrix默认是5秒),熔断器会进入半熔断状态。所谓半熔断就是尝试恢复服务调用,允许有限的流量调用该服务,并监控调用成功率。如果成功率达到预期,则说明服务已恢复,进入熔断关闭状态;如果成功率仍旧很低,则重新进入熔断关闭状态。
代码实现
@HystrixCommand(fallbackMethod = "provider_CircuitBreakerFallBack",
commandProperties = {@HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_ENABLED,value = "true"),
@HystrixProperty(name= HystrixPropertiesManager.CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD,value = "10"), //熔断触发的最小个数
@HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS,value = "10000"), //熔断多少秒后去尝试请求
@HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE,value = "50") //失败率达到多少百分比后熔断
}
)
public String provider_CircuitBreaker(Integer id) {
if (id < 0){
throw new RuntimeException("服务熔断");
}
return "线程池:" + Thread.currentThread().getName() + "---provider_CircuitBreaker---" + "正常返回" ;
}
public String provider_CircuitBreakerFallBack(Integer id){
return "线程池:" + Thread.currentThread().getName() + "---provider_CircuitBreakerFallBack---" + "服务熔断" ;
}
测试
id>=0:输出provider_CircuitBreaker方法的返回值
id < 0:输出provider_CircuitBreakerFallBack方法的返回值(fallback方法)
当请求时大于10,并且失败率达到50%,服务熔断开启,输入正值也走fallback方法
十秒之后,进入半熔断状态,如果服务能正常调用,则服务恢复(熔断关闭状态);否则重新进入熔断关闭状态