SpringCloud Alibaba de principiante a competente - Sentinel

SpringCloud Alibaba de principiante a competente - Sentinel

1. Construcción de infraestructura

La demostración que se muestra aquí se gestiona a través del proyecto padre-hijo de Maven. Los beneficios de utilizar la gestión de observación entre padres e hijos son:

  • 1. El código está centralizado para facilitar la gestión centralizada, descargar
  • 2. La gestión centralizada tiene menores costos de aprendizaje y los proyectos son más fáciles de aceptar

1. Creación del proyecto principal

Utilice IDEA. archivo–>nuevo–>proyecto–>maven para crear el proyecto principal. El proyecto principal debe estar en pom, para que el proyecto principal pueda lograr el propósito de administrar subproyectos cuando compilamos. Si no está en pom, No se puede crear en el proyecto principal. El subproyecto se creó correctamente.
Esta demostración adopta una gestión de versiones centralizada, solo necesitamos limitar las siguientes tres versiones:Solo necesita colocarlos en dependencyManagement para especificar la versión y declarar el tipo y el alcance al mismo tiempo para lograr el control de versión del componente global. La función es similar a la etiqueta principal, pero el padre solo puede declarar un proyecto principal para administrar las dependencias de la versión. y colóquelo en La dependencia de dependencyManagement puede admitir múltiples dependencias.

  • Versión de SpringBoot: 2.6.11
  • Versión de SpringCloud: 2021.0.4
  • Versión de SpringCould Alibaba: 2021.0.4.0

Si no tiene clara la correspondencia de versiones entre alibaba, nube y arranque, puede consultar aquí: Dependencias de la versión del componente SpringCloud

<dependencyManagement>
	<dependencies>
		<dependency>
		    <groupId>com.alibaba.cloud</groupId>
		    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
		    <version>${Spring-cloud-alibaba-version}</version>
		    <type>pom</type>
		    <scope>import</scope>
		</dependency>
	<dependencies>	
</dependencyManagement>

El siguiente es el archivo pom completo del proyecto principal.

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <!--这里不使用parent来管理整体的jar的版本,统一放在dependencymanager中进行管理-->
    <!--<parent>-->
    <!--<groupId>org.springframework.boot</groupId>-->
    <!--<artifactId>spring-boot-starter-parent</artifactId>-->
    <!--<version>3.1.3.RELEASE</version>-->
    <!--<relativePath/> &lt;!&ndash; lookup parent from repository &ndash;&gt;-->
    <!--</parent>-->
    <groupId>com.cheng</groupId>
    <artifactId>spring-cloud-alibaba-base</artifactId>
    <packaging>pom</packaging>
    <version>1.0.0</version>
    <modules>
        <module>order-server</module>
        <module>stock-server</module>
    </modules>

    <name>spring-cloud-alibaba-base</name>
    <description>alibaba父工程</description>
    <properties>
        <java.version>8</java.version>
        <Spring-boot-version>2.6.11</Spring-boot-version>
        <Spirng-cloud-version>2021.0.4</Spirng-cloud-version>
        <Spring-cloud-alibaba-version>2021.0.4.0</Spring-cloud-alibaba-version>
    </properties>

    <dependencyManagement>
        <!--通过此模块来规范boot和cloud的所有组件版本,所有的子工程将不需要考虑组件的版本问题-->
        <dependencies>
            <!--这种写法和写在parent中作用一样,注意type和scope不可省略-->
            <!--这种写法的优点是可以声明多个父级的项目包版本依赖,而parent只能由一个-->
            <!--这是springboot相关包的版本管理-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>${Spring-boot-version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!--这是alibaba组件的版本管理-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${Spring-cloud-alibaba-version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!--这是cloud的组件的版本管理,也可以使用pring-cloud-dependencies-parent,但是使用下面的更好-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${Spirng-cloud-version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>

    </dependencyManagement>


    <!--dependencies中的包会直接被子工程继承,而dependencyManagement的包不手动引入,则不会继承-->
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

2. Creación de subproyectos

La creación de subproyectos es la misma. Aquí hay un ejemplo: haga clic derecho en el proyecto principal->nuevo->módulo->spring-initializr. Spring-initializr no se usa aquí. Maven también está disponible, pero es Es más conveniente usar spring-initializr, no es necesario que creemos clases de inicio, archivos de configuración, etc., nosotros mismos. Si su IDEA es relativamente nueva (hasta donde yo sé, parece que no se puede usar a continuación de IDEA2021), también puede usar spring-initializr para especificar el andamio de terceros. Se recomienda usar la dirección de andamio de terceros de Alibaba. . https://start.aliyun.com , este andamio es más amigable para los componentes de Springcloud y también contiene más componentes de Alibaba
( nota: la versión comunitaria de IDEA no admite la función Spring Initializr )
Insertar descripción de la imagen aquí
. El siguiente es el archivo pom de subproyecto:

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.cheng</groupId>
        <artifactId>spring-cloud-alibaba-base</artifactId>
        <version>1.0.0</version>
    </parent>
    <groupId>com.cheng</groupId>
    <artifactId>order-server</artifactId>
    <version>1.0.0</version>
    <name>order-server</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

En este punto, simplemente construimos un estante y luego introducimos diferentes componentes y dependencias para cada servicio.
Si cree que la creación anterior de proyectos padre-hijo no es lo suficientemente detallada, se recomienda leer aquí: Explicación detallada de la creación de proyectos padre-hijo con Maven

2. Integración de Sentinel con Spring Cloud

Para obtener una introducción detallada a Sentinel, consulte la documentación oficial:
Sitio web oficial de Sentinel
El github de Sentinel será más detallado aquí.

1. Posibles problemas con los microservicios

  • 1. El tráfico aumenta y la capacidad de la CPU es demasiado alta para manejar las solicitudes normalmente.
  • 2. Fallo de la caché causado por datos que no se calientan
  • 3. Demasiados mensajes generan una acumulación de mensajes
  • 4. SQL lento hace que la conexión a la base de datos esté llena
  • 5. El sistema de terceros no responde y los clics repetidos hacen que el hilo se llene.
  • 6. La memoria anormal del sistema no se puede liberar normalmente OOM
  • 7. Cuello de botella en la memoria del servidor, el programa se cierra de forma anormal

Los problemas anteriores pueden provocar un único punto de falla en el servicio. Si no se agrega ningún procesamiento adicional al servicio, una vez que un determinado sistema se cuelga, el sistema que depende de él también experimentará anomalías. Como resultado, se producirán problemas en el servicio. suceden uno tras otro como fichas de dominó y, finalmente, como resultado, los servicios en grandes áreas no están disponibles, lo que a menudo se denomina avalancha de servicios. La avalancha de servicios es insoportable: una vez que ocurre, el sistema básicamente no estará disponible, lo que es muy hostil para los usuarios y provocará una gran pérdida de usuarios.
Por lo tanto, necesitamos resolver el problema de la indisponibilidad del servicio en base a escenarios, para esto se utiliza Sentinel, se llama guardia de tráfico de sistemas distribuidos, su función principal es garantizar la estabilidad (confiabilidad) y la recuperación del sistema (resiliencia). ), admite mecanismos de tolerancia a fallas de múltiples sistemas, los más comunes incluyen:

  • 1. Mecanismo de tiempo de espera
    : establezca el tiempo de espera, procéselo dentro del tiempo especificado y procese la lógica del tiempo de espera después del tiempo de espera.
  • 2. El mecanismo de limitación actual
    puede controlar el proceso de servicio según QPS
  • 3. El mecanismo de aislamiento de subprocesos
    utiliza el grupo de subprocesos para gestionar las solicitudes y se pueden definir otras estrategias de procesamiento para las partes sobrantes.
  • 4. Disyuntor de servicio:
    cuando el servicio alcanza el estándar de disyuntor definido o el estándar de degradación, se realiza un procesamiento de información secundaria en el servicio, que puede ser procesamiento de cola de mensajes o puede almacenarse en la base de datos para esperar el procesamiento de coherencia final.
  • 5. Degradación del servicio
    : Creo que este sentimiento es en realidad similar al disyuntor del servicio, excepto que la granularidad del manejo de excepciones del servicio requiere un procesamiento secundario del servicio.

Sentiael ha hecho un buen trabajo en el manejo de los escenarios anteriores y puede garantizar la disponibilidad y estabilidad de los servicios en escenarios de alta concurrencia. Los productos producidos por Alibaba deben ser de alta calidad, simplemente úsalos y listo. Actualmente Sentinel es el único código abierto en el mercado. Al igual que su predecesor, hystrix ha dejado de actualizarse. Aquí una pequeña comparación:
Insertar descripción de la imagen aquí

2.SpringCloud integra Sentinel para crear un panel

Sentinel se puede integrar en cualquier proyecto Springboot, y Alibaba también proporciona un iniciador correspondiente para facilitar nuestra rápida integración de Sentinel. El iniciador proporcionado por Alibaba contiene todos los paquetes jar que necesitamos usar (excluidos los frascos que integran OpenFeign, Gateway, etc.). . Experimentémoslo juntos. No es necesario declarar que la versión utilizada aquí es coherente con la versión de nivel superior. El que realmente se utiliza es Sentinel1.8.5.

Dirección del documento oficial del panel: Consola Sentinel
Dirección de descarga del panel: Descarga de Sentinel-Dashboard
Contraseña de cuenta predeterminada del panel: Sentinel/sentinel
es muy simple de construir. Solo necesitamos descargar su jar correspondiente del sitio web oficial. Dashboard es un proyecto SpringBoot estándar. puedes iniciarlo directamente usando el comando java.

java -Dserver.port=8080 \
-Dcsp.sentinel.dashboard.server=localhost:8080 \
-Dproject.name=sentinel-dashboard \
-jar sentinel-dashboard-1.8.5.jar

Si desea cambiar el nombre de usuario y la contraseña predeterminados, puede agregar parámetros de nombre de usuario y contraseña:

java -Dserver.port=8080 \
-Dcsp.sentinel.dashboard.server=localhost:8080 \
-Dproject.name=sentinel-dashboard \
-Dsentinel.dashboard.auth.username=admin \ 
-Dsentinel.dashboard.auth.password=admin \ 
-jar sentinel-dashboard-1.8.5.jar

Si desea realizar una verificación rápida, puede iniciarlo localmente con Git Bash y puede verificar rápidamente.
Además, si no desea que el panel en sí aparezca en el panel (controlar lo que usa es realmente inútil), Puede cancelar directamente project.name y la configuración de csp.sentinel.dashboard.server está bien, de la siguiente manera:

java -Dserver.port=8080 \
-Dsentinel.dashboard.auth.username=admin \
-Dsentinel.dashboard.auth.password=admin \
-jar sentinel-dashboard-1.8.5.jar

Cuando realmente lo use, está bien usarlo.
Insertar descripción de la imagen aquí
No entraré en detalles sobre las diversas configuraciones internas, pero Zhuo Yi las presentará más adelante.

3 SpringCloud integra Sentinel

  • 1. Introduzca frascos relevantes
    <!--sentinel依赖-->
    <dependency>
       <groupId>com.alibaba.cloud</groupId>
       <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    
  • 2 Agregar configuración
    Este paso es para especificar la dirección del Panel para que Sentinel pueda comunicarse con el Panel normalmente.
    # 已省略关系不大的配置
    spring:
      application:
        # sennel使用该名称注册到Dashboard
        name: stock-server 
      cloud:
        sentinel:
          transport:
            port: 8719 # dashboard控制面版与sentinel通信的本地端口
            dashboard: 127.0.0.1:8080   # sentinel控制面板地址
    
  • 3. Pruebe si el servicio está registrado en el Panel de control normalmente.
    De forma predeterminada, el servicio no se registrará directamente en el Panel de control después de iniciarse. Solo cuando llegue una solicitud, el servicio se registrará en el Panel de control, por lo que necesitamos para simular una solicitud de servicio, y luego será normal. Cuando vea los servicios en el Panel, habrá el siguiente menú de monitoreo de configuración debajo de cada servicio. He realizado varias solicitudes aquí para poder ver los datos de monitoreo en tiempo real. Si no hay datos en tiempo real, no se mostrarán aquí.
    Insertar descripción de la imagen aquí
    De esta manera, simplemente completamos la construcción de Sentinel y Dashboard.

3. Rebaja del servicio

Antes de entrar en detalles sobre las cinco reglas, primero debemos hablar de la degradación del servicio.La degradación del servicio es una forma de mejorar la experiencia del usuario. Cuando la solicitud del usuario es rechazada debido a razones del sistema, el sistema devuelve un resultado preestablecido que es aceptable para el usuario pero no satisfactorio para el usuario. Este tipo de degradación del servicio de procesamiento de solicitudes. Cuando la degradación del servicio alcanza el umbral, se activará un disyuntor. Veamos primero los métodos de procesamiento de degradación comunes en Spring Cloud.

1 degradación del servicio: Sentinel

Aquí debe utilizar la anotación @SentinelResource de Sentinel. Esta anotación es la anotación principal de Sentinel. Hablaremos brevemente sobre el uso de esta anotación y la explicación de cada parámetro en detalle más adelante. Esta anotación solo se usa para la degradación del servicio. No es necesario registrar el recurso (se registrará solo cuando se declare el valor). Esta anotación tiene cuatro atributos relacionados con la degradación del servicio:
Introducción oficial detallada a la anotación @SentinelResource: Anotación @SentinelResource

  • retroceso y degradación de clase alternativa
  • defaultFallback y fallbackDegradación de clase
  • Atributo excepcionesToIgnore: ignorar las excepciones, las excepciones ignoradas no desencadenarán una degradación
  • 1. Degradar: el
    respaldo alternativo debe pasar una cadena, que es el nombre del método de nuestro método de procesamiento de degradación. Entonces, ¿cómo deberíamos escribir este método? El método de degradación debe seguir las siguientes reglas

    • ① El tipo de valor de retorno debe ser coherente con el tipo de valor de retorno de la función original
    • ② La lista de parámetros del método debe ser coherente con la función original, o se puede agregar un parámetro de tipo Throwable adicional para recibir la excepción correspondiente.
    • ③ La función alternativa debe estar en la misma clase que el método original de forma predeterminada. Si desea utilizar funciones de otras clases, puede especificar fallbackClass como el objeto de clase de la clase correspondiente. Tenga en cuenta que la función correspondiente debe ser una función estática (cuando se usa fallbackClass), de lo contrario no se puede analizar.

    El siguiente es un código de muestra. No es necesario agregar ninguna configuración nueva aquí. Todavía se basa en la configuración 2.2.

    import com.alibaba.csp.sentinel.annotation.SentinelResource;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cloud.context.config.annotation.RefreshScope;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @author pcc
     */
    @Slf4j
    @RefreshScope // 动态刷新nacos配置注解
    @RestController
    @RequestMapping("/stock")
    public class StockController {
          
          
    
        @Value("${name}")
        String name;
    
    
    
        @RequestMapping("/addStock")
        @SentinelResource(fallback = "addStockFallBack")
        public void addStock() throws Exception{
          
          
            int i = 1/0;
            log.info("add stock start: {}",name);
    
        }
    
        /**
         * 这是方法降级的 方法
         * 这里可以不使用 static
         * @param throwable 触发的异常
         */
        public static void addStockFallBack(Throwable throwable){
          
          
            log.info("addStock 触发方法降级: {}", throwable.getMessage());
        }
    
    }
    

    A continuación se muestra una captura de pantalla en ejecución:
    Insertar descripción de la imagen aquí

  • 2 Downgrade: fallback coopera con fallbackClass y excepcionesToIgnore.
    Si hay muchas interfaces, definitivamente es inapropiado colocar todos los métodos de downgrade en la interfaz, lo que se verá muy desordenado. Por lo tanto, en escenarios reales, siempre colocamos el método de downgrade de un controlador. en En una clase separada, luego use fallbackClass de @SentinelResource para especificar la clase correspondiente y use fallback para especificar el método de degradación, de modo que el acoplamiento entre el método de degradación y la clase de interfaz se pueda desacoplar. Aquí, el atributo excepcionesToIgnore es usados ​​juntos.
    Esta es la clase donde se degrada el servicio.

    /**
     * @author pcc
     * 这是降级类
     */
    @Slf4j
    public class StockDegrade {
          
          
        /**
         * 这是类降级的 方法
         * @param a 触发的异常
         */
        public static void addStock(Throwable a) {
          
          
            log.info("add stock 类级降级: {}",a.getMessage());
    
        }
    }
    
    

    Esta es la interfaz utilizada en la degradación:

    import com.alibaba.csp.sentinel.annotation.SentinelResource;
    import com.cheng.stockserver.sentineldegrade.StockDegrade;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cloud.context.config.annotation.RefreshScope;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @author pcc
     */
    @Slf4j
    @RefreshScope
    @RestController
    @RequestMapping("/stock")
    public class StockController {
          
          
    
        @Value("${name}")
        String name;
        
        @SentinelResource(fallback = "addStock",fallbackClass = StockDegrade.class,exceptionsToIgnore =  {
          
          ArithmeticException.class})
        @RequestMapping("/addStock")
        public void addStock() throws Exception{
          
          
            log.info("add stock start: {}",name);
            throw new RuntimeException("运行时异常");
    
        }
    
    }
    

    Como se muestra arriba, use fallbackClass para especificar la clase donde se encuentra el método de degradación y use fallback para especificar el método de degradación correspondiente. Esto le permite separar los métodos de degradación en una clase de degradación separada. En el código anterior, se lanza manualmente una RuntimeException. Si se lanza una ArithmeticException, no ingresará al método de degradación del servicio, sino que se lanzará directamente hacia arriba y el servicio generará una excepción directa (suponiendo que no haya un manejo unificado de excepciones). Y debido a que aquí solo se ignora ArithmeticException, aún ingresará al método de degradación.
    Nota especial: al especificar una clase degradada, el método degradado debe ser estático; de lo contrario, no se puede analizar.

  • 3 Degradar: defaultFallback coopera con fallback, fallbackClass, excepcionesToIgnore.
    Cuando se aplica defaultFallback a un método, es completamente consistente con el uso de fallback. Las reglas requeridas también son las mismas. Es completamente factible reemplazar fallback con defaultFallback en lo anterior. dos ejemplos. Hay dos características especiales de defaultFallback que deben mencionarse aquí:

    • defaultFallback puede modificar la clase (el documento oficial dice que será compatible a partir de 1.8.0. Debería ser el método de degradación predeterminado que admita todas las interfaces. Después de las pruebas, no es tan compatible)
    • Si defaultFallback y fallback se configuran al mismo tiempo, el respaldo tendrá efecto y defaultFallback fallará.

    A continuación se muestra quién entra en vigor cuando defaultFallbck y fallback modifican una interfaz al mismo tiempo.

    import com.alibaba.csp.sentinel.annotation.SentinelResource;
    import com.cheng.stockserver.sentineldegrade.StockDefaultDegrade;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cloud.context.config.annotation.RefreshScope;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @author pcc
     */
    @Slf4j
    @RefreshScope
    @RestController
    @RequestMapping("/stock")
    public class StockController {
          
          
    
        @Value("${name}")
        String name;
    
    
        /**
         * 这里同时使用了fallback 、defaultFallback
         * 当同时使用时,只有fallback生效
         *
         */
        @SentinelResource(
                defaultFallback = "stockDefaultFallback",
                fallback = "addStockFallback",
                fallbackClass = StockDefaultDegrade.class,
                exceptionsToIgnore = ArithmeticException.class)
        @RequestMapping("/addStock")
        public void addStock(){
          
          
            log.info("add stock start: {}",name);
            throw new RuntimeException("运行时异常1");
    
        }
        
    }
    

    Las siguientes son clases degradadas y métodos correspondientes:

    import lombok.extern.slf4j.Slf4j;
    
    /**
     * @author pcc
     * 这是defaultFallback的降级类
     */
    @Slf4j
    public class StockDefaultDegrade {
          
          
    
        /**
         * 这是默认降级方法
         * @param throwable
         */
        public static void stockDefaultFallback(Throwable throwable){
          
          
            log.info("触发defaultFallback的降级方法:" + throwable.getMessage() + " ");
        }
    
        /**
         * 这是fallback用的指定降级方法
         * @param throwable
         */
        public static void addStockFallback(Throwable throwable){
          
          
            log.info("触发addStockFallback的降级方法:" + throwable.getMessage() + " ");
        }
    }
    

    Al llamar a la interfaz correspondiente, puede encontrar que el único método de degradación que realmente se activa es el método de degradación especificado por respaldo:
    Insertar descripción de la imagen aquí

2 Sentinel integra OpenFeign

OpenFeign integra Sentinel aquí solo para demostrar el procesamiento de la degradación del servicio y no amplía otras funciones. OpenFeign integra Sentinel en sólo dos pequeños pasos.

  • 1 Importar dependencias de Sentinel
    <!--sentinel依赖-->
    <dependency>
       <groupId>com.alibaba.cloud</groupId>
       <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    
  • 2 Habilite la compatibilidad de Sentinel con OpenFeign
    y configúrelo en yml o propiedades.
    # 已省略关系不大的配置
    feign:
      sentinel:
        enabled: true # 开启sentinel对feign的支持
    
    Podemos usarlo directamente sin agregar configuración adicional a Sentinel.

3 OpenFeign define la degradación del servicio

OpenFeign admite dos formas de degradar los servicios, pero necesitan integrar Sentinel o Hystrix. Aquí tomamos la integración de Sentinel como ejemplo.

  • 1 Utilice el respaldo para especificar la clase de degradación en FeignClient
  • 2 Utilice fallbackFactory para especificar la clase de degradación en FeignClient

Dado que ambos son compatibles, debe haber diferencias entre ellos. La principal diferencia es que Fallback no puede obtener excepciones, pero FallbackFactory puede conocer excepciones específicas, porque conocer las excepciones específicas puede realizar un procesamiento diferente de acuerdo con diferentes excepciones, por lo que en escenarios reales La mayoría de ellos use fallbackFactory (también hay algunos que usan respaldo). Se describen en detalle a continuación:

    1. Descenso del servicio de respaldo
      El uso del respaldo debe cumplir las siguientes condiciones
      1. La clase especificada por respaldo debe ser administrada por el contenedor Spring
      1. La clase especificada por respaldo debe implementar la interfaz de simulación modificada por FeignClient

    De esta manera, podemos entregar la clase al respaldo. Una vez que ocurre una excepción, se introducirá en el método correspondiente que anulamos. El siguiente es el código de prueba:
    Este es el código de interfaz de simulación:

    import org.springframework.cloud.openfeign.FeignClient;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    /**
     * @author pcc
     * url: 用于指定三方接口,通过url指定的接口不会从注册中心获取服务列表,而是直接通过接口名拼接地址
     * name:用以声明feign调用的服务,这个必须与注册中心服务名保持一致
     * path:控制器上的类路径,如果不写path在方法上写全路径也是一样的
     * configuration:配置类,可以配置一些公共的参数,只对当前类下的接口生效,属于局部配置
     * fallback : 声明降级类
     *
     */
    @FeignClient(name = "stock-server",path = "/stock",
            fallback = StockFeignControllerDegrade.class)
    public interface StockFeignController {
          
          
    
        @RequestMapping("/addStock")
        void addStock();
    }
    

    El siguiente es el código para la clase de degradación. Es muy simple. Es imposible saber qué tipo de excepción causó la degradación del servicio.

    import lombok.extern.slf4j.Slf4j;
    import org.springframework.stereotype.Component;
    
    /**
     * @author pcc
     */
    @Slf4j
    @Component
    public class StockFeignControllerDegrade implements StockFeignController{
          
          
        @Override
        public void addStock() {
          
          
            log.info("addStock: 降级方法处理中。。。");
        }
    }
    

    Luego lo probamos y podemos encontrar que cuando ocurre la excepción del servidor, normalmente ingresa al método de degradación (el código del proveedor de servicios arroja una excepción).
    Insertar descripción de la imagen aquí

    1. Reducción del servicio fallbackFactory
      El uso de fallbackFactory debe seguir las siguientes reglas
    • 1 La clase de implementación debe ser administrada por Spring
    • 2 La clase de implementación necesita implementar la interfaz FallbackFactory y pasar el tipo genérico de interfaz Feign

    El siguiente es el código para la interfaz Feign.

    /**
     * @author pcc
     * url: 用于指定三方接口,通过url指定的接口不会从注册中心获取服务列表,而是直接通过接口名拼接地址
     * name:用以声明feign调用的服务,这个必须与注册中心服务名保持一致
     * path:控制器上的类路径,如果不写path在方法上写全路径也是一样的
     * configuration:配置类,可以配置一些公共的参数,只对当前类下的接口生效,属于局部配置
     * fallback : 声明降级类
     * fallbackFactory: 声明降级工厂类
     *
     */
    @FeignClient(name = "stock-server",path = "/stock",
            fallbackFactory = StockFeignCallBackFactory.class)
    public interface StockFeignController {
          
          
    
        @RequestMapping("/addStock")
        void addStock();
    }
    

    La siguiente es la clase de implementación de fábrica de degradación.

    import lombok.extern.slf4j.Slf4j;
    import org.springframework.cloud.openfeign.FallbackFactory;
    import org.springframework.stereotype.Component;
    
    /**
     * @author pcc
     */
    @Slf4j
    @Component
    public class StockFeignCallBackFactory implements FallbackFactory<StockFeignController> {
          
          
        @Override
        public StockFeignController create(final Throwable cause) {
          
          
            return new StockFeignController() {
          
          
                @Override
                public void addStock() {
          
          
                    log.info("addStock:fallbackFactroy降级中:{}",cause.getMessage());
                }
            };
        }
    }
    

    Para demostrar los detalles de la excepción, el código anterior cambia la causa Throwable a la causa Throwable final; de lo contrario, la clase interna no puede operar la causa variable (debe estar familiarizado con este problema al escribir lambdas con frecuencia). Después de la ejecución, puede ver en la figura siguiente que obtuvimos la información de excepción de la interfaz remota en el método de degradación.
    Insertar descripción de la imagen aquí
    Una cosa que es necesario agregar es la relación entre la degradación del servicio y el manejo unificado de excepciones:
    Las excepciones manejadas por las degradaciones del servicio, naturalmente, no pueden detectarse mediante el manejo de excepciones global. El manejo global de excepciones puede verse como un proceso de degradación encubierto.

4. Regla del disyuntor limitador de corriente: DegradeRule

Nota: El entorno de uso actual es SringCloud. Si el entorno es diferente, el uso del disyuntor será ligeramente diferente.
Antes de hablar del disyuntor, hablemos del procesamiento de degradación. Implementamos el procesamiento de degradación del servicio declarando el método de degradación. La sección anterior presentó dos métodos de procesamiento: usar @SentinelResource o @FeignClient. Todos pueden implementar métodos de degradación que se activan cuando ocurren excepciones en el servicio. Entonces, ¿cuál es la relación entre el disyuntor y la degradación del servicio? Necesitamos configurar algunas reglas para el disyuntor de servicio. Por ejemplo, si hay 10 solicitudes en 1 segundo y 5 de ellas son anormales, activaremos el disyuntor. El método de degradación se llama cuando se activa el disyuntor. ¿Quizás tengas preguntas aquí? Las excepciones ordinarias llaman al método de degradación, y los disyuntores también llaman al método de excepción. Entonces, ¿por qué necesito configurar los disyuntores? ¿No es suficiente usar el método de degradación de forma predeterminada? La respuesta es definitivamente no, de lo contrario, ¿por qué necesitaríamos disyuntores? Los disyuntores se usan más comúnmente en escenarios de alta concurrencia para evitar que los servicios ocupen demasiados recursos de solicitud en escenarios anormales o escenarios con recursos limitados (si la llamada es anormal, el La llamada seguirá siendo llamada) De hecho, es un desperdicio de recursos de subprocesos; si la respuesta es lenta y varios servicios todavía llaman a esta interfaz, también es un desperdicio de recursos. Por supuesto, si es un servicio central, debe discutirse por separado). Por lo tanto, el disyuntor proporciona un concepto de tiempo del disyuntor. Cuando se activa el disyuntor, se proporciona un tiempo del disyuntor. Durante el período del disyuntor, las solicitudes recibidas por la interfaz o recurso actual ingresarán directamente al método de degradación en lugar de ingresar al método. . Esto puede resolver muchos problemas, por ejemplo, si el servicio está en un estado anormal, no es necesario realizar una serie de procesos y ocupar recursos, solo es necesario realizar un proceso de degradación. Cuando el tiempo alcanza el límite del tiempo del disyuntor, la siguiente solicitud ingresará al método. Si el método actual activa la degradación una vez, el disyuntor será directamente el disyuntor en lugar de juzgar la regla del disyuntor. Si es normal, el disyuntor saldrá.
El disyuntor de Sentinel admite tres estrategias: índice de llamadas lentas, índice de excepción y número de excepciones. Las siguientes son las reglas del disyuntor para estos tres tipos. Las descripciones detalladas se proporcionan de dos formas: configuración de página y configuración de API.

1. Página de fusibles de índice de llamada lento

La proporción de llamadas lentas significa literalmente un disyuntor basado en la proporción de llamadas lentas con respecto al número total de solicitudes. Los siguientes son los puntos a tener en cuenta al utilizar la configuración de la página:

  • Al configurar las reglas del disyuntor en la página, no es necesario agregar la anotación @SentinelResource en el método. Si no la agrega, use el método de degradación predeterminado.
  • Las reglas de disyuntor configuradas en la página desaparecerán si se reinicia el panel o se reinicia el servicio de destino.

A continuación, para configurar las reglas de disyuntor para la tasa de llamadas lentas, primero debe ingresar a la página "Enlace de punto de clúster" (el enlace de punto de clúster es en realidad la interfaz donde generamos la solicitud, que es el recurso para Sentinel), como sigue:
Insertar descripción de la imagen aquí
Sí Como puede ver, lo anterior es una captura de pantalla sin agregar ninguna configuración. En este momento, podemos hacer clic en "Circuit Break" para agregar reglas de disyuntor.
Insertar descripción de la imagen aquí
La imagen de arriba es una página de configuración de la regla del disyuntor de índice de llamadas lentas. Puede ver un total de cinco parámetros comerciales (excepto el índice de llamadas lentas):

  • RT máximo: unidad ms, tiempo máximo de respuesta de la interfaz, exceder este tiempo se considera una llamada lenta.
  • Umbral de relación: número de solicitudes de llamadas lentas/número total de solicitudes, valor máximo permitido
  • Duración de la fusión: después de activar el fusible, el tiempo para que la interfaz o recurso entre en el estado de fusible
  • Número mínimo de solicitudes: el número de solicitudes simultáneas. Solo cuando el número de solicitudes simultáneas alcance este número se calculará la tasa de llamadas lentas y luego se activará el disyuntor cuando se alcance el umbral.
  • Duración de las estadísticas: el tiempo para contar el número de solicitudes simultáneas

Como se muestra arriba, podemos realizar la siguiente configuración, el significado de configuración es:
Cuente si el número de solicitudes simultáneas en 1 segundo llega a 3. Si es así, calcule la proporción de llamadas lentas entre estas solicitudes en función del RT máximo. Una vez calculada la proporción, compárela con el umbral de proporción. Si se alcanza el umbral , se activa el disyuntor. El tiempo del disyuntor es de 10 segundos. Dentro de 10 segundos, todas las solicitudes no ingresarán al método, sino que ingresarán directamente al método de degradación. Si no se declara ningún método de degradación aquí, ingresarán al método de degradación predeterminado. Cuando expire el tiempo del disyuntor, si la siguiente solicitud tiene éxito, el cálculo se reiniciará, si falla, ingresará directamente al disyuntor nuevamente.
Insertar descripción de la imagen aquí
Una vez completada la configuración anterior, puede ver la regla de disyuntor que acabamos de configurar en el menú "Reglas de disyuntor"
Insertar descripción de la imagen aquí
y luego probarla. Aquí necesitamos simular llamadas lentas. Podemos generar un número aleatorio dentro de 100 y luego dormir para Simular llamadas lentas.

    @RequestMapping("/addStock")
    public void addStock() throws Exception{
    
    
        log.info("add stock start: {}",name);

        // 随机休眠100ms以内的时间-用于测试: 熔断规则-慢调用
        String s = String.valueOf(Math.floor(Math.random() * 100));
        Thread.sleep(Integer.parseInt(s.split("\\.")[0]));

    }

Luego mire el resultado del activador:
Insertar descripción de la imagen aquí
este es el retorno del método de degradación predeterminado.
El ejemplo que se muestra arriba no utiliza @SentinelResource y no especifica un método de degradación. Hablemos sobre el uso de @SentinelResource y la especificación del método de degradación al mismo tiempo. El uso de @SentinelResource para especificar el método de degradación también se menciona en la sección anterior. Puede usar directamente fallback o fallback+fallbackClass para especificar el método de degradación. Aquí también necesita usar otro valor de atributo de @SentinelResource. La función de este atributo es registrar el método como un recurso en Sentinel. El código Java es el siguiente (Al usar @SentinelResource, debe especificar el método de degradación. Se debe usar esta anotación y el sistema no utilizará el método de degradación predeterminado.):

	// 使用注解,表明Sentinel资源,同时指明降级方法
    @SentinelResource(
            value = "addStock",
            fallback = "addStockFallback",
            fallbackClass = StockDefaultDegrade.class,
            exceptionsToIgnore = ArithmeticException.class)
    @RequestMapping("/addStock")
    public void addStock() throws Exception{
    
    
        log.info("add stock start: {}",name);

        // 随机休眠100ms以内的时间-用于测试: 熔断规则-慢调用
        String s = String.valueOf(Math.floor(Math.random() * 100));
        Thread.sleep(Integer.parseInt(s.split("\\.")[0]));
    }

Aquí está el código para el método de degradación:

@Slf4j
public class StockDefaultDegrade {
    
    

    /**
     * 这是fallback用的指定降级方法
     * @param throwable
     */
    public static void addStockFallback(Throwable throwable){
    
    
        log.info("触发addStockFallback的降级方法:" + throwable.getMessage() + " ");
    }
}

Las reglas de configuración de la página son las mismas que la última vez que se utilizó el método de degradación predeterminado, de la siguiente manera:
Insertar descripción de la imagen aquí
Cuando iniciemos el método de degradación nuevamente, no se eliminará la degradación predeterminada e ingresaremos nuestro propio método de degradación:
Insertar descripción de la imagen aquí

Nota especial: solo los marcados con un cuadro rojo aquí son los métodos de degradación que realmente se ejecutan cuando se inicia el disyuntor. Puede ver que las excepciones obtenidas aquí son todas nulas. ¿Por qué? Porque después del disyuntor, nuestra solicitud ingresará directamente al método de degradación. En este momento, el método no informa un error, por lo que habrá un valor nulo aquí. En este momento, si se lanza aleatoriamente una excepción dentro del método, puede haber debe ser un método de degradación que imprima la excepción, pero que no sea activado por el disyuntor. Ya sea que el método de degradación activado por el disyuntor sea la tasa de llamada lenta, el número de excepciones o la tasa de excepción, su información de excepción debe ser nula. Esto también se puede utilizar para distinguir si se trata de una degradación provocada por una excepción de método o por un disparador de disyuntor.

1. Disyuntor-API de relación de llamada lenta

Lo anterior presenta el uso del panel para configurar el disyuntor de la tasa de llamadas lentas, la degradación cuando no se utiliza la anotación SentinelResource y el disyuntor del método de degradación personalizado. A continuación se explica cómo usar API para configurar disyuntores. En la mayoría de los escenarios reales, la API todavía se usa para la configuración y luego se ajusta con el tablero en escenarios especiales. Preste atención a los siguientes problemas al utilizar la API:

  • El uso de API para configurar el disyuntor no requiere el uso del panel en absoluto. El propósito de usar el panel es ver los resultados de la configuración de la API con mayor claridad.
  • Se requieren tres pasos para configurar las reglas del disyuntor: establecer el nombre del recurso y la política del disyuntor, configurar los parámetros y enviar las reglas al administrador de reglas.
  • Utilice el disyuntor configurado por la API. Si utiliza el panel, podrá ver las reglas después de que se inicie el panel.
  • Usando el disyuntor configurado por la API, el tablero también se puede modificar. La modificación tendrá efecto, pero dejará de ser válida cuando se reinicie el servicio o el tablero.
  • Finalmente, no olvide entregar el objeto al contenedor Spring para su administración.

El código del método de degradación y el método de interfaz son los mismos que los anteriores, por lo que no los publicaré nuevamente aquí. Aquí está la configuración de la regla del disyuntor de relación de llamada lenta. Aquí hay tres formas de escribir para facilitar la comparación de las diferencias entre las tres formas de escribir, de hecho, todas requieren Tres pasos, excepto que el segundo paso de los dos últimos tiene solo cuatro parámetros y no hay diferencia en los demás.

/**
 * @author pcc
 * 三种熔断规则不可以同时设置到一个资源上,若是同时作用到一个资源上,最后加载的规则会覆盖之前的规则
 * 最终只有一个生效
 */
@Configuration
public class FuseConfig {
    
    

    // 熔断规则-慢调用比例
    @Bean
    public DegradeRule degradeRule(){
    
    
        DegradeRule degradeRule = new DegradeRule();
        // 资源名,资源名是唯一的
        degradeRule.setResource("addStock");
        // 熔断策略-0 慢调用比例 ,1 异常比例 ,2 异常数
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_RT);

        // 熔断时长,单位为 s
        degradeRule.setTimeWindow(10);
        // 触发熔断的最小请求数,需要配合下面的时间一起,默认5
        degradeRule.setMinRequestAmount(3);
        // 触发熔断的最小请求数的单位时间ms默认1000ms(这个时间内请求数达到最小请求,才会进行计算时间超过阈值的请求,然后计算比例,比例达到后才会进行熔断)
        degradeRule.setStatIntervalMs(1000);
        // 慢调用比例模式下为慢调用临界 RT,单位ms(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值
        degradeRule.setCount(40);
        // 慢调用比例阈值默认1.0,sentinel1.8.0加入,0.0-1.0 之间
        degradeRule.setSlowRatioThreshold(0.2);


        // 将熔断规则交给熔断规则管理器
        List<DegradeRule> rules = new ArrayList<DegradeRule>();
        rules.add(degradeRule);
        DegradeRuleManager.loadRules(rules);

        return degradeRule;
    }


    // 熔断规则-异常比例
    @Bean
    public DegradeRule exceptionRatioRule(){
    
    
        DegradeRule degradeRule = new DegradeRule();
        // 该熔断规则对应资源名
        degradeRule.setResource("addStock");
        // 熔断策略-异常比例
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);

        // 异常比例阈值20%
        degradeRule.setCount(0.2);
        // 熔断时间单位s
        degradeRule.setTimeWindow(10);
        //  触发熔断的最小请求数,需要配合下面的时间一起,默认5
        degradeRule.setMinRequestAmount(3);
        // 触发熔断的最小请求数的单位时间ms默认1000ms(这个时间内请求数达到最小请求,才会进行计算时间超过阈值的请求,然后计算比例,比例
        degradeRule.setStatIntervalMs(1000);


        // 将熔断规则交给熔断规则管理器-这里可以使用单例集合,因为无论在哪里声明的规则都是要交给管理器的
        // 即使在这里将别的规则也加载了也没问题,所以可以使用单例集合
        DegradeRuleManager.loadRules(Collections.singletonList(degradeRule));
        return degradeRule;
    }

    // 熔断规则-异常数
    @Bean
    public DegradeRule execptionCountRule(){
    
    
        DegradeRule degradeRule = new DegradeRule();
        // 熔断资源
        degradeRule.setResource("addStock");
        // 熔断策略-异常数
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);

        // 异常数的阈值
        degradeRule.setCount(2);
        // 熔断触发最小请求数
        degradeRule.setMinRequestAmount(3);
        // 熔断最小请求书的统计时长,默认1000ms
        degradeRule.setStatIntervalMs(1000);
        // 熔断时间
        degradeRule.setTimeWindow(10);


        // 将熔断规则交给熔断规则管理器-这里可以使用单例集合,因为无论在哪里声明的规则都是要交给管理器的
        DegradeRuleManager.loadRules(Collections.singletonList(degradeRule));
        return degradeRule;
    }
}

Si el resultado no es diferente al anterior, no lo publicaré nuevamente.

2. Proporción anormal de disyuntor - página

Excepto por la configuración ligeramente diferente de la página, todo lo demás es igual que la configuración de la página del índice de llamadas lentas.
Insertar descripción de la imagen aquí
La página también es fácil de entender. Sirve para configurar el umbral de la relación anormal. Cuando se alcanza el umbral, se activará el disyuntor y luego se ejecutarán todos los métodos de degradación. Para verificar aquí, simplemente ejecute la excepción directamente en función de la aleatoriedad. El siguiente es el código Java:

    /**
     * 这里同时使用了fallback 、defaultFallback
     * 当同时使用时,只有fallback生效
     *
     */
    @SentinelResource(
            value = "addStock",
            defaultFallback = "stockDefaultFallback",
            fallback = "addStockFallback",
            fallbackClass = StockDefaultDegrade.class,
            exceptionsToIgnore = ArithmeticException.class)
    @RequestMapping("/addStock")
    public void addStock() throws Exception{
    
    
        log.info("add stock start: {}",name);

        // 随机休眠100ms以内的时间-用于测试: 熔断规则-慢调用
        String s = String.valueOf(Math.floor(Math.random() * 100));
        Thread.sleep(Integer.parseInt(s.split("\\.")[0]));

        // 随机产生异常用于测试:熔断规则-异常比例/异常数
        if(Integer.parseInt(s.split("\\.")[0])>50){
    
    
            throw new RuntimeException("运行异常哈");
        }

    }

De esta manera, una cierta proporción de solicitudes arrojarán RuntimeException. El punto principal es que si la solicitud es lo suficientemente rápida, se activará el disyuntor. No hay diferencia después de la activación. Aquí solo se utiliza un método de degradación (el mismo recurso solo puede tener un método de degradación).

2. Proporción anormal de disyuntor-API

Lo que hay que mencionar aquí es el método setCount, no hay nada más que decir. Este método está disponible en las tres estrategias de disyuntores, pero su significado es diferente y requiere atención especial. En RT, la unidad que representa la duración de las llamadas lentas es ms. En proporción de excepción, representa la proporción de excepción sin unidad. El valor está entre 0.0-1.0. En número de excepción, representa el número de excepciones. No hay mucho que decir sobre los demás, así que aquí están todos los códigos para las tres API:

/**
 * @author pcc
 * 三种熔断规则不可以同时设置到一个资源上,若是同时作用到一个资源上,最后加载的规则会覆盖之前的规则
 * 最终只有一个生效
 */
@Configuration
public class FuseConfig {
    
    

    // 熔断规则-慢调用比例
    @Bean
    public DegradeRule degradeRule(){
    
    
        DegradeRule degradeRule = new DegradeRule();
        // 资源名,资源名是唯一的
        degradeRule.setResource("addStock");
        // 熔断策略-0 慢调用比例 ,1 异常比例 ,2 异常数
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_RT);

        // 熔断时长,单位为 s
        degradeRule.setTimeWindow(10);
        // 触发熔断的最小请求数,需要配合下面的时间一起,默认5
        degradeRule.setMinRequestAmount(3);
        // 触发熔断的最小请求数的单位时间ms默认1000ms(这个时间内请求数达到最小请求,才会进行计算时间超过阈值的请求,然后计算比例,比例达到后才会进行熔断)
        degradeRule.setStatIntervalMs(1000);
        // 慢调用比例模式下为慢调用临界 RT,单位ms(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值
        degradeRule.setCount(40);
        // 慢调用比例阈值默认1.0,sentinel1.8.0加入,0.0-1.0 之间
        degradeRule.setSlowRatioThreshold(0.2);


        // 将熔断规则交给熔断规则管理器
        List<DegradeRule> rules = new ArrayList<DegradeRule>();
        rules.add(degradeRule);
        DegradeRuleManager.loadRules(rules);

        return degradeRule;
    }


    // 熔断规则-异常比例
    @Bean
    public DegradeRule exceptionRatioRule(){
    
    
        DegradeRule degradeRule = new DegradeRule();
        // 该熔断规则对应资源名
        degradeRule.setResource("addStock");
        // 熔断策略-异常比例
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);

        // 异常比例阈值20%
        degradeRule.setCount(0.2);
        // 熔断时间单位s
        degradeRule.setTimeWindow(10);
        //  触发熔断的最小请求数,需要配合下面的时间一起,默认5
        degradeRule.setMinRequestAmount(3);
        // 触发熔断的最小请求数的单位时间ms默认1000ms(这个时间内请求数达到最小请求,才会进行计算时间超过阈值的请求,然后计算比例,比例
        degradeRule.setStatIntervalMs(1000);


        // 将熔断规则交给熔断规则管理器-这里可以使用单例集合,因为无论在哪里声明的规则都是要交给管理器的
        // 即使在这里将别的规则也加载了也没问题,所以可以使用单例集合
        DegradeRuleManager.loadRules(Collections.singletonList(degradeRule));
        return degradeRule;
    }

    // 熔断规则-异常数
    @Bean
    public DegradeRule execptionCountRule(){
    
    
        DegradeRule degradeRule = new DegradeRule();
        // 熔断资源
        degradeRule.setResource("addStock");
        // 熔断策略-异常数
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);

        // 异常数的阈值
        degradeRule.setCount(2);
        // 熔断触发最小请求数
        degradeRule.setMinRequestAmount(3);
        // 熔断最小请求书的统计时长,默认1000ms
        degradeRule.setStatIntervalMs(1000);
        // 熔断时间
        degradeRule.setTimeWindow(10);


        // 将熔断规则交给熔断规则管理器-这里可以使用单例集合,因为无论在哪里声明的规则都是要交给管理器的
        DegradeRuleManager.loadRules(Collections.singletonList(degradeRule));
        return degradeRule;
    }
}

3. Disyuntor de número de excepción: página y API

No hay mucha diferencia aquí, y la cantidad de cambios es muy pequeña en comparación con lo anterior. No vale la pena hablar de ello por separado. Solo mírenlo juntos. El siguiente es el contenido de la página de configuración: Puede verlo en comparación
Insertar descripción de la imagen aquí
con la proporción anormal, solo se ha cambiado la proporción anormal. Se ha convertido en una anomalía, incluso en la forma en que está escrita la API. El umbral de proporción en la proporción anormal y el número de excepciones en el número anormal están representados por recuento. Por lo tanto, la diferencia en API es una diferencia en la estrategia del disyuntor, que no se mostrará repetidamente aquí.

4. Añade otros puntos clave

4.1 Después de agregar la anotación @SentinelResource, la degradación predeterminada no tendrá efecto.

En realidad, este problema se ha explicado anteriormente. De hecho, cuando no utilizamos la anotación @SentinelResource, una vez que se activa el disyuntor, se utilizará el método de degradación predeterminado. Sin embargo, una vez que agregamos esta anotación, debemos declarar el método de degradación. de lo contrario, informará 500 en lugar de utilizar el método de degradación predeterminado del sistema. Por supuesto, en escenarios reales, nadie utilizará un disyuntor en lugar de degradarlo, solo debe prestar atención a esto al verificar el funcionamiento.

4.2 Procesamiento de degradación unificado

El método de degradación predeterminado mencionado anteriormente es en realidad el manejo de excepciones unificado proporcionado por Sentinel (algo similar al controlador de excepciones global). Esto también se puede cambiar y podemos usar este manejo de excepciones unificado para especificar información de devolución o devolver una página. O se puede redirigir a un sitio web específico o a un recurso estático. Este es el método de manejo de degradación unificado predeterminado:
Insertar descripción de la imagen aquí

Entonces, si implementamos este manejo unificado de excepciones nosotros mismos, ¿cómo deberíamos hacerlo? De hecho, solo necesitamos consultar su método de escritura de la siguiente manera:

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author pcc
 */
@Component
public class GlobalDegradeConfig implements BlockExceptionHandler {
    
    

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, BlockException e) throws Exception {
    
    
        response.setStatus(429);
        response.setHeader("Content-Type", "application/json");
        response.setCharacterEncoding("UTF-8");
        response.getWriter().write("{\"code\":429,\"msg\":\"请求过于频繁,请稍后再试\"}");
        response.getWriter().flush();
    }
}

La verificación también es muy simple. Solo necesitamos eliminar la anotación @SentinelResource en la interfaz y luego reconfigurar las reglas del disyuntor en la página. En este momento, podemos probarlo. El resultado es como se muestra en la figura:
Insertar descripción de la imagen aquí

Sin embargo, existe un problema con el uso de este procesamiento de degradación unificado, es decir, si no hay un método de degradación cuando ocurre una excepción, se enviará directamente al usuario, porque este método unificado solo es aplicable a escenarios de degradación provocados por disyuntores. . Por lo tanto, todavía no se recomienda utilizar este procesamiento de degradación de disyuntor unificado, sino que utilice @SentinelResource para especificar el método de degradación. De esta manera, no habrá escenarios en los que no se puedan manejar excepciones ordinarias.

4.3 Lanzar BLockException no activará la regla del disyuntor

Este escenario rara vez se encuentra en escenarios comerciales reales, pero se puede encontrar cuando lo prueba usted mismo. Si usamos la estrategia de disyuntor de relación de excepción y número de excepciones, lo que se arroja en el código es el hijo de la clase BlockException. las excepciones (excepciones correspondientes a las cinco reglas) no pueden activar las reglas del disyuntor normalmente. Si estás interesado, puedes verificarlo.

4.4 Implementar spring.cloud.sentinel.eager:true

Active el modo de inactividad del servicio de carga de Sentinel. De forma predeterminada, Sentinel cargará el servicio de destino solo después de que se llame a la interfaz del servicio. Después de activar la carga de inanición, el servicio se cargará directamente cuando se inicie. Sin embargo, si no llega ninguna solicitud , lo cargaremos en "monitoreo en tiempo real" y los datos aún no son visibles en el "enlace del punto de clúster".

5. Reglas actuales de control de flujo limitante: FlowRule

La limitación de corriente y la interrupción del circuito son las dos reglas más importantes de Sentinel. La interrupción del circuito garantiza el retorno correcto del servicio en escenarios anormales, mientras que el control de flujo garantiza la estabilidad del servicio en condiciones de alta concurrencia. Establecemos estrategias de control de flujo adecuadas para garantizar que los servicios no se verá abrumado en escenarios de alta concurrencia.
Es concebible que ninguna empresa pueda expandir el servidor sin restricciones, por lo que dentro de los recursos limitados del servidor, debemos considerar cómo garantizar que se procesen las solicitudes que excedan la concurrencia permitida por el clúster de servidores. En este momento, debemos utilizar el control de flujo. reglas. . Las reglas de control de flujo de Sentinel admiten dos categorías principales según el tipo: QPS (consultas por segundo) y el número de subprocesos simultáneos (el número de subprocesos simultáneos puede considerarse como TPS). Estas son también dos de las soluciones más populares en la actualidad. Si hay diferencias, las detallaremos a continuación.
1.
Esta es la página para la configuración de reglas de control de flujo del panel Sentinel. Contiene el siguiente contenido. A primera vista, sentirá que hay muchos escenarios de combinación para cada parámetro. De hecho, generalmente puede centrarse en los tipos de umbral y los grupos. Si hay escenarios de necesidades especiales, puede considerar la configuración del modo de control de flujo y los efectos.

  • Nombre del recurso: el recurso registrado en Sentinel debe declararse mediante @SentinelResource
  • Para fuentes: Sentinel admite el control de flujo para diferentes fuentes. Por ejemplo, soy un proveedor de servicios y Baidu, Alibaba y Tencent usan mis servicios. Solo establezco reglas de control de flujo para Tencent. Puede usar este atributo en este momento. Sin embargo, esto requiere algunos cambios en el código, que se analizarán por separado, porque tanto QPS como el número de subprocesos concurrentes admiten fuentes específicas, que se analizarán por separado.
  • Tipo de umbral y umbral de una sola máquina: estas son las dos reglas admitidas por Sentinel
  • Ya sea para agrupar: los servicios están básicamente agrupados, por lo que esto es básicamente una selección obligatoria. Sin embargo, debemos establecer si es una sola máquina o un umbral general en el modo de clúster. Esto también se discutirá por separado, porque QPS y el número de subprocesos simultáneos son compatibles.
  • Modo de control de flujo: no se admite en el modo de clúster. Aquí se admiten configuraciones directas, asociadas y de enlace. Se admiten tanto QPS como el número de subprocesos simultáneos. Se presentarán en detalle por separado.
  • Efecto de control de flujo: no es compatible con el modo de clúster, solo QPS lo admite. Puede elegir falla rápida, calentamiento o espera en cola. Esto también se presentará por separado.

Como se mencionó anteriormente, algunas configuraciones admiten QPS y se puede establecer la cantidad de subprocesos simultáneos. Este parámetro solo se demostrará usando uno de los escenarios, como: fuente, clúster, modo de control de flujo, etc.

1.Página de control de flujo QPS

Cabe señalar que después de declarar las reglas de control de flujo, si usamos el método de degradación declarado por respaldo, ya sea un disyuntor o control de flujo, se llamará al método de degradación en respaldo. Si se usa un controlador de bloques, ya sea Si es un disyuntor o control de flujo, se llamará al método de degradación en respaldo. El método blockhandler aún se llamará para control de flujo. Por supuesto, se declara que la degradación ordinaria del controlador de bloques seguirá usando respaldo. Otro punto a tener en cuenta es que si declara fusibles y limitación de corriente al mismo tiempo, primero debe determinar si el fusible está fusionando. Si ya lo está, no se aplicará la limitación de corriente.

  • 1. Utilice el respaldo para declarar el método de degradación para manejar la degradación, el disyuntor, el control de flujo, etc.
    Si desea configurar reglas de control de flujo en la página, primero debe entregar el método a Sentinel para su administración, y luego debe para declarar el método de degradación, ya sea degradación, disyuntor o control de flujo. El control de flujo normalmente puede ingresar al método de reserva.
    Este es el código de recurso administrado por Sentinel:
package com.cheng.stockserver.flowrule.controller;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.cheng.stockserver.flowrule.degradeclass.BlockMethod;
import com.cheng.stockserver.flowrule.degradeclass.DegradeMethod;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author pcc
 * 正常情况下sentinel应该使用在customer端,而不是server端,这里只是测试一下就无所谓了
 */
@Slf4j
@RestController
@RequestMapping("/flow")
public class controller {
    
    

    @Value("${name}")
    String name;

    @RequestMapping("/testFlowRule")
    @SentinelResource(
            value = "testFlowRule",
            fallback = "testFlowRule", // 降级配置
            fallbackClass = DegradeMethod.class
    )
    public String testFlowRule(){
    
    

        log.info("testFlowRule start, name : {}",name);

        // 产生一个100以内的随机数
        int i = Integer.parseInt(String.valueOf(Math.random() * 100).split("\\.")[0]);

        // 当随机数大于60时,抛出异常(值越大抛出异常概率越小) 方便验证降级、熔断
        if(i>60){
    
    
            throw new RuntimeException("testFlowRule error");
        }

        return "success";
    }

}

Este es el método alternativo declarado. Imprima aquí el tipo real de Throwable para saber qué escenario activó el método: puede ser una degradación, un disyuntor o un control de flujo, que se pueden distinguir por la clase de excepción.

import lombok.extern.slf4j.Slf4j;

/**
 * @author pcc
 */
@Slf4j
public class DegradeMethod {
    
    

    public static String testFlowRule(Throwable th){
    
    
        log.info("触发降级方法: {},异常:{}",th.getMessage(),th.getClass().getName());
        return "降级方法返回:success";
    }
}

No hay diferencia entre la configuración de la regla del disyuntor y lo anterior. Aquí usamos la relación anormal para configurar la regla del disyuntor:

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;

/**
 * @author pcc
 */
@Configuration
public class DegradeConfig {
    
    

    /**
     * 如果有多个熔断规则应该这么写
     * 或者是使用一个单例list,把所有的熔断规则都放进去,最后一次交给
     * 熔断规则管理器
     * @return
     */
    @Bean
    public DegradeRule getDegradeRule() {
    
    

        List<DegradeRule> lists = new ArrayList<DegradeRule>();

        /**
         * 这是第一个熔断规则,支持多个规则的配置
         */
        // 这里使用熔断规则的异常比例规则来处理降级
        // 使用异常比例更容易看到是普通降级还是熔断导致的降级(看异常信息有没有值就知道了)
        DegradeRule degradeRule = new DegradeRule();
        // 声明熔断对应的资源、sentinelresource中value声明
        degradeRule.setResource("testFlowRule");
        // 降级策略使用异常比例
        degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);

        // 设置降级规则
        degradeRule.setCount(0.5); // 20%的异常会熔断
        degradeRule.setTimeWindow(10); // 熔断10s
        degradeRule.setMinRequestAmount(2);// 最小请求数
        degradeRule.setStatIntervalMs(1000);// 最小请求数的统计时间1s

        // 将降级规则交由熔断管理器
        // 以上配置,1s内有两次请求,其中只要有一个异常就会熔断10s
        lists.add(degradeRule);

        DegradeRuleManager.loadRules(lists);

        return degradeRule;
    }
}

Solo estos son necesarios para la fusión, que en realidad son cosas que se han introducido antes. El objetivo principal aquí es demostrar el efecto de configurar la fusión y el control de flujo al mismo tiempo, por lo que es necesario configurar la fusión nuevamente. El control de flujo se configura aquí usando la página. Configuramos el recurso testFlowRule para la regla del disyuntor que acaba de configurar y luego configuramos la regla de control de flujo de la siguiente manera: Después de configurar
Insertar descripción de la imagen aquí
esta regla, las solicitudes con un QPS mayor que 3 ingresarán directamente al respaldo. Método, siempre que el QPS no sea mayor que 3 solicitudes pueden ingresar al recurso normalmente. La siguiente es una captura de pantalla en ejecución:
Insertar descripción de la imagen aquí
puede ver que el método de degradación tiene tres salidas: salida de degradación, salida de control de flujo y salida de fusible. Aquí puede ver el efecto cuando se aplican el disyuntor y la degradación a un recurso al mismo tiempo.
En resumen, es necesario tener en cuenta los siguientes puntos:
①. Fallback puede manejar escenarios como degradación, disyuntor y control de flujo al mismo tiempo. Internamente, se puede usar instancia de para determinar la clase de excepción para implementar diferentes procesamientos para diferentes escenarios. ②.
Cuando el disyuntor y el control de flujo se configuran para un recurso al mismo tiempo. , la activación de las reglas de control de flujo requiere una premisa de que el recurso no puede ser un disyuntor y el control de flujo no se puede activar normalmente durante el disyuntor. período Esto también es razonable, porque no hay necesidad de acceder a los recursos si son anormales, y no hay necesidad de control de flujo si no hay acceso. Una solicitud normal debería ser la siguiente:
Insertar descripción de la imagen aquí

Cuando llega una solicitud, primero verificará si el recurso es un disyuntor. Si es un disyuntor, se ejecutará el método del disyuntor. Aquí está el método especificado por respaldo. Solo si no hay un disyuntor se juzgará si se debe realizar control de flujo. Si no hay control de flujo, se puede ingresar el recurso.

  • 2. Use blockhandler para declarar el método de degradación.
    El respaldo se usa anteriormente para demostrar el disyuntor y el control de flujo. SentinelResource también proporciona un controlador de bloque para manejar específicamente cinco escenarios de reglas, como el disyuntor y el control de flujo. Por lo tanto, nuestra mejor manera es no usar el respaldo para manejar el control de flujo. En lugar de usar un disyuntor, se usa blockhandler, mientras que el respaldo se usa específicamente para manejar degradaciones. No hay diferencia entre el uso de blockhandler y respaldo. La diferencia con el código general que usa el respaldo anterior es que solo necesitamos agregar la configuración de blockhandler y el resto será completamente consistente con lo anterior. El siguiente es el código para la nueva configuración en el recurso, que muestra solo los cambios:
    @RequestMapping("/testFlowRule")
    @SentinelResource(
            value = "testFlowRule",
            fallback = "testFlowRule", // 降级配置
            fallbackClass = DegradeMethod.class,
            blockHandler = "testFlowRule", // 流控配置:配置熔断规则时若是增加了blockhandler,则熔断时进入的是该方法而不是fallback
            blockHandlerClass = BlockMethod.class
    )

La siguiente es la implementación del método de control de flujo,Tenga en cuenta que este método debe pasar BlockException; de lo contrario, no tendrá efecto. Este es un requisito obligatorio., dentro del método podemos juzgar qué escenario activó el método según el tipo de excepción real.

import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import lombok.extern.slf4j.Slf4j;

/**
 * @author pcc
 */
@Slf4j
public class BlockMethod {
    
    

    /**
     * 流控方法这里必须声明BlockException的,不然是无法进入流控方法的
     * 流控也不会生效
     * @param blockException 流控异常
     * @return
     */
    public static String testFlowRule(BlockException blockException){
    
    

        /**
         * 这里异常时没有异常信息的,只能通过异常的类型来判定是熔断还是流控等
         */
        if(blockException instanceof DegradeException){
    
    
            // 处理熔断
            log.info("block-熔断-方法: {}","DegradeException");
            return "block-熔断-方法返回:success";
        }
        if(blockException instanceof FlowException){
    
    
            // 处理流控
            log.info("block-流控-方法: {}","FlowException");
            return "block-流控-方法返回:success";
        }

        return "block方法返回:success";
    }
}

Los otros códigos son exactamente los mismos que el ejemplo anterior de uso de respaldo, por lo que no se mostrarán nuevamente aquí. Luego observe el resultado de activar la interfaz en este momento: En la figura anterior, podemos ver que la degradación del servicio
Insertar descripción de la imagen aquí
aún usa respaldo, y el disyuntor y el control de flujo han agregado un controlador de bloque. En el futuro, no se usará el respaldo, pero se usará el método especificado por el controlador de bloque.

1.API de control de flujo QPS

El código y los cambios aquí se basan en el uso de blockhandler en el escenario anterior y se agrega la siguiente configuración. De hecho, las reglas de configuración en la página se colocan en el código, nada más, nada más permanece sin cambios.

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Collections;

/**
 * @author pcc
 */
@Configuration
public class FlowConfig {
    
    

    @Bean
    public FlowRule getFlowRule() {
    
    
        FlowRule flowRule = new FlowRule();
        // 声明流控的资源
        flowRule.setResource("testFlowRule");
        // 声明使用的流控规则:0 并发线程数,1 QPS
        flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);

        // 流控规则设置-QPS阈值2
        flowRule.setCount(2);
        // 来源没有默认值,必须手动设定,default表示对所有来源生效
        flowRule.setLimitApp("default");


        // 将流控规则交给流控管理器
        FlowRuleManager.loadRules(Collections.singletonList(flowRule));
        return flowRule;
    }
}

Después de agregar la configuración anterior, es posible que no pueda ver las reglas de control de flujo configuradas o incluso las reglas de disyuntor anteriores en la página de inicio de sesión. Sin embargo, estas reglas tendrán efecto normalmente en el cliente. Si las ve, deberían ser se muestra de la siguiente manera:
Insertar descripción de la imagen aquí
El error del tablero anterior no afecta la efectividad de las reglas de disyuntores y las reglas de control de flujo, pero ocasionalmente hará que nuestras reglas no se puedan ver en el tablero (no es de extrañar que tenga que recomendar el tablero para uso directo en producción, hay muchos). errores). Resolver este problema es realmente simple. Primero comente la FlowRule que configuramos y reinicie, luego descomente y reinicie para omitirla. No sé el motivo específico.
La verificación no es diferente de la anterior, por lo que no la repetiré aquí.

2. Número de subprocesos simultáneos-página/API

El control de flujo basado en QPS debería ser fácil de entender, simplemente cuente la cantidad de solicitudes por unidad de tiempo. Además, Sentinel también admite la cantidad de subprocesos simultáneos para el control de flujo. Hystrix proporcionó por primera vez el número de subprocesos concurrentes, Hystrix proporciona dos métodos de implementación para el número de subprocesos concurrentes, uno es el aislamiento del grupo de subprocesos y el otro es el aislamiento del semáforo. El aislamiento del grupo de subprocesos consiste en preasignar un grupo de subprocesos para los recursos. El recurso especificado solo puede usar subprocesos del grupo de subprocesos especificado y el control de flujo está agotado. El aislamiento del semáforo solo cuenta el número total de subprocesos entrantes. Cuando se alcance el número total, controlaré el flujo. La solución de subprocesos concurrentes de Sentinel es equivalente a una integración de los dos (aislamiento del grupo de subprocesos, aislamiento de semáforos). Sentinel es similar al aislamiento del grupo de subprocesos en que separa los subprocesos de solicitud de los subprocesos de ejecución. Al igual que los semáforos, Sentinel contará el número total de subprocesos (esta cantidad debe ser la cantidad de subprocesos de ejecución). Cuando el número de subprocesos alcance el control de flujo.

Luego, echemos un vistazo a la configuración de la página de datos de subprocesos concurrentes:
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí
el código de recurso aquí debe ajustarse ligeramente para activar el control de flujo del número de subprocesos concurrentes. Debe dejar que el programa duerma manualmente por un tiempo para aumente el número de subprocesos simultáneos; de lo contrario, la solicitud se bloqueará cuando llegue. Después del procesamiento, es difícil activarlo (tenga en cuenta que si el tiempo de inactividad excede el tiempo estadístico del fusible, el fusible no se activará).

Lo anterior es la configuración de la página. La API también es muy simple. Solo necesita cambiar la calificación. Las otras configuraciones en realidad no son diferentes de QPS. El otro código no es diferente del anterior, este es para migrar la configuración de la página a la API, de la siguiente manera:

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Collections;

/**
 * @author pcc
 */
@Configuration
public class FlowConfig {
    
    

    @Bean
    public FlowRule getFlowRule() {
    
    
        FlowRule flowRule = new FlowRule();
        // 声明流控的资源
        flowRule.setResource("testFlowRule");
        // 声明使用的流控规则:0 并发线程数,1 QPS
        flowRule.setGrade(RuleConstant.FLOW_GRADE_THREAD);

        // 流控规则设置-线程并发阈值2
        flowRule.setCount(2);
        // 来源没有默认值,必须手动设定,default表示对所有来源生效
        flowRule.setLimitApp("default");


        // 将流控规则交给流控管理器
        FlowRuleManager.loadRules(Collections.singletonList(flowRule));
        return flowRule;
    }
}

Nota:
QPS y la cantidad de subprocesos simultáneos tienen efectos similares en algunos escenarios, pero la mayoría de los escenarios son diferentes. ¿cómo decir?
QPS se refiere a las solicitudes que llegan por unidad de tiempo. Siempre que la solicitud reciba el número umbral máximo de solicitudes por unidad de tiempo, no pueden ingresar otras solicitudes.
El número de subprocesos concurrentes enfatiza el número de subprocesos ocupados por la solicitud actual. Habrá un escenario en el que llegarán 3 solicitudes en 1 segundo. Suponiendo que 3 solicitudes es el umbral de QPS, se activará el control de flujo de QPS. 3 Llegan solicitudes pero habrá 3 hilos para realizar estas tres tareas, pero hay dos posibilidades. ① El procesamiento del lado del servidor de estas tres solicitudes toma 10 segundos, por lo que dentro de estos 10 segundos, si llega otra solicitud, se controlará el flujo, pero QPS no. Solo depende de si se recibe la solicitud, no cuánto tiempo lleva procesar. ② El servidor solo tardó 0,5 s en procesar estas tres solicitudes, por lo que pueden llegar hasta 6 solicitudes en este 1 s. Ésta es la diferencia entre QPS y la cantidad de subprocesos simultáneos. En resumen, QPS se centra en el tráfico de entrada y la cantidad de subprocesos concurrentes se centra en la concurrencia dentro del recurso.

3. Modo de control de flujo-asociación (usando QPS)-página/API

Debe existir un escenario de este tipo en escenarios de la vida real: algunas interfaces principales no deben desactivarse, mientras que otras interfaces se pueden desactivar durante un corto período de tiempo sin ningún problema.
Para este escenario, podemos usar el modo de control de flujo asociado. El llamado modo de control de flujo asociado es como se muestra a continuación. Necesitamos seleccionar asociación en el modo de control de flujo e ingresar el recurso asociado, de modo que cuando accedamos al recurso addStock y alcanza el umbral QPS de 2, testFlowRule tendrá control de flujo.
Nota: No lo hagas al revés. El recurso declarado en la primera línea tiene control de flujo cuando el acceso al recurso asociado alcanza el umbral QPS.
Insertar descripción de la imagen aquí
Para verificar aquí, podemos usar Jemter (también se pueden usar otras herramientas de cliente http) para configurar un grupo de subprocesos y luego la cantidad de accesos por segundo debe llegar a más de 2. Realice la siguiente configuración:
Insertar descripción de la imagen aquí

Luego, durante el acceso a addStock, nuestro acceso a testFlowRule debe controlarse por flujo, como se muestra a continuación:

(La interfaz addStock aquí no es diferente de la interfaz normal, por lo que el código no se publicará. Cabe señalar que debe registrarse como un recurso Sentinel y declarar que el nombre del recurso es addStock).
Insertar descripción de la imagen aquí
La solicitud de acceso de testFlowRule está completamente controlada por flujo, porque en este momento el QPS de addStock es 10, que excede el 2 que configuramos, por lo que todo el acceso a testFlowRule está controlado por flujo.

Pensamiento: si addStock activa un disyuntor, ¿testFlowRule controlará el flujo normalmente?

No debe controlarse el flujo, porque los recursos del sistema no se consumirán durante la interrupción del circuito de addStock. En este momento, el control de flujo no tiene sentido, por lo que no debe controlarse el flujo, y en realidad existe un proceso mencionado anteriormente para determinar si debe controlarse el flujo. Control de flujo: primero determine si el circuito es un disyuntor. El fusible, naturalmente, no controlará el flujo. ![Inserte descripción de imagen aquí](https://img-blog.csdnimg.cn/0b42ce80d90a457ab8494c08684294ff.png) Del método de salida anterior, podemos ver que testFlowRule son datos normales y no han sido controlados por flujo, lo que también está en línea con expectativas.

-------------------------------------------------- ---------------Configuración API--------------------------------- ------------------------------------------------
Lo anterior ha introducido cómo usar la página. Todas las operaciones, cómo configurar el control de flujo asociado usando API, se pueden modificar de la siguiente manera. Si no hay diferencia en otros códigos, no los publicaré:

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Collections;

/**
 * @author pcc
 */
@Configuration
public class FlowConfig {
    
    

    @Bean
    public FlowRule getFlowRule() {
    
    
        FlowRule flowRule = new FlowRule();
        // 声明流控的资源
        flowRule.setResource("testFlowRule");
        // 声明使用的流控规则:0 并发线程数,1 QPS
        flowRule.setGrade(RuleConstant.FLOW_GRADE_THREAD);

        // 流控规则设置-线程并发阈值2
        flowRule.setCount(2);
        // 来源没有默认值,必须手动设定,default表示对所有来源生效
        flowRule.setLimitApp("default");
        // 流控模式-关联
        flowRule.setStrategy(RuleConstant.STRATEGY_RELATE);
        // 流控模式-关联-资源
        flowRule.setRefResource("addStock");


        // 将流控规则交给流控管理器
        FlowRuleManager.loadRules(Collections.singletonList(flowRule));
        return flowRule;
    }
}

No hay diferencia en las pruebas ni en nada más, así que no lo repetiré aquí.

4. Modo de control de flujo - enlace (número de subprocesos simultáneos utilizados) - página/API

Los recursos de control de flujo generalmente se agregan a las interfaces, pero también podemos agregarlos a los métodos ordinarios. Si existe tal escenario, ambas interfaces A y B llaman al mismo recurso al mismo tiempo. Si el negocio A es más importante y el negocio B no es tan importante, podemos inclinar los recursos hacia A y controlar el flujo de B cuando los recursos son limitados.
Mirándolo de esta manera, ¿el control de flujo de enlace es similar al control de flujo de asociación? Lo que puede hacer con el control de flujo de enlace también es posible con el control de flujo asociado, pero el control de flujo asociado apunta a recursos en diferentes escenarios, mientras que el control de flujo de enlace tiene más que ver con restringir diferentes entradas al mismo recurso. Otra diferencia entre el control de flujo de asociación y el control de flujo de enlace es que el recurso B de control de flujo de asociación alcanza el umbral, mientras que el control de flujo A, mientras que el control de flujo de enlace es una de las fuentes de control de flujo B cuando el recurso B alcanza el umbral.
El uso del control de flujo de enlaces requiere que agreguemos una configuración en application.yml: spring.cloud.sentinel.web-context-unify=false, de la siguiente manera:

spring:
  application:
    # 阿里系的组件好像都会使用这个作为默认名称:nacos、sentinel
    name: stock-server # nacos配置中心和注册中心默认都是用这个作为默认名称
  cloud:
    sentinel:
      transport:
        port: 8719 # dashboard控制面版与sentinel通信的本地端口
        dashboard: 127.0.0.1:8088   # sentinel控制面板地址
      eager: true # 是否饥饿加载,默认为false,开启后启动项目就会初始化,而不是在第一次调用,dashboard也可以直接就可以看到服务,不用等待接口调用后才可以看到
      web-context-unify: false # 默认true,收敛资源访问的所有入口,若是想要使用链路流控,必须关闭
      

Existe el siguiente método testChain, al que hacen referencia las interfaces /testFlowRule1 y /testFlowRule2 al mismo tiempo. Configuramos el control de flujo para /testFlowRule1 cuando testChainQPS o subprocesos concurrentes alcanzan el umbral. El código es el siguiente:

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.cheng.stockserver.flowrule.degradeclass.BlockMethod;
import lombok.extern.slf4j.Slf4j;

/**
 * @author pcc
 */
@Slf4j
@org.springframework.stereotype.Service
public class serviceImpl implements ChainService {
    
    


    @Override
    @SentinelResource(
            value = "testChain",
            blockHandler ="testChainFlow",
            blockHandlerClass = BlockMethod.class
    )
    public void testChain() {
    
    
        log.info("testChain start");
        // 使用并发线程数模拟流控-加大方法响应时间,提高线程并发数
        try {
    
    
            Thread.sleep(1000);
        } catch (InterruptedException e) {
    
    
            throw new RuntimeException(e);
        }

    }
}

Además, cabe señalar que el método de control de flujo debe utilizar métodos estáticos, el valor de retorno debe ser coherente y se debe declarar BlockException, todas estas son regulaciones que se deben seguir al utilizar blockhandler. El siguiente es el método de control de flujo:

    /**
     * 链路流控使用的流控方法
     */
    public static void testChainFlow(BlockException blockException) {
    
    

        if(blockException instanceof DegradeException){
    
    
            // 处理熔断
            log.info("链路流控-熔断-方法: {}","DegradeException");

        }
        if(blockException instanceof FlowException){
    
    
            // 处理流控
            log.info("链路流控-流控-方法: {}","FlowException");
        }

    }

Agregue configuración a la página:
Insertar descripción de la imagen aquí
La siguiente es una captura de pantalla de prueba. Puede ver que solo la llamada testChain realizada por la interfaz testFlowRule1 tendrá control de flujo, mientras que la llamada testFlowRule2 no tendrá control de flujo.
Insertar descripción de la imagen aquí
************************************************** * ********** La siguiente es una introducción a APIj********************************* **** *************************
Usar la API es equivalente a usar la página, el único cambio es configurar las reglas usando código. Todo Lo demás es lo mismo. Estos son los únicos cambios: No hay diferencia entre mostrar código y verificación. Los atributos y modos de asociación operados cuando se usa la API son los mismos. Solo necesitamos cambiar los valores de los atributos, de la siguiente manera:

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Collections;

/**
 * @author pcc
 */
@Configuration
public class FlowConfig {
    
    

    @Bean
    public FlowRule getFlowRule() {
    
    
        FlowRule flowRule = new FlowRule();
        // 声明流控的资源
        flowRule.setResource("testChain");
        // 声明使用的流控规则:0 并发线程数,1 QPS
        flowRule.setGrade(RuleConstant.FLOW_GRADE_THREAD);

        // 流控规则设置-线程并发阈值2
        flowRule.setCount(3);
        // 来源没有默认值,必须手动设定,default表示对所有来源生效
        flowRule.setLimitApp("default");
        // 流控模式-链路
        flowRule.setStrategy(RuleConstant.STRATEGY_CHAIN);
        // 流控模式-链路-路径
        flowRule.setRefResource("/flow/testFlowRule1");



        // 将流控规则交给流控管理器
        FlowRuleManager.loadRules(Collections.singletonList(flowRule));
        return flowRule;
    }
}

5. Efecto de control de flujo-precalentamiento-página/API

El efecto de control de flujo por defecto es una falla rápida (solo QPS admite el efecto de control de flujo). Una falla rápida llamará al método de manejo de bloques que especificamos. De hecho, cuando el QPS aumenta instantáneamente, el servidor puede causar que el servicio se abrume directamente, incluso si Se permiten 100.000 concurrencias durante la prueba de estrés, pero en los negocios reales, si el QPS cae de un nivel muy bajo a 10 W, el servicio también puede verse abrumado. En este momento, podemos considerar utilizar el efecto de control de flujo del precalentamiento. El control de flujo de precalentamiento aumentará lentamente el QPS durante el tiempo de precalentamiento, dándole tiempo al sistema para reaccionar, asegurando así que el sistema no se verá abrumado por el pico instantáneo.
Si existe tal escenario: QPS es 10 en circunstancias normales, y de repente QPS llega a 1000, usamos el modo de precalentamiento y el tiempo de precalentamiento es 10 s, entonces Sentinel aumentará lentamente nuestro valor de QPS de control de flujo en 10 s. En un segundo, solo puede recibir 100 QPS y los demás fallarán. En el segundo segundo, recibirá 200 QPS y los demás también fallarán. En el décimo segundo, puede manejar 1000 QPS. En este momento, el calentamiento es terminado.
Hay una pequeña desventaja del modo de precalentamiento: el umbral de QPS durante el período de precalentamiento no es en realidad el valor máximo que establecemos, sino que aumenta gradualmente hasta el valor máximo que establecemos con el tiempo. La configuración de la página es la siguiente:
Insertar descripción de la imagen aquí

Para las pruebas, debe usar Jemeter aquí, porque los humanos no pueden alcanzar 100 QPS y debe usar herramientas. Como se muestra en la imagen de arriba, realizamos un control de flujo de precalentamiento en testChain. El efecto esperado: al principio, se solicitará que algunas solicitudes sean controladas por flujo. Después de 10 segundos, todas las solicitudes no estarán controladas por flujo (jemeter establece la concurrencia en 100): No hay una captura de pantalla real aquí
Insertar descripción de la imagen aquí
. El efecto es en realidad muy cercano a lo que esperábamos, excepto que el tiempo de precalentamiento de Sentinel es de 10 segundos. Su umbral de QPS aumenta en 10 segundos, lo cual no es lineal. Es posible que no tarde 10 segundos en completarse. el precalentamiento, pero puede garantizar 10. El QPS del sistema final debe ser 100. Básicamente, satisface todas nuestras necesidades.

************************************************** * ********** La siguiente es la introducción a la API********************************* *** *************************
Comparado con la página, la API solo agrega dos líneas de configuración, es muy simple y no hay otra. diferencia:
Nota: La cantidad de subprocesos simultáneos no admite el efecto de control de flujo.

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Collections;

/**
 * @author pcc
 */
@Configuration
public class FlowConfig {
    
    

    @Bean
    public FlowRule getFlowRule() {
    
    
        FlowRule flowRule = new FlowRule();
        // 声明流控的资源
        flowRule.setResource("testChain");
        // 声明使用的流控规则:0 并发线程数,1 QPS
        flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);

        // 流控规则设置-线程并发阈值2
        flowRule.setCount(100);
        // 来源没有默认值,必须手动设定,default表示对所有来源生效
        flowRule.setLimitApp("default");
        // 流控模式-链路
        flowRule.setStrategy(RuleConstant.STRATEGY_CHAIN);
        // 流控模式-链路-路径
        flowRule.setRefResource("/flow/testFlowRule1");
        // 流控效果-预热
        flowRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
        // 流控效果-预热-预热时间: 10s
        flowRule.setWarmUpPeriodSec(10);


        // 将流控规则交给流控管理器
        FlowRuleManager.loadRules(Collections.singletonList(flowRule));
        return flowRule;
    }
}

6. Página de cola de efectos de control de flujo/API

Aquí está el efecto de control de flujo: esperando en la fila, puede haber tal escenario. El sistema solo puede soportar 1000 QPS, pero tiene un pico de 1500 QPS. Los 500 restantes no se pueden procesar en un instante, pero el pico no durará mucho o aparecerán picos y subestimaciones alternativamente, por lo que en este momento nuestra mejor solución. es utilizar el efecto de control de flujo de cola de espera. El efecto de las colas es similar al de reducción de picos y llenado de valles: el alto tráfico instantáneo es la reducción de picos, y las solicitudes que no se pueden procesar se procesan cuando no hay muchas solicitudes. Por supuesto, también hay casos en los que no hay muchas solicitudes y es posible que no se procesen, en este caso se ejecutará el método de control de flujo blockhandler.
La configuración de la página es la siguiente:
Insertar descripción de la imagen aquí
La configuración anterior significa que las solicitudes con un QPS superior a 100 ingresarán a la cola de espera y esperarán a que se ejecute el sistema. El tiempo de espera máximo es de 5000 ms. Si no se procesa después de 5 segundos, el flujo Se ejecutará el método de control. No hay necesidad de cambiar nada cuando se usa el código de configuración de la página. La verificación también requiere la ayuda de jemeter. Podemos configurar la concurrencia en 150 y ejecutarlo una vez. Si el sistema no ejecuta el método de control de flujo, significa que nuestras solicitudes de más de 100 se procesan normalmente y nuestra cola de espera también entra en vigor.

Insertar descripción de la imagen aquí
Aquí solo se toma una parte de la fotografía, de hecho, toda la información es normal, lo que demuestra que la cola de espera que configuramos está completamente bien.
************************************************** * ********** La siguiente es la introducción a la API********************************* *** **********************
En comparación con la configuración de la página, el único cambio es colocar el efecto de control de flujo: cola y espera en el código, y no hay otros cambios. :

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Collections;

/**
* @author pcc
*/
@Configuration
public class FlowConfig {
    
    

   @Bean
   public FlowRule getFlowRule() {
    
    
       FlowRule flowRule = new FlowRule();
       // 声明流控的资源
       flowRule.setResource("testChain");
       // 声明使用的流控规则:0 并发线程数,1 QPS
       flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);

       // 流控规则设置-线程并发阈值2
       flowRule.setCount(160);
       // 来源没有默认值,必须手动设定,default表示对所有来源生效
       flowRule.setLimitApp("default");
       // 流控模式-链路
       flowRule.setStrategy(RuleConstant.STRATEGY_CHAIN);
       // 流控模式-链路-路径
       flowRule.setRefResource("/flow/testFlowRule1");
       // 流控效果-排队等待
       flowRule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER);
       // 流控效果-排队等待-超时时间: 5s
       flowRule.setMaxQueueingTimeMs(5000);


       // 将流控规则交给流控管理器
       FlowRuleManager.loadRules(Collections.singletonList(flowRule));
       return flowRule;
   }
}

7. Controlar el flujo según la fuente

El control de flujo específico de la fuente es algo similar al modo de enlace en el modo de control de flujo, pero funcionan en diferentes ubicaciones. Los que apunten a la fuente estarán más arriba. Podemos acordar esta fuente con la persona que llama al servicio en el encabezado de la solicitud. Luego podemos realizar el control de flujo para fuentes específicas. El enlace en el modo de control de flujo mencionado anteriormente es el control de flujo realizado dentro del servicio cuando se llama al mismo recurso en diferentes interfaces. Por supuesto, también podemos usar el modo de enlace para lograr el mismo efecto de control de fuente, simplemente proporcionando diferentes fuentes. Proporciona diferentes entradas para que se pueda realizar el control de flujo de enlace para diferentes almacenes. Pero esto sin duda aumentará la cantidad de código, por lo que si desea controlar el código fuente, es mejor utilizar restricciones de código fuente.
Si queremos usar fuentes para el control de flujo, necesitamos usar RequestOriginParser de Sentinel, que proporciona un método parseOrigin para que analicemos la fuente. Cómo analizar la fuente depende de nosotros. Podemos especificarla según Origen, Referencia, etc. También podemos personalizar el encabezado de la solicitud.
Aquí usamos un encabezado de solicitud personalizado para especificar la fuente. Supongamos que el encabezado de la solicitud contiene la fuente del parámetro:

import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.RequestOriginParser;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.Optional;


/**
 * @author pcc
 */
@Component
public class SentinelOriginRequestOriginParser implements RequestOriginParser {
    
    
    @Override
    public String parseOrigin(HttpServletRequest request) {
    
    
        String source = request.getHeader("source");
        /**
         * 当存在来源时我们直接设置来源为传入的值
         * 否则返回null
         */
        if (Optional.ofNullable(source).isPresent()) {
    
    
            return source;
        }
        return null;
    }
}

En el código anterior, obtenemos la fuente en el encabezado de la solicitud como fuente y luego necesitamos usar jemter para configurar la fuente del parámetro del encabezado de la solicitud. Utilicé jemeter aquí para dos solicitudes http, una fuente del encabezado de solicitud se establece en uno y una fuente se establece en dos. La siguiente es la configuración de la página:
Insertar descripción de la imagen aquí
Como se configuró anteriormente, cuando QPS es mayor que 100, el control de flujo se realizará en testFlowRule1, y en este momento solo se controlarán el flujo de las solicitudes con la fuente dos. digamos, si la fuente no es dos, no habrá control de flujo incluso si QPS es mayor que 100.
Insertar descripción de la imagen aquí
Lo anterior es una solicitud cuando se establece fuente = dos en el encabezado de la solicitud y el número de solicitudes simultáneas se establece en 160. Como se esperaba, se produce control de flujo. Cuando se prueba fuente = uno y la concurrencia es 160, no habrá flujo. control.

************************************************** * ********** La siguiente es la introducción a la API********************************* *** **********************
La API solo necesita cambiar un poco de código y no es necesario cambiar otras configuraciones de página:

import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.Collections;

/**
* @author pcc
*/
@Configuration
public class FlowConfig {
    
    

   @Bean
   public FlowRule getFlowRule() {
    
    
       FlowRule flowRule = new FlowRule();
       // 声明流控的资源
       flowRule.setResource("testChain");
       // 声明使用的流控规则:0 并发线程数,1 QPS
       flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);

       // 流控规则设置-线程并发阈值2
       flowRule.setCount(100);
       // 来源没有默认值,必须手动设定,default表示对所有来源生效
       flowRule.setLimitApp("one");
       // 流控模式-链路
       flowRule.setStrategy(RuleConstant.STRATEGY_CHAIN);
       // 流控模式-链路-路径
       flowRule.setRefResource("/flow/testFlowRule1");


       // 将流控规则交给流控管理器
       FlowRuleManager.loadRules(Collections.singletonList(flowRule));
       return flowRule;
   }
}

8. Configuración del clúster

Sin utilizar el modo de clúster, si somos un servicio de clúster, las reglas que establecemos son para un solo nodo.
Use el modo de clúster. Si somos un servicio de clúster, entonces las reglas que establecemos pueden ser para todo el clúster, y el control de flujo de un solo nodo se puede usar como una solución de encubrimiento. Este es en realidad el modo en que los microservicios deberían uso (si la carga del clúster es por turnos) Si se utiliza el sondeo, la diferencia entre el modo de clúster y el modo independiente no es particularmente grande. Si no se utiliza el sondeo, la diferencia será muy grande).
Este modo debe discutirse por separado, porque sería exagerado poner demasiadas cosas aquí, por lo que no lo presentaré aquí por el momento.
Introducción oficial al modo de clúster: modo de clúster de control de flujo Sentinel
Insertar descripción de la imagen aquí

6. Reglas actuales de limitación-autorización: AuthorityRule

Las reglas de autorización en realidad configuran listas negras y listas blancas para recursos. Si se configura una lista blanca para un recurso, las fuentes no configuradas se incluyen en la lista negra. Lo contrario también es cierto: si se configura una lista negra para un recurso, entonces la fuente no configurada es una lista blanca.

1.Página de reglas de autorización/API

El requisito previo para usar reglas de autorización es obtener la fuente de datos: esto es lo mismo que la fuente en el control de flujo, solo use RequestOriginParser. No hay diferencia entre RequestOriginParser aquí y el de control de flujo, así que no repetiré el código Entonces nosotros Las páginas que deben configurarse también son muy simples
Nota: Cuando el autor verificó la autorización, la autorización a la interfaz fue exitosa, pero la autorización al método ordinario no fue aplicable. De hecho, considerando que la interfaz ha entrado, es extraño no permitir el acceso al método. por lo que normalmente también deberíamos ser interceptados en el nivel de la interfaz.
Insertar descripción de la imagen aquí
Si esto está configurado, significa que al acceder a la interfaz actual solo podrán entrar solicitudes con fuente uno, y otras serán rechazadas, de la siguiente manera: ¿Qué pasa
Insertar descripción de la imagen aquí
si hay más de una lista blanca? Podemos usar comas para separar múltiples recursos de la lista blanca (o lista negra) durante la configuración, de la siguiente manera:
Insertar descripción de la imagen aquí
**************************** ***** ******************************* La siguiente es la introducción a la API************ * ***********************************************
API bastante como para la configuración de la página, la configuración simplemente se mueve al código y no se agregan otros cambios. El nuevo código es el siguiente:

  @Bean
  public AuthorityRule getAuthorityRule(){
    
    
      AuthorityRule rule = new AuthorityRule();
      // 授权规则管理的资源
      rule.setResource("/flow/testFlowRule1");
      // 授权策略:白名单0,黑名单1
      rule.setStrategy(RuleConstant.AUTHORITY_WHITE);
      //
      rule.setLimitApp("one,two");

      // 将授权规则交给授权管理器
      AuthorityRuleManager.loadRules(Collections.singletonList(rule));
      return rule;
  }

7. Reglas actuales de limitación de puntos de acceso: ParamFlowRule

Las reglas de puntos de acceso en realidad deberían incluirse en las reglas de control de flujo, porque las reglas de puntos de acceso controlan el flujo de los parámetros de solicitud de recursos en función del control de flujo de recursos. De hecho, las reglas de puntos de acceso hacen que el control de flujo sea más granular. Por lo tanto, debería incluirse en las normas de control de flujo. Además, la regla de puntos de acceso solo admite puntos de acceso en modo QPS y no admite la cantidad de subprocesos simultáneos. Curiosamente, también admite exclusiones.
El escenario de aplicación de las reglas de punto de acceso es principalmente cuando se accede a ciertos datos con demasiada frecuencia o se ejerce una gran presión sobre el servidor. Es necesario controlar la frecuencia de acceso de estos datos. Por ejemplo, hay una operación de consulta relativamente grande y el tipo = 10 es pasado. Tal vez el tipo = 10 tiene muchos datos. No queremos que verifiquen así todo el tiempo. Podemos hacer control de flujo solo para el tipo. Cuando tipo = 10, se realiza el control de flujo. Cuando es igual a otros valores, no se requiere control de flujo o el QPS permitido para pasar es mayor.

1. Página de reglas de hotspot

Esta es la página de configuración de las reglas del hotspot. Supongamos que hay una interfaz con el tipo y nombre de los parámetros:
Insertar descripción de la imagen aquí
Explique los parámetros anteriores:

  • Índice de parámetros: el subíndice de la lista de parámetros de la interfaz, escriba aquí el primer subíndice es 0
  • Umbral de una sola máquina: umbral QPS
  • Tiempo de ventana estadística: el QPS aquí tiene como valor predeterminado el número de solicitudes por segundo, pero también podemos cambiar la unidad de tiempo de las estadísticas. Aquí se cambia a 10 segundos, lo que significa que si hay 3 parámetros de solicitud que llevan el tipo dentro de 10 segundos, el control de flujo se activará.
  • Ya sea para agrupar: el modo de clúster aquí es el mismo que el modo de clúster de control de flujo. No hay diferencia. No entraré en detalles aquí.
  • Excepciones de parámetros: esto equivale a configurar reglas de excepción, lo que significa que las reglas de control de flujo anteriores deben ejecutarse sobre la base de reglas de excepción.
  • Tipo de parámetro: debe ser coherente con el tipo de índice de parámetro aquí, donde el tipo es Cadena.
  • Umbral límite actual: un umbral específico para el valor del parámetro. Podemos configurar el umbral para un valor específico a través de esto. Por ejemplo, cuando el tipo es 10 y quiero que la concurrencia se controle en 1, entonces puedo establecer el umbral en 1 por ello. Otros valores no están sujetos a esta restricción.

Estos parámetros son más fáciles de entender, necesitamos agregar una interfaz para registrarlos en Sentinel:

@RequestMapping("/testParamFlowRule2")
@SentinelResource(
        value = "testParamFlowRule2",
        blockHandler = "testParamFlowRule2",
        blockHandlerClass = BlockMethod.class
)
public String testParamFlowRule2(@RequestParam("type") String type,@RequestParam("name") String name) throws Exception{
    
    
    log.info("{},{}",type,name);
    service.testChain();
    return "testFlowRule1 : success";
}

Luego, también debe proporcionar el método blockhandler del recurso de la siguiente manera:
Nota: debe ser estático y debe haber BlockException

/**
 * 热点流控
 * @param type
 * @param name
 * @return
 * @throws Exception
 */
public static String testParamFlowRule2(String type,String name,BlockException blockException) throws Exception{
    
    
    log.info("热点流控方法:{},{}",type,name);
    return "热点流控了 : success";
}

Luego, de acuerdo con la configuración anterior, el efecto que se debe mostrar es que si el tipo es 11, se puede acceder a él hasta 100 veces cada 10 segundos (es difícil hacer clic en esta velocidad de la mano), si el tipo es 10, se puede se accede hasta una vez cada 10, y si es otro, se puede acceder cada 10. Visité y me emborraché 3 veces.

Insertar descripción de la imagen aquí
Puede ver que cuando se transmite tipo = 11 al principio, el flujo no se controlará cuando se haga clic manualmente. Cuando se transmite 10, el flujo se controlará por cuarta vez.

2. Reglas de hotspot-API

La diferencia entre la configuración de API y la página es que los elementos de configuración se mueven hacia adelante en el código. No hay otra diferencia. Aquí solo se muestra la escritura del código. La verificación no es diferente de lo anterior: Nota: La mayoría de las configuraciones de API admiten Un poco más de funciones que la página
..., puedes estudiarla si estás interesado, pero son básicamente las mismas.

    @Bean
    public ParamFlowRule getParamFlowRule(){
    
    
        ParamFlowRule paramFlowRule = new ParamFlowRule();
        // 热点流控-资源
        paramFlowRule.setResource("testParamFlowRule2");
        // 限流模式-必须QPS,默认就是QPS
        paramFlowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);


        // 参数索引: 方法参数列表下标
        paramFlowRule.setParamIdx(0);
        // 单机阈值
        paramFlowRule.setCount(3);
        // 单机阈值的统计时间:默认1s,支持更改单位秒
        paramFlowRule.setDurationInSec(10);



        // 参数例外项
        ParamFlowItem paramFlowItem = new ParamFlowItem();
        // 参数例外项-参数类型:必须与setParamIdx对应的参数保持一致
        paramFlowItem.setClassType("java.lang.String");
        // 参数例外项-参数值
        paramFlowItem.setObject("10");
        // 参数例外项-限流阈值
        paramFlowItem.setCount(1);

        ParamFlowItem paramFlowItem2 = new ParamFlowItem();
        // 参数例外项-参数类型:必须与setParamIdx对应的参数保持一致
        paramFlowItem2.setClassType("java.lang.String");
        // 参数例外项-参数值
        paramFlowItem2.setObject("11");
        // 参数例外项-限流阈值
        paramFlowItem2.setCount(101);

        List<ParamFlowItem> list = new ArrayList<>();
        list.add(paramFlowItem);
        list.add(paramFlowItem2);
        paramFlowRule.setParamFlowItemList(list);

        // 加载热点流控规则
        ParamFlowRuleManager.loadRules(Collections.singletonList(paramFlowRule));
        return paramFlowRule;
    }

8. Reglas actuales del sistema limitante: SystemRule

Las diversas reglas introducidas anteriormente son para un solo recurso o una sola interfaz, por lo que no pueden garantizar el límite actual de todo el sistema. Las reglas del sistema j están diseñadas para proporcionar un mayor nivel de protección para el sistema en su conjunto. En este momento , el control de flujo de un solo recurso se puede usar como una solución de encubrimiento y las reglas del sistema se pueden usar como una solución general (algunas son similares al modo de clúster, pero no iguales).

1. Página de reglas del sistema/API

La siguiente es la página de configuración de las reglas del sistema:
Insertar descripción de la imagen aquí
Primero, echemos un vistazo al significado de cada parámetro:
Documento oficial de las reglas del sistema: Limitación de corriente adaptativa del sistema

  • CARGA: La carga1 del sistema se utiliza como indicador heurístico para la protección adaptativa del sistema. La protección del sistema se activará cuando la carga del sistema1 exceda el umbral establecido y el número actual de subprocesos simultáneos en el sistema exceda la capacidad estimada del sistema.
    Nota:
    1. El número actual de subprocesos simultáneos en el sistema: maxQps * minRt se puede calcular aproximadamente a partir de esto
    2. Capacidad del sistema: generalmente configurada en núcleos de CPU*2.5
    3. Solo los sistemas Linux tienen el parámetro load1, use el tiempo de actividad para ver el carga del sistema
    Insertar descripción de la imagen aquí

  • RT: cuando el RT promedio de todo el tráfico de entrada en una sola máquina alcanza el umbral, se activa la protección del sistema. La unidad es milisegundos.

  • Número de subprocesos: cuando el número de subprocesos simultáneos para todo el tráfico de entrada en una sola máquina alcanza el umbral, se activa la protección del sistema.

  • QPS de ingreso: cuando el QPS de todo el tráfico de ingreso en una sola máquina alcanza el umbral, se activa la protección del sistema.

  • Uso de la CPU: cuando el uso de la CPU del sistema excede el umbral, se activa la protección del sistema (rango de valores 0,0-1,0), que es relativamente sensible.

Los anteriores son todos los parámetros admitidos por las reglas del sistema. Admite establecer reglas del sistema con diferentes estrategias al mismo tiempo, como configurar carga y RT, etc. Las reglas del sistema protegen los servidores desde el nivel del servidor del sistema. El control de flujo, los puntos de acceso, la autorización, los disyuntores, etc. mencionados anteriormente se basan en recursos o interfaces, esta es su principal diferencia.
Las siguientes son las reglas de RT establecidas:
Insertar descripción de la imagen aquí
Resultados esperados: cuando el RT promedio de la interfaz supera los 30 ms, se activará el control de flujo.
La siguiente es una nueva interfaz:

    @RequestMapping("/testSystemRule")
    @SentinelResource(
            value = "testSystemRule",
            blockHandler = "testSystemRule",
            blockHandlerClass = BlockMethod.class
    )
    public String testSystemRule(@RequestParam("type") String type,@RequestParam("name") String name) throws Exception{
    
    
        log.info("{},{}",type,name);
        // 等待40ms,模仿RT超过30ms
        Thread.sleep(400);
        return "testSystemRule : success";
    }

El siguiente es su método de control de bloques de control de flujo:

    /**
     * 系统规则
     */
    public static String testSystemRule(String type, String name,BlockException blockException) throws Exception{
    
    
        log.info("{},{}",type,name);
        return "系统规则-流控 : success";
    }

Nota:
1. Se ha verificado que las reglas del sistema no se activarán exactamente de acuerdo con los valores establecidos y la sensibilidad de algunos parámetros no es alta. Aquí se utiliza RT para verificar que la sensibilidad no sea alta. 2. El sistema El límite actual
no llamará al método de límite actual correspondiente a la interfaz o recurso al que se accede, sino al método de limitación de corriente unificado: simplemente implemente BlockExceptionHandler. Para obtener más detalles, consulte la introducción en la Sección 4.2 de la cuarta sección de este artículo. Incluso
Insertar descripción de la imagen aquí
si Al configurar el controlador de bloques, el método de limitación de corriente del sistema todavía utiliza el método de limitación de corriente unificado. Esto debería ser comprensible, porque en este momento la solicitud no ingresó a la interfaz sino que fue interceptada a nivel del sistema, naturalmente, se debe utilizar el método de limitación actual a nivel del sistema.
************************************************** * ********** La siguiente es la introducción a la API********************************* *** *************************

   /**
    * 系统限流
    */
   @Bean
   public SystemRule getSystemRule() {
    
    
       SystemRule systemRule = new SystemRule();

       // 平均RT:2ms
       systemRule.setAvgRt(2);

       // 加载规则
       SystemRuleManager.loadRules(Collections.singletonList(systemRule));
       return systemRule;
   }

No hay diferencia entre otras configuraciones y verificación y la página, por lo que no las repetiré aquí.

9. Resumen

De hecho, hay varias partes de este artículo que aún no se han escrito: agrupación en clústeres, integración de Sentinel con la puerta de enlace para control de flujo, modificación del código Sentinel durante la implementación en producción, etc. Sin embargo, este artículo ya ha alcanzado los 50.000 puntos. Si lo escribo más, será demasiado largo y se convertirá en una envoltura para los pies. Actualizaré otra información sobre Sentinel en otro artículo.
La función principal de Sentinel es realizar downgrade, disyuntor, control de flujo, autorización, etc. En realidad, el control de flujo se puede dividir en control de flujo ordinario, control de flujo de datos de punto de acceso, control de flujo del sistema, etc. Lo más importante es que el control de flujo ordinario es la aplicación más común para escribir. El control de flujo ordinario admite dos estrategias: QPS y número de subprocesos concurrentes (puede considerarse como TPS pero no TPS). Cada estrategia admite tres modos de control de flujo diferentes: directo, asociación y enlace. En el escenario QPS, cada modo de control de flujo también admite la edición de diferentes efectos de control de flujo: falla, precalentamiento, cola, etc. De hecho, aunque Sentinel no es difícil, todavía hay mucho conocimiento. Este artículo se puede utilizar como un más guía más detallada que el documento oficial.Aprenda a utilizar el documento, espero que ayude a todos los estudiantes que estén de paso.

Supongo que te gusta

Origin blog.csdn.net/m0_46897923/article/details/132796974
Recomendado
Clasificación