Procesamiento de limitación actual en escenarios de alta concurrencia

Para los sistemas comerciales, la alta concurrencia es para soportar "solicitudes masivas de usuarios", y QPS será cientos de veces o incluso más alto de lo habitual.
Si no se considera una alta concurrencia, incluso si el sistema empresarial generalmente funciona bien, una vez que la cantidad de concurrencia aumenta, se producirán varios problemas comerciales extraños con frecuencia. Por ejemplo, en el negocio del comercio electrónico, puede haber pérdida de pedidos e inventario de los usuarios deducciones Anormales, sobreventa y otros problemas.

La limitación de corriente es un medio de degradación del servicio.Como su nombre lo indica, el propósito de proteger el sistema se logra limitando el flujo del sistema.

Una configuración de limitación de corriente razonable requiere una comprensión del rendimiento del sistema, por lo que la limitación de corriente generalmente requiere una combinación de planificación de capacidad y prueba de presión.

Cuando la solicitud externa se acerca o alcanza el umbral máximo del sistema, se activa el límite actual y se toman otras medidas para degradar para proteger el sistema de ser abrumado. Las estrategias comunes de degradación incluyen procesamiento retrasado, denegación de servicio, denegación aleatoria, etc.

La estrategia de limitación actual es en realidad muy similar al grupo de subprocesos en la programación concurrente de Java. Todos sabemos que cuando el grupo de subprocesos está lleno, se pueden configurar diferentes estrategias de rechazo, como:

AbortPolicy, descartará tareas y lanzar una excepción
DiscardPolicy, tareas de descarte, no tiro excepción
DiscardOldestPolicy, etc. Por supuesto, también se puede poner en práctica la estrategia de rechazo de sí mismo.
Agrupación de hebras de Java es un pequeño punto de función en el desarrollo, pero también se puede extender a el sistema En términos de diseño y arquitectura, el conocimiento se transfiere y se reutiliza de manera razonable.

Uno de los puntos clave en el esquema de limitación actual es cómo juzgar que el flujo de corriente ha alcanzado el valor máximo que establecimos. Existen diferentes estrategias de implementación. El siguiente es un análisis simple.

  1. Método de contador
    En general, cuando limitamos la corriente, utilizamos el número de solicitudes por unidad de tiempo, lo que comúnmente se conoce como QPS. La idea más directa de contar QPS es implementar un contador.

El método de contador es el algoritmo más simple en el algoritmo de limitación actual. Suponemos que una interfaz limita el número de visitas en 100 segundos a no más de 10,000 veces. Se mantiene un contador. Cada vez que llega una nueva solicitud, el contador aumenta en 1.

A juzgar en este momento,

Si el valor del contador es menor que el valor límite actual, y el intervalo de tiempo con la última solicitud está dentro de los 100 segundos, la solicitud puede pasar; de lo contrario, la solicitud
es rechazada. Si se excede el intervalo de tiempo, el contador debe . ser limpiado
el código siguiente usos AtomicInteger como el mostrador, puede ser utilizado como una referencia:

public class CounterLimiter {
    
     
    //初始时间 
    private static long startTime = System.currentTimeMillis(); 
    //初始计数值 
    private static final AtomicInteger ZERO = new AtomicInteger(0); 
    //时间窗口限制 
    private static final int interval = 10000; 
    //限制通过请求 
    private static int limit = 100; 
    //请求计数 
    private AtomicInteger requestCount = ZERO; 
    //获取限流 
    public boolean tryAcquire() {
    
     
        long now = System.currentTimeMillis(); 
        //在时间窗口内 
        if (now < startTime + interval) {
    
     
            //判断是否超过最大请求 
            if (requestCount.get() < limit) {
    
     
                requestCount.incrementAndGet(); 
                return true; 
            } 
            return false; 
        } else {
    
     
            //超时重置 
            requestCount = ZERO; 
            startTime = now; 
            return true; 
        } 
    } 
} 
 

La estrategia de contador limita la corriente y se puede extender desde un solo punto a un clúster, que es adecuado para su aplicación en un entorno distribuido.

La limitación de corriente de un solo punto puede usar memoria. Si se expande a la limitación de corriente del clúster, puede usar un nodo de almacenamiento independiente, como Redis o Memcached, para el almacenamiento. Establezca el tiempo de vencimiento en un intervalo de tiempo fijo y luego podrá contar el tráfico de clúster y realizar la limitación general.

La contra estrategia tiene una gran desventaja, no es amigable con el flujo crítico y el límite actual no es lo suficientemente suave.

Suponiendo tal escenario, limitamos a los usuarios a realizar pedidos no más de 100.000 veces por minuto. Ahora, en la intersección de las dos ventanas de tiempo, se envían 100.000 solicitudes en un segundo. En otras palabras, dentro de los dos segundos de cambio de ventana, el sistema recibió 200.000 solicitudes de pedido. Este valor máximo puede exceder el umbral del sistema y afectar la estabilidad del servicio.

La optimización del algoritmo del contador es para evitar la solicitud del doble del límite de la ventana, se puede implementar mediante el algoritmo de la ventana deslizante y los estudiantes interesados ​​pueden ir a averiguarlo.

  1. Algoritmos de
    depósito con fugas y depósito de fichas El algoritmo de depósito con fugas y el algoritmo de depósito de fichas se utilizan más ampliamente en aplicaciones prácticas y, a menudo, se comparan.

El algoritmo del balde con fugas se puede comparar con el balde con fugas. Suponiendo que hay un balde de capacidad fija y se perfora un pequeño orificio en la parte inferior para filtrar el agua, controlamos el procesamiento de las solicitudes controlando la tasa de fuga de agua para lograr la corriente limitante.

La estrategia de rechazo del algoritmo del depósito con fugas es muy simple: si la solicitud externa supera el umbral actual, se acumulará en el depósito hasta que se desborde y el sistema no se preocupa por el tráfico de desbordamiento.

El algoritmo del depósito con fugas limita la tasa de solicitud desde la salida. No hay ningún problema crítico con el método de contador anterior y la curva de solicitud siempre es suave.

Uno de sus problemas centrales es que el filtrado de solicitudes es demasiado preciso. A menudo decimos "no hay peces cuando el agua está clara". De hecho, lo mismo ocurre con el límite actual. Limitamos el pedido a 100.000 veces por segundo, que es 100.000. ¿Qué pasa con esta solicitud? ¿Tengo que rechazarlo?

En la mayoría de los escenarios comerciales, la respuesta es no. Aunque la corriente es limitada, todavía se espera que el sistema permita una cierta ráfaga de tráfico. En este momento, se requiere el algoritmo de token bucket.

En el algoritmo del depósito de tokens, supongamos que tenemos un depósito de tamaño constante. La capacidad de este depósito está relacionada con el umbral establecido. Hay muchos tokens en el depósito. A una tasa fija, los tokens se colocan en el depósito. Cuando está lleno, descarte los tokens y la cantidad máxima de tokens que se pueden almacenar en el depósito nunca excederá el tamaño del depósito. Cuando llega una solicitud, intenta eliminar un token del depósito. Si el depósito está vacío, la solicitud se rechazará.

Me pregunto si ha utilizado el kit de herramientas de código abierto Guava de Google. La clase de herramienta RateLimiter de la estrategia de flujo limitado en Guava, RateLimiter, implementa la restricción de flujo basada en el algoritmo de token bucket, que es muy conveniente de usar.

RateLimiter arrojará tokens al depósito con una frecuencia determinada, y el hilo puede ejecutar el token después de obtener el token. La API de RateLimter se puede aplicar directamente. Los métodos principales son adquirir y tryAcquire.

La adquisición se bloqueará, el método tryAcquire no es bloqueante.

Aquí hay un ejemplo simple:

public class LimiterTest {
    
     
    public static void main(String[] args) throws InterruptedException {
    
     
        //允许10个,permitsPerSecond 
        RateLimiter limiter = RateLimiter.create(100); 
        for(int i=1;i<200;i++){
    
     
            if (limiter.tryAcquire(1)){
    
     
                System.out.println("第"+i+"次请求成功"); 
            }else{
    
     
                System.out.println("第"+i+"次请求拒绝"); 
            } 
        } 
    } 
} 
 

Comparación de diferentes algoritmos de limitación de corriente El algoritmo de
contador es relativamente simple de implementar y es particularmente adecuado para su uso en clústeres. Sin embargo, se deben considerar las condiciones críticas y se pueden usar estrategias de ventana deslizante para la optimización. Por supuesto, también depende de la corriente específica -escenarios limitantes.

El algoritmo del depósito con fugas y el algoritmo del depósito con fugas. El algoritmo del depósito con fugas proporciona un límite de corriente relativamente estricto. El algoritmo del depósito con fugas permite un cierto grado de tráfico en ráfagas además del límite actual. En el desarrollo real, no necesitamos controlar el flujo con tanta precisión, por lo que el algoritmo del depósito de tokens tiene más aplicaciones.

Si el tráfico máximo que establecemos es allowPerSecond = N, que es el número de solicitudes por segundo, el algoritmo del contador tendrá tráfico 2N, el algoritmo del depósito con fugas siempre limitará el tráfico N y el algoritmo del depósito del token permite más de N, pero No alcanzar un pico tan alto como 2N.

Referencia: "¡Los últimos conceptos básicos de Java de 2020 y tutoriales en video detallados y rutas de aprendizaje!

Enlace: https://segmentfault.com/a/1190000038949009

Supongo que te gusta

Origin blog.csdn.net/weixin_46699878/article/details/112524965
Recomendado
Clasificación