Procesamiento de tolerancia a fallas Hystrix de 6-Spring Cloud (Parte 1)

Procesamiento de tolerancia a fallas Hystrix de 6-Spring Cloud (Parte 1)

1. Introducción

1.1 Sobre las avalanchas

1.1.1 ¿Qué es una avalancha catastrófica?

  • Los microservicios se llaman entre sí, porque una falla del servicio en la cadena de llamadas imposibilita una serie de servicios, es decir, todo el enlace es inaccesible.

1.1.2 Causas de avalancha de servicio

  • El proveedor de servicios no está disponible.
    Por ejemplo: falla de hardware, error de programa, falla de caché, solicitudes simultáneas excesivas (como Double Eleven), etc.
    en,Desglose de cachéPor lo general, ocurre cuando se reinicia la aplicación de almacenamiento en caché, se borran todos los cachés y cuando una gran cantidad de cachés caducan en un corto período de tiempo. Una gran cantidad de errores de caché provocan solicitudes para acceder directamente al backend, lo que provoca que el proveedor de servicios se sobrecargue y el servicio deje de estar disponible.
  • La persona que llama al servicio no está disponible.
    Por ejemplo: agotamiento de recursos causado por el bloqueo de solicitudes sincrónicas.
  • Inténtelo de nuevo con mayor tráfico. como:
    • El usuario vuelve a intentarlo:
      después de que el proveedor de servicios no está disponible, el usuario sigue actualizando la página e incluso envía el formulario porque no puede soportar la larga espera en la interfaz.
    • Lógica de reintento de código:
      el extremo que llama del servicio tiene una gran cantidad de lógica de reintento después de las excepciones del servicio.

1.1.3 Cómo prevenir los efectos catastróficos de las avalanchas

  • degradación del servicio
  • Disyuntor de servicio
  • solicitar caché

1.2 Introducción previa

2. Procesamiento de tolerancia a fallas de Hystrix

2.1 Construcción del proyecto (Ribbon integra Hystrix)

2.1.1 Estructura del proyecto

  • Para que el proyecto general aparezca en orden y tenga una jerarquía más clara, este proyecto crea directamente un nuevo Módulo. Se puede entender que este proyecto es una versión mejorada de dog-consumer-80, que simplemente agrega Hystrix a la Cinta.
  • La estructura del proyecto es la siguiente:
    Insertar descripción de la imagen aquí

2.1.2 archivo pom

  • como sigue:
    Insertar descripción de la imagen aquí

    <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.0</modelVersion>
        <parent>
            <groupId>com.liu.susu</groupId>
            <artifactId>dog-cloud-parent</artifactId>
            <version>1.0-SNAPSHOT</version>
        </parent>
    
        <artifactId>dog-consumer-ribbon-hystrix-80</artifactId>
        <packaging>jar</packaging>
    
        <name>dog-consumer-ribbon-hystrix-80</name>
        <url>http://maven.apache.org</url>
    
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>com.liu.susu</groupId>
                <artifactId>dog-po</artifactId>
                <version>${project.version}</version>
            </dependency>
    
            <!--版本同${spring-boot.version}-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <!--引入ribbon相关依赖,ribbon是客户端的负载均衡,ribbon需要和eureka整合-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-ribbon</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-config</artifactId>
            </dependency>
    
            <!--引入Hystrix相关依赖-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-hystrix</artifactId>
            </dependency>
    
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <scope>test</scope>
            </dependency>
    
        </dependencies>
    </project>
    
    

2.1.3 archivo yml

  • como sigue:
    Insertar descripción de la imagen aquí

    server:
      port: 80
    
    spring:
      application:
        name: dog-consumer-ribbon-hystrix
    
    eureka:
      client:  # 客户端注册进eureka服务列表内
        register-with-eureka: false  # false表示不向注册中心注册自己
        service-url:
          defaultZone: http://IP1:2886/eureka/,http://IP2:2886/eureka,http://IP3:2886/eureka/
    

2.1.4 Clase de configuración

  • como sigue:
    Insertar descripción de la imagen aquí

2.1.5 Clase de inicio

  • como sigue:
    Insertar descripción de la imagen aquí

2.1.6 controlador

  • como sigue:
    Insertar descripción de la imagen aquí

    package com.liu.susu.controller;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;
    
    /**
     * @Description
     * @Author susu
     */
    
    @RestController
    public class DogConsumerController {
          
          
    
        private static final String REST_URL_PREFIX = "http://DOG-PROVIDER";
        @Autowired
        private RestTemplate restTemplate;
    
        @RequestMapping(value = "/consumer/dog/hello")
        public String hello(){
          
          
            System.out.println("==============================");
            String url = REST_URL_PREFIX + "/dog/hello";
            return restTemplate.getForObject(url, String.class);
        }
        
        /**
         * http://localhost:80/consumer/dog/getDogByNum/1
         * http://localhost/consumer/dog/getDogByNum/1
         */
        @RequestMapping("/consumer/dog/getDogByNum/{dogNum}")
        public Object getDogByNum(@PathVariable("dogNum") Long dogNum){
          
          
            String url = REST_URL_PREFIX + "/dog/getDogByNum/" + dogNum;
            return restTemplate.getForObject(url, Object.class);
        }
    }
    
    

2.1.7 Iniciar para garantizar que el servicio esté disponible

  • Debido a que el clúster Eureka y varios proveedores de servicios no se han detenido, compruébelo de la siguiente manera:
    Insertar descripción de la imagen aquí
  • Inicie el consumidor de servicios recién creado y acceda a él de la siguiente manera:
    Insertar descripción de la imagen aquí
  • Después de asegurarse de que no hay problemas, puede continuar simulando la degradación del servicio y el disyuntor, continúe...

2.1.8 El servicio remoto de demostración no está disponible

2.1.8.1 Demostración sencilla

  • Ahora detenga a todos esos proveedores de servicios (cuando se detuvieron por primera vez, todavía estaban en el centro de registro, vea el tiempo de latido establecido)
    Insertar descripción de la imagen aquí

    Insertar descripción de la imagen aquí

  • Luego visite nuevamente para ver el efecto (cambios en el proceso):

    • Primero Connection refused (Connection refused)(Esto significa que el servicio no está disponible.
      Insertar descripción de la imagen aquí
    • Entonces, otra vez, No instances available
      pero esta situación es normal porque has detenido el servicio.
      Insertar descripción de la imagen aquí

2.1.8.2 El servicio remoto es normal y anormal

  • El servicio remoto es normal
    • Hay resultados devueltos.
    • Se pasa una excepción
  • Error de servicio remoto
    • El servicio remoto no está disponible (acceso denegado)
    • Tiempo de espera de respuesta del servicio remoto

2.2 Degradación del servicio

2.2.1 En pocas palabras, degradación del servicio

  • La degradación del servicio se refiere al cierre temporal de algunos servicios sin importancia o la devolución de algunos datos simples almacenados en caché para garantizar el funcionamiento normal de los servicios principales cuando un servicio falla o es anormal. La degradación del servicio puede reducir efectivamente el tiempo de respuesta del servicio y la tasa de error y mejorar la disponibilidad del sistema.

    Es decir: la degradación del servicio es una asignación razonable de los recursos generales del sistema. Distinguir entre servicios básicos y servicios no básicos. Hacer una estimación del tiempo de retraso en el acceso, anormalidad, etc. de un determinado servicio y proporcionar un método para evitarlo. Esta es una consideración global, considerando la carga total.

2.2.2 Simulación de la degradación del servicio

  • A continuación, simulamos un tiempo de espera.
    • Cuando el servicio no se degrada, si diseñamos deliberadamente un tiempo de espera, no importa cuánto tiempo de espera sea, SpringCloud esperará la llamada remota. Puedes probarlo tú mismo, pero no lo demostraré aquí.
  • El código central para simular el tiempo de espera del servicio y el procesamiento de degradación es el siguiente:
    • clase de inicio

      @EnableHystrix    //开启Hystrix容错处理能力
      

      Insertar descripción de la imagen aquí

    • Métodos en el controlador

      @HystrixCommand(fallbackMethod = "errorHello")
      

      Insertar descripción de la imagen aquí

          /**
           * @EnableHystrix 启动类上注解,开启Hystrix容错处理能力
           * @HystrixCommand 代表当前方法是一个需要做容错处理的方法
           * @EnableHystrix 结合 @HystrixCommand,默认地配置了一个远程服务超时配置,默认设置超时是1秒
           */
          @RequestMapping(value = "/consumer/dog/hello")
          @HystrixCommand(fallbackMethod = "errorHello")
          public String hello(){
              
              
              System.out.println("==============================");
      
              //默认情况下,SpringCloud远程调用时,不管多久都会等
              try {
              
              
                  Thread.sleep(3000);
              } catch (InterruptedException e) {
              
              
                  throw new RuntimeException(e);
              }
      
              String url = REST_URL_PREFIX + "/dog/hello";
              return restTemplate.getForObject(url, String.class);
          }
      
      	/**
           * 降级方法
           *   1、返回类型要和对应的服务方法的返回类型一致
           *   2、参数和对应的服务方法要一致
           *   3、返回的内容:远程服务访问错误时(比如超时),返回的拖底数据
           */
          public String errorHello(){
              
              
              return "服务器忙,请稍后再试!";
          }
      

2.2.3 Ver el efecto

  • como sigue:
    Insertar descripción de la imagen aquí

    Insertar descripción de la imagen aquí

2.3 Disyuntor de servicio

2.3.1 En pocas palabras, disyuntor de servicio

  • La fusión de servicios significa que cuando un servicio falla o es anormal, la conexión al servicio se desconecta para evitar que el servicio continúe aceptando solicitudes, evitando así la propagación de la falla y restaurando rápidamente la disponibilidad del servicio. La fusión de servicios generalmente detecta la disponibilidad de los servicios de acuerdo con una determinada estrategia. Si el tiempo de respuesta o la tasa de error del servicio excede un cierto umbral, se activará el mecanismo de fusión, se desconectará la conexión al servicio y luego la conexión reintentar periódicamente hasta que el servicio sea normal.
  • Es decir: el disyuntor de servicio generalmente estáUn fallo de servicio ( servicio descendente )causado, y la degradación del servicio generalmente se considera a partir de la carga general

2.3.2 Simular el disyuntor de servicio 1 (detener el servicio)

2.3.2.1 Código de degradación

  • como sigue:

        @RequestMapping("/consumer/dog/getDogByNum/{dogNum}")
        @HystrixCommand(fallbackMethod = "errorGetDogByNum",commandProperties = {
          
          
           //是否开启熔断机制
           @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_ENABLED,value = "true"),
            //一个时间窗内,发生远程访问错误的次数阈值,达到开启熔断
           @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD,value = "3"),
            //一个时间窗内,发生远程访问错误的百分比,达到则开启熔断
           @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE,value = "20"),
            //开启熔断后,多少毫秒内,不发起远程服务访问
           @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS,value = "3000")
    
        })
        public Object getDogByNum(@PathVariable("dogNum") Long dogNum){
          
          
            System.out.println("本地测试熔断....");
    
            String url = REST_URL_PREFIX + "/dog/getDogByNum/" + dogNum;
            return restTemplate.getForObject(url, Object.class);
        }
    
        public Object errorGetDogByNum(Long dogNum){
          
          
            System.out.println("进入熔断,dogNum是:===>"+dogNum);
            return "熔断——服务器忙,请稍后再试!";
        }
    

2.3.2.2 Ver el efecto

  • Detenga el proveedor de servicios de la siguiente manera:
    Insertar descripción de la imagen aquí
    Insertar descripción de la imagen aquí

    Insertar descripción de la imagen aquí

2.3.3 Disyuntor 1 del servicio de simulación (excepción de simulación del servidor)

2.3.3.1 Modificar proveedor de servicios

  • Modifique el código de la siguiente manera

       System.out.println("进入服务提供者,模拟异常....");
       System.out.println(2 / dogNum);
    

    Insertar descripción de la imagen aquí

  • Inicie el servicio. Para mayor comodidad, inícielo localmente directamente.
    Insertar descripción de la imagen aquí

2.3.3.2 Ver el efecto

2.3.3.2.1 Comentar el procesamiento del disyuntor
  • 500 dolor de cabeza, todavía no sé qué lo causó, tengo que ir al proveedor de servicios para abrir el registro, de la siguiente manera:
    Insertar descripción de la imagen aquí
    Insertar descripción de la imagen aquí
2.3.3.2.2 Agregar procesamiento de fusibles
  • Registros del proveedor de servicios, de la siguiente manera:
    Insertar descripción de la imagen aquí
  • Servir a los consumidores
    Insertar descripción de la imagen aquí
  • Página, si eres cliente, se ve mucho más cómoda.
    Insertar descripción de la imagen aquí

2.4 Uso difuso (¿disyuntor? ¿Rebajado de categoría?)

  • Concepto difuso: el disyuntor de servicio es una versión mejorada de la degradación del servicio. Por lo tanto, si el error ocurre en el lado del consumidor, también puede usar el disyuntor de servicio, y el efecto es similar al anterior.
  • El siguiente es el error en el disyuntor de servicio del lado del consumidor, de la siguiente manera:

2.4.1 Código (el código del servidor es normal, el código del consumidor simula una excepción)

  • como sigue:
    Insertar descripción de la imagen aquí

        @RequestMapping("/consumer/dog/getDogByNum/{dogNum}")
        @HystrixCommand(fallbackMethod = "errorGetDogByNum",commandProperties = {
          
          
           //是否开启熔断机制
           @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_ENABLED,value = "true"),
            //一个时间窗内,发生远程访问错误的次数阈值,达到开启熔断
           @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD,value = "3"),
            //一个时间窗内,发生远程访问错误的百分比,达到则开启熔断
           @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE,value = "20"),
            //开启熔断后,多少毫秒内,不发起远程服务访问
           @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS,value = "3000")
    
        })
        public Object getDogByNum(@PathVariable("dogNum") Long dogNum){
          
          
            System.out.println("本地测试熔断....");
    
            System.out.println(2 / dogNum);
    
            String url = REST_URL_PREFIX + "/dog/getDogByNum/" + dogNum;
            return restTemplate.getForObject(url, Object.class);
        }
    
        public Object errorGetDogByNum(Long dogNum){
          
          
            System.out.println("进入熔断,dogNum是:===>"+dogNum);
            return "熔断——服务器忙,请稍后再试!";
        }
    

2.4.2 Efecto

2.4.2.1 Efecto cuando el fusible no está activado

  • como sigue:
    Insertar descripción de la imagen aquí

2.4.2.2 Efecto después de encender el fusible

  • Primero pruebe el dog_num que no causará errores, de la siguiente manera:
    Insertar descripción de la imagen aquí

  • Se producirá un error al realizar la prueba nuevamente, de la siguiente manera:
    Insertar descripción de la imagen aquí

  • No debería haber ningún error al hacer clic nuevamente, de la siguiente manera:
    Insertar descripción de la imagen aquí

3. Feign integra el procesamiento de tolerancia a fallas de Hystrix

  • Para facilitar la modificación del código directamente en el proyecto dog-api, existen dos formas:
    • Mira el código original primero.
      Insertar descripción de la imagen aquí

3.1 Código central

3.1.1 Clases de implementación y anotaciones

3.1.1.1 Método 1

  • Agregue la clase de implementación de la siguiente manera
    Insertar descripción de la imagen aquí
  • Modifique la anotación de la siguiente manera.
    @FeignClient(value = "DOG-PROVIDER",fallback = DogClientApiImpl.class) //方式1
    
    Insertar descripción de la imagen aquí

3.1.1.2 Método 2

  • Agregue la clase de implementación de la siguiente manera:
    Insertar descripción de la imagen aquí

    package com.liu.susu.api;
    
    import com.liu.susu.pojo.Dog;
    import feign.hystrix.FallbackFactory;
    import org.springframework.stereotype.Component;
    
    import java.util.List;
    
    /**
     * @Description
     * @Author susu
     */
    @Component
    public class DogClientApiFallbackFactory implements FallbackFactory<DogClientApi> {
          
          
    
        @Override
        public DogClientApi create(Throwable throwable) {
          
          
            return new DogClientApi() {
          
          
                @Override
                public String hello() {
          
          
                    System.out.println("进入 DogClientApiFallbackFactory 服务降级--->hello");
                    return "DogClientApiFallbackFactory 服务降级处理,请稍后再试";
                }
    
                @Override
                public Object getDogByNum(Long dogNum) {
          
          
                    return null;
                }
    
                @Override
                public List<Dog> getAllDog() {
          
          
                    return null;
                }
            };
        }
    }
    
    
  • Modifique la anotación de la siguiente manera:

    @FeignClient(value = "DOG-PROVIDER",fallbackFactory = DogClientApiFallbackFactory.class) //方式2
    

    Insertar descripción de la imagen aquí

3.1.2 Año del consumidor

  • Configure el archivo yml del consumidor (¡¡no lo olvide !!!)
    Insertar descripción de la imagen aquí
    feign:
      hystrix:
        enabled: true
    

3.1.3 Ver el efecto

  • Inicie el servicio y vea el efecto.
    Insertar descripción de la imagen aquí
  • Luego desconecte el proveedor de servicios y vea el efecto
    Insertar descripción de la imagen aquí
    Insertar descripción de la imagen aquí
    . Bueno, eso es todo. El otro método tiene el mismo efecto. Si está interesado, pruébelo usted mismo.

Supongo que te gusta

Origin blog.csdn.net/suixinfeixiangfei/article/details/131598220
Recomendado
Clasificación