目录
一、Hystrix介绍
1、分布式系统面临问题
多个微服务之间调用的时候,假如微服务A调用微服务B和微服务C,微服务B和微服务C又调用其他的微服务,这就是所谓的"扇出"。
如果扇出的链路上某个微服务的调用响应的时间过长或者不可用,对微服A的调用就会占用越来越多的系统资源,进而引起系统崩溃,即"雪崩效应"。
对于高流量的应用来说,单一的后端依赖可能会导致所有的服务器上的所有资源都在几秒钟内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。
所以,通常当你发现一个模块下的某个实例失败后,这时候这个模块依然还会接收流量,然后这个有问题的模块还调用了其他的模块,这样就会发生级联故障,或者叫雪崩。
2、Hystrix概念
①Hystrix是一个用于处理分布式系统的延迟和容错的开源库,可以保证一个服务出现故障时,不会导致整个系统出现雪崩效应,以提高分布式系统弹性;
②作为“断路器”,在一个服务出现故障时,可以通过短路器监控,返回一个可以处理的响应结果,保证服务调用线程不会长时间被占用,避免故障蔓延。
3、Hystrix作用
(1)服务降级
服务出现故障时,给故障服务降级到事先准备好的故障处理结果,将此结果返回给服务消费者,如:
客户端访问服务1,服务1调用服务2,服务2出现故障,Hystrix服务降级,返回一个可以处理的结果给服务1,服务1再以友好的错误界面返回给客户端。
(2)服务熔断
熔断机制是应对服务雪崩的一种链路保护机制,当服务出现故障时,服务会进行降级,熔断该服务节点,迅速返回错误响应信息。当检测到服务访问正常时,恢复其链路节点。
二、服务降级案例
1、搭建Eureka服务端
(1)创建maven工程
(2)导入依赖
导入Eureka服务端、web模块依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
(3)配置application.yml
①服务端口为7001;
②Eureka服务端主机名;
③Eureka客户端:
register-with-eureka:是否在服务中心注册
fetchRegistry:是否可以在注册中心被发现
service-url:服务中心url地址
server:
port: 7001
eureka:
instance:
hostname: localhost
client:
register-with-eureka: false
fetchRegistry: false
service-url:
defaultZone: http://localhost:7001/eureka
(4)创建主启动类
@EnableEurekaServer:Eureka服务端注解
@SpringBootApplication
@EnableEurekaServer
public class Eureka7001 {
public static void main(String[] args) {
SpringApplication.run(Eureka7001.class,args);
}
}
(5)启动Eureka注册中心
访问http://localhost:7001
2、搭建服务提供者Provider80
(1)创建maven工程
(2)导入依赖
导入Eureka客户端、web模块、监控,Htstrix依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
(3)配置application.yml
①配置服务端口号为80;
②配置服务应用名称;
③配置Eureka注册中心,开启注册,指明注册中心地址。
server:
port: 80
spring:
application:
name: provider
eureka:
client:
register-with-eureka: true
fetchRegistry: true
service-url:
defaultZone: http://localhost:7001/eureka
(4)创建启动类
@EnableEurekaClient:指明该服务为Eureka客户端
@EnableCircuitBreaker:开启Hystrix
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class Provider80 {
public static void main(String[] args) {
SpringApplication.run(Provider80.class,args);
}
}
(5)创建controller(设置自身降级方法)
@HystriCommand注解:
fallbackMethod:指定服务降级后调用方法,降级方法参数一定要和controller方法参数一致
commandProperties:相关参数。
@RestController
public class FeignController {
@Value("${server.port}")
private String port;
@GetMapping("/provider")
public String hello(){
return "访问端口号为:"+port;
}
@HystrixCommand(fallbackMethod = "TimeoutHandler",commandProperties = {
//2秒钟以内就是正常的业务逻辑
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="2000")
})
@GetMapping("timeout")
public String timeout(){
try {
//睡眠3秒
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hello";
}
//降级后方法,上面方法出问题,我来处理,返回一个出错信息
public String TimeoutHandler() {
return "访问请求失败了,服务不可用";
}
}
(6)测试自身降级
因为服务延迟3秒后执行,而降级设置时间为2秒,所以访问该请求时,服务降级
测试完成后,为方便后边测试服务消费者降级,我们将服务提供者controller中时间设置为5秒以内业务为正常
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="5000")
3、搭建服务消费者Consumer83
(1)创建maven工程
(2)导入依赖
引入OpenFeign、Eureka、web,服务监控,Hystrix依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!--openfeign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
(3)配置application.yml
①配置服务·端口号为83;
②配置服务名称为:Consumer83;
③配置Eureka客户端,开启注册。配置注册中心地址;
④开启Hystrix降级服务。
server:
port: 83
spring:
application:
name: consumer83
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:7001/eureka
feign:
hystrix:
enabled: true #如果处理自身的容错就开启。开启方式与生产端不一样。
(4)创建主启动类
开启Eureka客户端,远程条用Feign客户端,Hystrix服务
@EnableEurekaClient
@SpringBootApplication
@EnableFeignClients
@EnableHystrix
public class Consumer83 {
public static void main(String[] args) {
SpringApplication.run(Consumer83.class,args);
}
}
(5)创建远程调用服务接口
①@FeignClient注解,指定远程调用的服务名称,服务提供者Provider80、Provider81对应名称为:provider。
②接口中方法为:调用服务的controller方法。
@Component
@FeignClient(value = "PROVIDER")
public interface FeignService {
//调用远程接口
@GetMapping("/provider")
public String hello();
}
(6)创建controller
远程调用服务时间超过1.5秒就会自动降级。
@RestController
public class FeignController {
//调用远程服务接口
@Autowired
private FeignService feignService;
@GetMapping("consumer")
public String hello(){
//调用接口
return feignService.hello();
}
//超时降级演示
@HystrixCommand(fallbackMethod = "TimeoutHandler",commandProperties = {
//超过1.5秒就降级自己
@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value="1500")
})
@GetMapping("time")
public String time(){
return feignService.timeout();
}
//降级方法
public String TimeoutHandler(){
return "远程调用服务超时,调用失败";
}
}
4、测试案例
①启动Eureka7001
②启动Provider80
③启动·Consumer83
④访问http://localhost:83/time
由于远程服务需要3秒后才能处理结果,而设置超时时间为1.5秒,所以服务消费者自动调用降级后的方法。
三、服务熔断
1、熔断设置参数
①circuitBreaker.enabled:是否开启熔断;
②circuitBreaker.requestVolumeThreshold:当前服务失败几次后开启断路,默认20次;
③circuitBreaker.sleepWindowInMilliseconds:设置断路时间,过了该时间后会尝试恢复,在断路时间内,即使请求正确也会走降级方法;
2、熔断类型
(1)熔断打开
熔断打开后,在此时间内不会对该服务进行调用,而是直接访问降级方法。通过设置熔断时间,当达到该时间后,会尝试恢复该服务。
(2)熔断关闭
熔断关闭代表服务正常,不会干扰正常服务调用。
(3)熔断半开
熔断半开时,请求可以访问服务,若请求正常访问,则熔断会关闭;若请请求不正常,继续熔断,调用降级方法。