8. Spring Cloud服务容错,Hystrix(Finchley版本)

  • 项目地址完整例子传送门
  • 此篇文章用到项目模块:
  • 模块介绍:
    1. eureka-server-standalone: 提供注册中心的服务
    2. hystrix-client:提供接口服务
    3. hystrix-consumer: 消费接口服务,包含hystrix模块功能
  • 官方文档:
    1. Spring Cloud Hystrix介绍以及使用方式
    2. Spring Cloud Hystrix官方项目
    3. Netflix官网开源的Hystrix项目

一.Spring Cloud Hystrix使用

  • 在微服务的架构中,服务间通常会形成相互依赖的关系,比如现在有三个微服务节点:A,B和C,B为A的消费者,C为B的消费者。假如由于网络波动或者A服务自身故障,导致B调用A服务的线程被挂起进入长时间的等待。在高并发的情况下可能导致B的资源被耗竭随之崩溃,从而导致C服务也不可用。这种连环式的雪崩效应在微服务中较为常见,为了解决这个问题,服务熔断技术应运而出。熔断一词来自电路学,指的是电路在出现短路状况时,“断路器”能够及时地切断故障电路,避免电路过载发热引发火灾。
  • 类似的,微服务架构中的断路器能够及时地发现故障服务,并向服务调用方返回错误响应,而不是长时间的等待。Spring Cloud Hystrix在Hystrix(又是一款由Netflix开发的开源软件,Github地址)的基础上进行了封装,提供了服务熔断,服务降级,线程隔离等功能,通过这些功能可以提供服务的容错率。

1.创建接口提供hystrix-client服务

  • pom.xml文件中引入eureka-client依赖和spring-boot-web依赖

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>
    <groupId>com.friendsgroupId>
    <artifactId>hystrix-clientartifactId>
    <version>0.0.1-SNAPSHOTversion>
    <name>hystrix-clientname>
    <description>Demo project for Spring Clouddescription>
    <parent>
        <groupId>org.friendsgroupId>
        <artifactId>centralparkartifactId>
        <version>1.0-SNAPSHOTversion>
    parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
    dependencies>
project>

  • 启动类中没有特殊引入,如下
@SpringBootApplication
@EnableDiscoveryClient
public class HystrixClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(HystrixClientApplication.class, args);
    }
}
  • 创建接口类HystrixClientController.java用于提供接口服务
@RestController
public class HystrixClientController {
    @Qualifier("eurekaRegistration")
    @Autowired
    private Registration registration;
    @GetMapping("getInstanceInfo")
    public String  getInstanceInfo(){
        String serviceId = registration.getServiceId();
        String host = registration.getHost();
        int port = registration.getPort();
        return serviceId+":"+port+";  "+"\n host:"+host;
    }
}

Registration:用于获取本实例信息,例如服务名称,host,端口等

  • application.yml中,写入注册中心地址和服务名称
spring:
  profiles:
    active: hystrixClient8601
  application:
    name: hystrixClient
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
---
server:
  port: 8601
spring:
  profiles: hystrixClient8601
---
server:
  port: 8602
spring:
  profiles: hystrixClient8602

2.创建带hystrix保护服务端项目:hystrix-consumer

  • pom.xml文件中引入spring-cloud-starter-netflix-hystrix依赖

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>
    <groupId>com.friendsgroupId>
    <artifactId>hystrix-consumerartifactId>
    <version>0.0.1-SNAPSHOTversion>
    <name>hystrix-consumername>
    <description>Demo project for Spring Clouddescription>
    <parent>
        <groupId>org.friendsgroupId>
        <artifactId>centralparkartifactId>
        <version>1.0-SNAPSHOTversion>
    parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-actuatorartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-hystrixartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.cloudgroupId>
            <artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
        dependency>
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-webartifactId>
        dependency>
    dependencies>
project>
  • 启动类中引入带有ribbon负载均衡的模板和@SpringCloudApplication的注解
@SpringCloudApplication
public class HystrixConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(HystrixConsumerApplication.class, args);
    }
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}
  • 开启hystrix可以使用@EnableHystrix注解也可以使用@EnableCircuitBreaker,两者是等价的
  • @SpringCloudApplication是一个全家桶的注解,包含了@SpringBootApplication@EnableDiscoveryClient(服务发现),@EnableCircuitBreaker(服务容错)的功能
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public @interface SpringCloudApplication {
}
  • 创建接口类HystrixConsumerApplicationController.java用于实现hystrix具体功能
@RestController
public class HystrixConsumerApplicationController {

   @Autowired
    HystrixConsumerApplicationServer hystrixConsumerApplicationServer;

    @GetMapping("getInstanceInfo")
    public String  getInstanceInfo(){
       return hystrixConsumerApplicationServer.getInstanceInfo();
    }

   
  @Service
  class HystrixConsumerApplicationServer{
      @Autowired
      private RestTemplate restTemplate;
      @HystrixCommand(fallbackMethod = "rollBack")
      public String  getInstanceInfo(){
          return restTemplate.getForObject("http://hystrixClient/getInstanceInfo",String.class);
      } 
      public String rollBack(){
          return  "降级处理";
      }  
  }
}

HystrixConsumerApplicationServer.java:作为内部类直接嵌入到了HystrixConsumerApplicationController.java
@HystrixCommand(fallbackMethod = "rollBack")指定了降级保护方法为rollBack()

  • application.yml
spring:
  application:
    name: hystrixConsumer
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
server:
  port: 8101

3.验证

  • 依次启动,注册中心eureka-server-standalone,接口服务hystrix-client,受保护的消费服务hystrix-consumer
    8. Spring Cloud服务容错,Hystrix(Finchley版本)_第1张图片
    • 打开eureka的控制面板,http://localhost:8761/如下:
      8. Spring Cloud服务容错,Hystrix(Finchley版本)_第2张图片
  • 访问http://localhost:8101/getInstanceInfo返回

    hystrixClient:8601; host:localhost

  • 模拟宕机,关闭 hystrix-client再次访问http://localhost:8101/getInstanceInfo,进入到了降级方法中,返回

    降级处理

二.Hystrix的特性详解

1.服务降级

  • 在上面我们定义getInstanceInfo方法@HystrixCommand(fallbackMethod = "rollBack")指定了降级方法为rollBack,当其请求的服务失败后,进入回退方法中。如果回退方法也可能抛出异常,则回退方法中也可以再次标注@HystrixCommand进行降级。
  • 关于服务降级的更多用法见,Fallback核心特性

2.服务熔断,断路器

  • 服务降级面临的问题,当上游服务宕机,每一个请求都要去尝试请求上游服务,达到超时时间后再执行降级逻辑,这样也会产生请求堆积

  • 服务熔断的断路器就是为了解决上述问题。断路器有三个重要参数:快照时间窗、请求总数下限、错误百分比下限。这个参数的作用分别是:

    1. 快照时间窗:断路器确定是否打开需要统计一些请求和错误数据,而统计的时间范围就是快照时间窗,默认为最近的10秒。
    2. 请求总数下限:在快照时间窗内,必须满足请求总数下限才有资格根据熔断。默认为20,意味着在10秒内,如果该hystrix命令的调用此时不足20次,即时所有的请求都超时或其他原因失败,断路器都不会打开。
    3. 错误百分比下限:当请求总数在快照时间窗内超过了下限,比如发生了30次调用,如果在这30次调用中,有16次发生了超时异常,也就是超过50%的错误百分比,在默认设定50%下限情况下,这时候就会将断路器打开。
  • 那么当断路器打开之后会发生什么呢?我们先来说说断路器未打开之前,对于之前那个示例的情况就是每个请求都会在当hystrix超时之后返回fallback,每个请求时间延迟就是近似hystrix的超时时间,如果设置为5秒,那么每个请求就都要延迟5秒才会返回。当熔断器在10秒内发现请求总数超过20,并且错误百分比超过50%,这个时候熔断器打开。打开之后,再有请求调用的时候,将不会调用主逻辑,而是直接调用降级逻辑,这个时候就不会等待5秒之后才返回fallback。通过断路器,实现了自动地发现错误并将降级逻辑切换为主逻辑,减少响应延迟的效果。

  • 在断路器打开之后,处理逻辑并没有结束,我们的降级逻辑已经被成了主逻辑,那么原来的主逻辑要如何恢复呢?对于这一问题,hystrix也为我们实现了自动恢复功能。当断路器打开,对主逻辑进行熔断之后,hystrix会启动一个休眠时间窗,在这个时间窗内,降级逻辑是临时的成为主逻辑,当休眠时间窗到期,断路器将进入半开状态,释放一次请求到原来的主逻辑上,如果此次请求正常返回,那么断路器将继续闭合,主逻辑恢复,如果这次请求依然有问题,断路器继续进入打开状态,休眠时间窗重新计时。

3.异常处理

  • 在请求发生异常时我们希望在降级方法中捕获到异常并自定义进行处理,这是就需要在回退方法参数签名中添加Throwable t用来捕获异常
  • @HystrixCommand中除了自身HystrixBadRequestException异常为其余的异常都会进入降级方法中,如果们希望忽略某个异常添加@HystrixCommandignoreExceptions属性进行忽略
  • 在上述例子中,HystrixConsumerApplicationServer中添加方法
  @HystrixCommand(fallbackMethod = "rollBackException",ignoreExceptions = {NullPointerException.class})
      public String hystrixHandleException(String name) {
          throw new RuntimeException("throw hystrixHandleException");
      }
     public String rollBackException(String name,Throwable t){
          return  name+":   "+t.getMessage();
      }
  • HystrixConsumerApplicationController.java
	@GetMapping("hystrixHandleException")
    public String  hystrixHandleException(String name){
        return hystrixConsumerApplicationServer.hystrixHandleException(name);
    }
  • 访问hystrixHandleException接口可以看到降级方法获取到了抛出的异常

上一篇:Spring Cloud 分布式配置中心,配置文件子目录存储以及高可用 ,Spring Cloud Config(Finchley版本)
下一篇:Spring Cloud Hystrix熔断的监控面板,Dashboard详解(Finchley版本)

你可能感兴趣的:(#,Spring,Cloud)