Springboot + aop + Lua distribuido análisis de principio de limitación de corriente

1. ¿Cuál es el límite actual? ¿Por qué limitar la corriente?
No sé si alguna vez has hecho el metro de la Ciudad Imperial, es decir, del tipo que tienes que hacer cola cuando vas a la estación de metro. ¿Por qué tienes que ir en círculos de esta manera? ¡La respuesta es limitar la corriente! Debido a que la capacidad de transporte de un metro es limitada, abarrotar a demasiadas personas a la vez provocará el hacinamiento de la plataforma y la sobrecarga del tren, y habrá ciertos riesgos de seguridad. De la misma manera, nuestro programa es el mismo y su capacidad para procesar solicitudes es limitada. Una vez que el número de solicitudes excede su límite de procesamiento, se bloqueará. Para no tener la peor situación de choque, solo podemos retrasar el tiempo para que todos ingresen a la estación.
Springboot + aop + Lua distribuido análisis de principio de limitación de corriente

¡La limitación de corriente es un medio importante para garantizar una alta disponibilidad del sistema! ! !

Debido al enorme tráfico de las compañías de Internet, el sistema se pondrá en línea para realizar una evaluación de tráfico pico, especialmente como varias promociones de picos. Con el fin de garantizar que el sistema no se vea abrumado por el tráfico enorme, cuando el tráfico del sistema alcance un cierto umbral, rechazará parte del tráfico .

El límite actual hará que el usuario no esté disponible por un corto período de tiempo (este período de tiempo es del orden de milisegundos). En general, el indicador para medir la capacidad de procesamiento del sistema es QPS o TPS por segundo. Suponiendo que el umbral de flujo del sistema por segundo es 1000, teóricamente Cuando llega una solicitud 1001 dentro de un segundo, la solicitud se acelerará.

Segundo, el programa de límite actual
1. El contador
Java también puede usar el contador atómico AtomicInteger, Semaphore semaphore para hacer un límite de corriente simple.

// 限流的个数
        private int maxCount = 10;
        // 指定的时间内
        private long interval = 60;
        // 原子类计数器
        private AtomicInteger atomicInteger = new AtomicInteger(0);
        // 起始时间
        private long startTime = System.currentTimeMillis();

        public boolean limit(int maxCount, int interval) {
                atomicInteger.addAndGet(1);
                if (atomicInteger.get() == 1) {
                        startTime = System.currentTimeMillis();
                        atomicInteger.addAndGet(1);
                        return true;
                }
                // 超过了间隔时间,直接重新开始计数
                if (System.currentTimeMillis() - startTime > interval * 1000) {
                        startTime = System.currentTimeMillis();
                        atomicInteger.set(1);
                        return true;
                }
                // 还在间隔时间内,check有没有超过限流的个数
                if (atomicInteger.get() > maxCount) {
                        return false;
                }
                return true;
        }

2.
Algoritmo de cubeta con fugas La idea del algoritmo de cubeta con fugas es muy simple: comparamos el agua como una solicitud y la cubeta con fugas como el límite de la capacidad de procesamiento del sistema. Cuando la tasa es menor que la tasa de entrada, debido a la capacidad limitada del cubo con fugas, el agua entrante subsiguiente se desborda directamente (rechaza la solicitud) para lograr la limitación de flujo.
Springboot + aop + Lua distribuido análisis de principio de limitación de corriente

3.
Algoritmo de depósito de fichas El principio del algoritmo de depósito de fichas también es relativamente simple. Podemos entenderlo como un hospital registrado para ver a un médico. Solo después de obtener el número se puede diagnosticar al médico.
El sistema mantiene un depósito de fichas y coloca fichas en el depósito a una velocidad constante. Si llega una solicitud y quiere ser procesada, primero debe obtener una ficha del depósito. ), Cuando no hay token disponible en el depósito, se denegará la solicitud de servicio. El algoritmo de depósito de tokens alcanza el límite de solicitudes controlando la capacidad del depósito y la tasa de emisión de tokens.
Springboot + aop + Lua distribuido análisis de principio de limitación de corriente

4. Redis + Lua ¿
Muchos estudiantes no saben qué es Lua? Personalmente, los scripts Lua y las bases de datos MySQL tienen procedimientos almacenados similares, ejecutan un conjunto de comandos y todos los comandos se ejecutan con éxito o no logran la atomicidad. También puede entender el script Lua como un fragmento de código con lógica empresarial.

Lua en sí es un lenguaje de programación. Aunque Redis no proporciona directamente la API correspondiente para la limitación de corriente, admite la función de los scripts de Lua. Se puede usar para implementar algoritmos complejos de depósito de tokens o depósito de fugas, que también se implementan en sistemas distribuidos. Una de las principales formas de limitar la corriente.

En comparación con las transacciones de Redis, las ventajas de los scripts de Lua son:

Reduzca la sobrecarga de la red: use el script Lua, no necesite enviar múltiples solicitudes a Redis, ejecútelo una vez, reduzca
la operación atómica de transmisión de red : Redis ejecuta el script Lua completo como un comando, atómico, sin preocuparse por la
reutilización concurrente : una vez que se ejecuta el script Lua, Se guardará permanentemente en Redis, y otros clientes pueden reutilizar los
scripts de Lua aproximadamente de la siguiente manera:

-Obtener el primer valor de clave que se pasa al llamar al script (utilizado como la clave de límite actual) clave
local = KEYS [1] -Obtener
el primer valor de parámetro que se pasa al llamar al límite
local de script (límite de tamaño actual) = número (ARGV [1])


-Obtenga el tamaño actual del tráfico local curentLimit = tonumber (redis.call ('get', key) o "0")

-- 是否超出限流
    if curentLimit + 1 > limit then
            -- 返回(拒绝)
            return 0
    else
            -- 没有超出 value + 1
            redis.call("INCRBY", key, 1)
            -- 设置过期时间
            redis.call("EXPIRE", key, 2)
            -- 返回(放行)
            return 1
    end

Obtenga el parámetro de clave entrante a través de KEYS [1] Obtenga el parámetro de
límite entrante a través del método ARGV [1]
redis.call, obtenga el valor relacionado con la clave del caché, si es nulo, devuelva 0 y
luego juzgue el registro en el caché Si el valor será mayor que el tamaño límite. Si excede el límite, significa que la corriente es limitada.
Si no excede 0 , entonces el valor de caché de la clave es +1, y el tiempo de caducidad se establece en 1 segundo más tarde, y
se devuelve el valor de caché +1. La solución recomendada en este artículo se explicará en detalle más adelante.

5. La limitación de corriente de la capa de puerta de enlace y la
limitación de corriente a menudo se realizan en la capa de puerta de enlace, como Nginx, Openresty, kong, zuul, Spring Cloud Gateway, etc., y el principio de implementación subyacente de la limitación de corriente de la puerta de enlace de Spring Cloud-Gateway se basa en Redis + Lua Guión de limitación de corriente Lua incorporado.
Springboot + aop + Lua distribuido análisis de principio de limitación de corriente

Tercero, implementación de limitación actual de Redis + Lua
A continuación, logramos la limitación actual a través de anotaciones personalizadas, aop, Redis + Lua, los pasos serán más detallados, para que Bai Bai pueda comenzar rápidamente, los veteranos experimentados tendrán más cuidado.

1. La
dirección de creación del proyecto springboot de preparación del entorno : https://start.spring.io , una herramienta muy conveniente y práctica.

Springboot + aop + Lua distribuido análisis de principio de limitación de corriente
2. Introduzca el paquete de dependencia en el
archivo pom y agregue los siguientes paquetes de dependencia: los principales son spring-boot-starter-data-redis y spring-boot-starter-aop.

<dependencies>
                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-web</artifactId>
                </dependency>
                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-data-redis</artifactId>
                </dependency>
                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-aop</artifactId>
                </dependency>
                <dependency>
                        <groupId>com.google.guava</groupId>
                        <artifactId>guava</artifactId>
                        <version>21.0</version>
                </dependency>
                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-test</artifactId>
                </dependency>
                <dependency>
                        <groupId>org.apache.commons</groupId>
                        <artifactId>commons-lang3</artifactId>
                </dependency>

                <dependency>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-starter-test</artifactId>
                        <scope>test</scope>
                        <exclusions>
                                <exclusion>
                                        <groupId>org.junit.vintage</groupId>
                                        <artifactId>junit-vintage-engine</artifactId>
                                </exclusion>
                        </exclusions>
                </dependency>
        </dependencies>

3. Configure application.properties
para configurar la dirección del servicio redis y el puerto que se han creado de antemano en el archivo application.properties.

spring.redis.host=127.0.0.1

spring.redis.port=6379
4、配置RedisTemplate实例
@Configuration
public class RedisLimiterHelper {

@Bean
public RedisTemplate<String, Serializable> limitRedisTemplate(LettuceConnectionFactory redisConnectionFactory) {
    RedisTemplate<String, Serializable> template = new RedisTemplate<>();
    template.setKeySerializer(new StringRedisSerializer());
    template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
    template.setConnectionFactory(redisConnectionFactory);
    return template;
}

}
Clase de enumeración de tipo de límite actual

/**
 * @author fu
 * @description 限流类型
 * @date 2020/4/8 13:47
 */
public enum LimitType {

        /**
         * 自定义key
         */
        CUSTOMER,

        /**
         * 请求者IP
         */
        IP;
}

5. Anotaciones personalizadas
Definimos una anotación @Limit, el tipo de anotación es ElementType.METHOD, que actúa sobre el método.

período es el período de tiempo límite de la solicitud, y cuenta es el número de veces que se permite liberar la solicitud durante el período. limitType representa el tipo de límite actual. Puede personalizar la clave de acuerdo con la IP solicitada. Si no pasa el atributo limitType, el nombre del método se utiliza como clave predeterminada de forma predeterminada.

/**
 * @author fu
 * @description 自定义限流注解
 * @date 2020/4/8 13:15
 */
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Limit {

/**
 * 名字
 */
String name() default "";

/**
 * key
 */
String key() default "";

/**
 * Key的前缀
 */
String prefix() default "";

/**
 * 给定的时间范围 单位(秒)
 */
int period();

/**
 * 一定时间内最多访问次数
 */
int count();

/**
 * 限流的类型(用户自定义key 或者 请求ip)
 */
LimitType limitType() default LimitType.CUSTOMER;
}

6. Implementación del código de aspecto
/ **

}
8. Prueba de
expectativa de prueba: tres solicitudes consecutivas pueden ser exitosas, la cuarta solicitud es rechazada. A continuación, veamos si esperamos el efecto. La dirección de solicitud:
http://127.0.0.1:8080/limitTest1 . Utilice postman para probar. Es lo mismo si hay una URL de cartero publicada directamente en el navegador.
Springboot + aop + Lua distribuido análisis de principio de limitación de corriente

Se puede ver que cuando se realizó la cuarta solicitud, la aplicación rechazó directamente la solicitud, lo que indica que nuestra solución de limitación de corriente Springboot + aop + lua se creó con éxito.

Springboot + aop + Lua distribuido análisis de principio de limitación de corriente
Para resumir el
springboot + aop + Lua actual, la implementación del límite actual es relativamente simple, diseñada para que todos sepan cuál es el límite actual. Cómo hacer una función de límite de corriente simple, la entrevista debe saber de qué se trata. Aunque las soluciones mencionadas anteriormente para lograr la limitación actual, pero cuál elegir debe combinarse con escenarios comerciales específicos, no se puede utilizar para su uso.

Supongo que te gusta

Origin blog.51cto.com/14765930/2486702
Recomendado
Clasificación