Solución distribuida: limitación de corriente
La limitación del tráfico es muy común en la vida diaria. Por ejemplo, cuando se va a algunos lugares pintorescos, el número de entradas vendidas por día es limitado, como 2000, lo que significa que solo pueden ir 2000 personas cada uno. día. ¿Cuál es el límite actual de nuestro proyecto? Lo que es limitado es el "flujo". En diferentes escenarios, la definición de "flujo" es diferente, que puede ser la cantidad de solicitudes por segundo, la cantidad de transacciones por segundo, el tráfico de red, etc. En términos generales, lo que llamamos límites de flujo se refiere a solicitudes por segundo, transacciones por segundo, tráfico de red, etc. Lo que generalmente llamamos limitación de flujo se refiere a limitar la cantidad de solicitudes simultáneas que llegan al sistema para que el sistema pueda manejar algunas solicitudes de los usuarios normalmente, asegurando así la estabilidad del sistema.
En el negocio diario, habrá actividades de venta flash, promociones de Double Eleven o noticias de última hora. En estos escenarios, el tráfico de usuarios aumentará repentinamente y la capacidad de procesamiento del servicio back-end será limitada, por lo que Backend. Los servicios pueden verse fácilmente abrumados si no pueden manejar ráfagas de tráfico. Además del tráfico anormal, como el de los rastreadores, nuestros servicios expuestos externamente también deben defenderse de las llamadas más maliciosas. No sabemos cómo la persona que llama llamará a nuestro servicio. Supongamos que una persona que llama inicia docenas de hilos las 24 horas del día para llamar a su servicio locamente. Si no tomamos ninguna contramedida, nuestro servicio básicamente terminará. , también serán atacados por DDoS.
Para muchas plataformas abiertas de terceros, no solo es necesario evitar el tráfico anormal, sino también garantizar la utilización justa de los recursos, garantizando que ciertos recursos de la interfaz no siempre puedan estar ocupados por un solo cliente, y también es necesario para garantizar que otros Clientes puedan llamar a estos recursos normalmente.
La limitación de contracorriente es el algoritmo de limitación de corriente más simple. Por ejemplo, el sistema puede procesar 100 solicitudes al mismo tiempo, guardar un contador, aumentar el contador en uno al procesar una solicitud y disminuir el contador en uno después de procesar una solicitud. Cada vez que se recibe una solicitud, el sistema mira el valor del contador y rechaza la solicitud si excede el umbral. Si el valor del contador se almacena en la memoria, se considera un algoritmo de limitación de corriente independiente; si el valor del contador se almacena en un almacenamiento de terceros (como Redis), se considera un algoritmo de limitación de corriente distribuido; si es accedido por un grupo de máquinas.
Los típicos algoritmos de limitación actuales tienen como objetivo limitar el número de visitas dentro de un intervalo de tiempo específico, por lo que también existe un algoritmo llamado ventana fija.
En comparación con el conteo del límite actual, tiene principalmente el concepto de ventana de tiempo. Cada vez que pasa una ventana de tiempo, el contador se reinicia. Las reglas son las siguientes:
Este método también enfrenta algunos problemas, como el problema de criticidad de la ventana fija: suponga que el sistema permite 100 solicitudes por segundo, suponiendo que la primera ventana de tiempo es 0-1, en 0. Aunque el conteo de la ventana no excede el valor crítico, el contador se reinicia cada vez que pasa la ventana de tiempo, por lo que no es necesario cambiarlo. Si bien el recuento en la ventana no supera el umbral, hay 200 solicitudes globalmente en 0,1 segundos entre 0,55 y 1,05 segundos, lo que en realidad es inaceptable para un sistema con un umbral de 100/s.
Para resolver este problema, la industria ha propuesto otro algoritmo de limitación de tráfico, a saber, la limitación de tráfico de ventana deslizante.
La limitación de corriente de la ventana deslizante resuelve el problema de los umbrales de ventana fijos al garantizar que el umbral no se exceda en ninguna ventana de tiempo. En comparación con las ventanas fijas, las ventanas deslizantes requieren la introducción de un contador para registrar el momento en que llega cada solicitud dentro de la ventana de tiempo, por lo que consume más memoria.
Aquí están las reglas suponiendo una ventana de tiempo de 1 segundo:
Sin embargo, ni las ventanas correderas ni las fijas solucionan el problema de concentrar el tráfico en un corto periodo de tiempo. El escenario en el que queremos limitar el tráfico es de 100 solicitudes por segundo. Esperamos tener una solicitud cada 10 milisegundos para que el tráfico se pueda procesar sin problemas, pero en escenarios de aplicaciones reales es difícil controlar la frecuencia de las solicitudes, porque incluso si configuramos 100 solicitudes en 1 segundo, puede ser en 5 milisegundos. . Se alcanzan todos los umbrales. Por supuesto, existen soluciones para abordar esta situación, como establecer múltiples reglas de limitación actuales.
No solo está limitando la cantidad de solicitudes a 100 por segundo, sino que también está estableciendo el umbral en no más de 2 cada 10 ms, lo que resultará en una peor experiencia de usuario.
Por otro lado, el algoritmo de embudo resuelve los puntos débiles del tipo de ventana de tiempo y hace que el flujo sea más fluido.
Como se muestra en la siguiente figura, una gota de agua gotea continuamente dentro del embudo y sale desde el fondo a una velocidad constante. Si las gotas de agua caen más rápido de lo que salen, el balde se desbordará cuando el agua almacenada exceda su capacidad.
Las reglas son las siguientes:
Una gota de agua corresponde a una petición.
Implementado de la misma manera que un grupo de subprocesos.
Ante solicitudes en ráfagas, el servicio las gestionará a la misma velocidad habitual, que no es lo que realmente queremos. Queremos mantener el sistema fluido durante las ráfagas de tráfico y, al mismo tiempo, mejorar la experiencia del usuario tanto como sea posible al poder procesar y responder a las solicitudes más rápido en lugar de seguir las mismas reglas que el tráfico normal.
El depósito de tokens puede ser más agresivo cuando se maneja tráfico en ráfagas.
El depósito de tokens es similar al depósito con fugas, excepto que el depósito con fugas fluye el tráfico a una velocidad constante, mientras que el depósito de tokens introduce tokens en el depósito a una velocidad constante y luego la solicitud solo obtiene el token. Sólo entonces podrá ser pasado y procesado por el servidor.
Por supuesto, el tamaño del depósito de tokens es limitado; suponiendo que el depósito de tokens esté lleno, los tokens generados a un ritmo constante se descartarán.
Reglas:
El principio del depósito de tokens es muy similar al de la señal Semaphore de JUC. Puede controlar el número de accesos simultáneos a recursos. un token. La diferencia es que uno es para obtener la señal y el otro es para obtener el token. Las señales se devuelven cuando se agotan, mientras que los tokens no se devuelven cuando se agotan, ya que se rellenan periódicamente.
Comparándolo con el algoritmo del depósito de embudo, podemos encontrar que el depósito de tokens es más adecuado para manejar el tráfico en ráfagas, por lo que si hay 100 tokens en el depósito, estos 100 tokens se pueden obtener inmediatamente, mientras que No se consume a un ritmo uniforme como un cubo de embudo. Sin embargo, el método anterior de obtener tokens en lotes también generará algunos problemas nuevos, como errores de limitación actual dentro de un cierto rango. Por ejemplo, si toma 10 tokens en este momento y no los usa nuevamente, entonces el clúster. Las máquinas los usarán al mismo tiempo. La capacidad de procesamiento total puede exceder el umbral. Por lo tanto, cuando se usa Redis en la realidad, es posible que no se tenga en cuenta el problema de la lectura frecuente de Redis y el método de recuperar directamente un token a la vez. Se puede utilizar. La estrategia específica a utilizar depende del escenario real.
1. Contador versus ventana fija versus ventana deslizante
2. Embudo versus depósito de tokens
General
Límite independiente El La diferencia esencial entre streaming y limitación distribuida es que el "umbral" se almacena en la ubicación. Los "umbrales" se almacenan en servicios/memoria implementados de forma independiente, pero nuestros servicios generalmente se implementan en un clúster, por lo que necesitamos varias máquinas trabajando juntas para proporcionar la funcionalidad de limitación. Algoritmos como los contadores o ventanas de tiempo anteriores pueden almacenar los contadores en Redis, etc. En el almacenamiento K-V distribuido, otro ejemplo es usar zset de Redis para almacenar el registro de tiempo de cada solicitud en la ventana deslizante, usar ZREMRANGEBYSCORE para eliminar datos fuera de la ventana de tiempo y luego usar ZCARD para contar
Como. Como puede ver, cada límite de tráfico tiene un umbral, y cómo establecer el umbral es una tarea difícil. Es posible que el servidor no tolere umbrales más grandes, mientras que los umbrales más pequeños son "falsos positivos" y no se pueden maximizar. para la experiencia del usuario. El enfoque general es estimar un umbral aproximado después de que el límite actual esté en línea y luego no realizar la operación de límite actual real. En su lugar, utilice el método de registro para analizar los registros y ver el efecto del límite actual. luego ajuste el umbral para obtener la capacidad de procesamiento total del clúster y la capacidad de procesamiento de cada máquina (para facilitar la expansión y reducción). Luego reproduzca el tráfico en línea para probar el efecto real del límite actual, determine el umbral final y luego conéctate.
De hecho, los escenarios comerciales reales son muy complejos, hay muchas condiciones y recursos que requieren limitaciones actuales, y los requisitos de limitación actuales para cada recurso también son diferentes.
En términos generales, no necesitamos implementar el algoritmo de limitación actual nosotros mismos para lograr el propósito de la limitación actual, ya sea que se trate de una limitación de corriente de la capa de acceso o una limitación de corriente de interfaz detallada, existen ruedas listas para usar. que se puede utilizar Ellos La implementación es el algoritmo limitante actual que mencionamos anteriormente.
El método de uso específico sigue siendo muy simple. Los estudiantes interesados pueden buscar por sí mismos. Los estudiantes que estén interesados en la implementación interna pueden consultar el código fuente para comprender cómo se implementa la limitación actual a nivel de producción.
Todavía hay muchos puntos que deben considerarse al aplicar la limitación de corriente a los proyectos. La limitación de corriente es solo una parte para garantizar la estabilidad del sistema, y también debe coordinarse con la degradación, el disyuntor y otro contenido relacionado. .