Procesamiento de tolerancia a fallas Hystrix de 6-Spring Cloud (Parte 1)
- 1. Introducción
- 2. Procesamiento de tolerancia a fallas de Hystrix
-
- 2.1 Construcción del proyecto (Ribbon integra Hystrix)
- 2.2 Degradación del servicio
- 2.3 Disyuntor de servicio
- 2.4 Uso difuso (¿disyuntor? ¿Rebajado de categoría?)
- 3. Feign integra el procesamiento de tolerancia a fallas de Hystrix
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.
- El usuario vuelve a intentarlo:
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
- Este artículo es una continuación del artículo anterior, por lo que algunos clústeres o servicios no se presentan a continuación. Por ejemplo, el clúster Eureka todavía se inicia sobre la base de los anteriores. La introducción de los artículos anteriores es la siguiente:
- 1-Registro y descubrimiento del servicio Eureka y construcción de clústeres Eureka (práctico) .
- 2-Eureka de Spring Cloud elimina rápidamente los servicios no válidos
- 3-Construcción del equilibrio de carga de Ribbon en Spring Cloud: operación práctica en el servidor (Parte 1)
- 4-Construcción del equilibrio de carga de Ribbon en Spring Cloud: operación práctica en el servidor (Parte 2)
- 5-Uso de Feign en Spring Cloud: operación práctica en el servidor .
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:
2.1.2 archivo pom
-
como sigue:
<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:
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:
2.1.5 Clase de inicio
- como sigue:
2.1.6 controlador
-
como sigue:
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:
- Inicie el consumidor de servicios recién creado y acceda a él de la siguiente manera:
- 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)
-
Luego visite nuevamente para ver el efecto (cambios en el proceso):
- Primero
Connection refused (Connection refused)
(Esto significa que el servicio no está disponible.)
- Entonces, otra vez,
No instances available
pero esta situación es normal porque has detenido el servicio.
- Primero
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容错处理能力
-
Métodos en el controlador
@HystrixCommand(fallbackMethod = "errorHello")
/** * @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:
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:
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);
-
Inicie el servicio. Para mayor comodidad, inícielo localmente directamente.
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:
2.3.3.2.2 Agregar procesamiento de fusibles
- Registros del proveedor de servicios, de la siguiente manera:
- Servir a los consumidores
- Página, si eres cliente, se ve mucho más cómoda.
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:
@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:
2.4.2.2 Efecto después de encender el fusible
-
Primero pruebe el dog_num que no causará errores, de la siguiente manera:
-
Se producirá un error al realizar la prueba nuevamente, de la siguiente manera:
-
No debería haber ningún error al hacer clic nuevamente, de la siguiente manera:
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.
- Mira el código original primero.
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
- Modifique la anotación de la siguiente manera.
@FeignClient(value = "DOG-PROVIDER",fallback = DogClientApiImpl.class) //方式1
3.1.1.2 Método 2
-
Agregue la clase de implementación de la siguiente manera:
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
3.1.2 Año del consumidor
- Configure el archivo yml del consumidor (¡¡no lo olvide !!!)
feign: hystrix: enabled: true
3.1.3 Ver el efecto
- Inicie el servicio y vea el efecto.
- Luego desconecte el proveedor de servicios y vea el efecto
. Bueno, eso es todo. El otro método tiene el mismo efecto. Si está interesado, pruébelo usted mismo.