Análisis del código fuente de Alibaba Sentinel
Comience con el proceso principal de Sentinel y analice cómo Sentinel recopila indicadores de tráfico y completa la configuración del tráfico.
Primero, veamos una demostración centinela simple. Simplemente llame a SphU.entry para obtener la entrada y luego llame a Entry.exit después de completar el método comercial.
SphU.entry llamará a Env.sph.entry, encapsulará el nombre y la dirección del flujo de tráfico en StringResourceWrapper y luego continuará llamando al procesamiento de entrada.
Ingrese el método de entrada de CtSph y finalmente acceda a EntryWithPriority y llame a InternalContextutil. InternalEnter inicializa el contexto de ThreadLocal, luego llama a lookProcessChain para inicializar la cadena de responsabilidad y finalmente llama a chain.entry para ingresar a la cadena de responsabilidad para su procesamiento.
InternalContextutil. InternalEnter llamará al método trueEnter, principalmente para generar el proceso de DefaultNode a ContextNameNode, y luego generará el proceso de establecer el contexto en contextHolder.
LookProcessChain se ha optimizado para admitir la carga spi de generadores de cadenas de responsabilidad personalizados. Si no se define, se utilizará el DefaultSlotChainBuilder predeterminado para la carga. Las ranuras y secuencias cargadas por defecto se pueden ver en el mapa de construcción de la ciudad y no se describirán nuevamente.
Finalmente, el evento principal chain.entry ingresa a la cadena de responsabilidad para el procesamiento, y cada procesador lo analizará por separado en orden.
Lo primero es NodeSelectorSlot, que principalmente obtiene el DefaultNode correspondiente al nombre y lo almacena en caché, lo establece como el nodo actual del contexto y luego notifica al siguiente nodo.
El siguiente nodo es ClusterBuilderSlot, continúe configurando ClusterNode y OriginNode para DefaultNode y luego notifique al siguiente nodo.
El siguiente nodo es LogSlot, que simplemente imprime registros, por lo que no entraré en detalles.
El siguiente nodo es StatisticSlot, que es un post-nodo. Primero, notifique al siguiente nodo después del procesamiento,
1. Si no hay errores, aumente la cantidad de subprocesos y la cantidad de solicitudes de entrega para nodo, clusterNode, originNode y ENTRY_NODE.
2. Si el error es PriorityWaitException, solo se aumentará el número de subprocesos.
3. Si el error es una BlockException, establezca el error en nodo y luego aumente el número de solicitudes de bloqueo.
4. Si se informan otros errores, simplemente establezca el error en node.
El siguiente nodo es FlowSlot, que es un nodo importante para el procesamiento de limitación actual. Para ingresar a este nodo, llame a checker.checkFlow para el procesamiento de limitación actual.
Vaya al método checkFlow de FlowRuleChecker, llame a ruleProvider.apply para obtener la lista FlowRule correspondiente al recurso, luego recorra FlowRule y llame a canPassCheck para verificar las reglas de restricción actuales.
CanPassCheck elegirá la limitación de corriente del clúster o la limitación de corriente local según el método de limitación actual de la regla, que se analizará aquí.
PassLocalCheck es la entrada a la limitación de corriente local. Primero, se llamará a SelectNodeByreQuestRandStrategy para seleccionar el nodo actualmente limitado y luego se llamará a canPass para su verificación.
selectnodebyrequestrandstrategy seleccionará nodos de acuerdo con las siguientes reglas.
1. La estrategia es STRATEGY_DIRECT.
Cuando 1.1.limitApp no es otra y es la predeterminada, y es igual a orgin, seleccione originNode.
1.2.limitApp Otros, seleccione originNode.
1.3.limitApp es el valor predeterminado, seleccione clusterNode.
2. La estrategia es STRATEGY_RELATE y seleccione clusterNode.
3. La estrategia es STRATEGY_CHAIN, selecciona el nodo.
Después de seleccionar el nodo correspondiente, se llamará a canPass para verificar la regla de limitación actual. Actualmente, Sentinel tiene tres reglas locales de limitación de corriente: limitación de corriente normal, limitación de corriente de velocidad constante y limitación de corriente de arranque en frío.
Una implementación común de limitación actual es DefaultController, que cuenta si el número actual de subprocesos o qp más el número a pasar es mayor que el valor límite. Si es menor o igual al límite, pasará directamente, de lo contrario se bloqueará.
La implementación de la limitación de corriente unificada es RateLimiterController, que utiliza AtomicLong para garantizar el crecimiento atómico de LatestPassedTime, por lo que el tiempo de pausa se calcula en función de LatestPassedTime-currentTime para obtener un tiempo de suspensión unificado.
La implementación de la limitación de corriente de arranque en frío es WarmUpController, que es el método de limitación de corriente más difícil en Sentinel. De hecho, no necesita prestar demasiada atención al cálculo de estas fórmulas complejas, también puede obtener la idea de limitación de corriente de arranque en frío:
1. Cuando qps haya alcanzado el estado cálido, agregue. tokens y consumir tokens normalmente.
2. Cuando qps está en un estado sobreenfriado, se agrega un token para mantener el algoritmo fresco.
3. Cuando qps aumenta gradualmente y excede el valor de qps del límite de sobreenfriamiento, ya no se agregarán tokens. La cantidad de solicitudes que se pueden pasar por unidad de tiempo aumentará gradualmente consumiendo tokens lentamente, de modo que. el algoritmo continúa preparándose en caliente.
En resumen, la cantidad de solicitudes que pueden pasar es inversamente proporcional a la cantidad de tokens que quedan en el depósito de tokens, logrando así el efecto de inicio en frío.
El siguiente paso es limitar la corriente del clúster. passClusterCheck es la entrada a la limitación de corriente del clúster. Llamará a clusterSerivce para obtener la cantidad especificada de tokens según el flowId y luego determinará si se pasa, se suspende, se degrada a la limitación de corriente local o se bloquea según el resultado.
A continuación, veamos el procesamiento de ClusterService. Se obtendrá la FlowRule correspondiente en función del ruleId y luego se llamará a ClusterFlowChecker. Obtenga el resultado y devuélvalo. Comprobador de flujo de clúster. El método de procesamiento de AcquireClusterToken es el mismo que el de la limitación de corriente ordinaria, excepto que todas las solicitudes del clúster se procesarán en un servicio para lograr el efecto de limitación de corriente del clúster. No entraré en detalles.
El siguiente nodo de FlowSlot es DegradeSlot, que es un procesador de fusibles. Cuando entra, llama a performChecking para obtener la lista de disyuntores y luego llama a tryPass para verificar si está fundido.
El método tryPass del disyuntor abstracto se utiliza principalmente para determinar el estado del fusible.
Si está cerrado, se liberará directamente. Si está abierto, se comprobará si es el momento de abrirlo. Si tiene éxito, se seguirá liberando; de lo contrario, se bloqueará.
Entonces, ¿cómo se cambia el estado del fusible de apagado a encendido? ¿Cómo convertir un semiabierto en cerrado o abierto? Sentinel consta de dos fusibles: el fusible con número de error ExceptionCircuitBreaker y el fusible de tiempo de respuesta ResponseTimeCircuitBreaker; se analizan todos los fusibles.
Cuando un método empresarial informa un error, llama a Tracer.traceEntry para establecer el error en Entrada.
Cuando se llama a Entry.exit, seguirá la cadena de responsabilidad hasta el método de salida de DegradeSlot, atravesará la lista de fusibles y llamará a su método onRequestComplete.
onRequestComplete de ExceptionCircuitBreaker registra el número de errores y el número total de solicitudes, y luego llama a HandleStateChangeWhenthereshelded para continuar con el procesamiento.
1. Cuando el estado actual está encendido, la parte inferior del fusible no debe cambiar de estado y salir directamente.
2. Cuando el estado actual es medio abierto, si no hay error, gire medio abierto a cerrado; de lo contrario, gire medio abierto para abrir.
3. Cuando el estado actual es cercano, se basa en si el número total de solicitudes ha alcanzado el número mínimo de solicitudes. Si es así, compare si el número de errores/tasa de error es mayor que el valor límite. Si es así, se convierte directamente para abrir.
OnRequestComplete de ExceptionCircuitBreaker registra el número de respuestas lentas y el número total de solicitudes, y luego llama a HandleStateChangeWhenthereshelded para continuar con el procesamiento.
1. Cuando el estado actual está encendido, la parte inferior del fusible no debe cambiar de estado y salir directamente.
2. Cuando el estado actual es medio abierto, si el tiempo de respuesta actual es menor que el valor límite, medio abierto se girará para cerrar; de lo contrario, medio abierto se girará para abrir.
3. Cuando el estado actual es cercano, se basa en si el número total de solicitudes ha alcanzado el número mínimo de solicitudes. Si es así, compare si la proporción de solicitudes lentas/solicitudes lentas es mayor que el valor límite. Si es así, se convierte directamente para abrir.
El siguiente nodo es AuthoritySlot, el controlador de autoridad. Este controlador solo verifica si el origen actual permite solicitudes de entrada. De lo contrario, informará un error sin entrar en detalles.
Finalmente, llegamos al último nodo SystemSlot, que es un procesador adaptativo. Se basa principalmente en la carga del propio sistema (qps, número máximo de subprocesos, tiempo máximo de respuesta, utilización de la CPU, bbr del sistema) para determinar si la solicitud puede pasar y garantizar que el sistema esté en un estado seguro que pueda procesar la solicitud de manera estable.
Vale la pena mencionar especialmente el algoritmo bbr. Refiriéndose al diseño de tcp bbr, el autor calcula dinámicamente la cantidad de subprocesos que pueden ingresar a través del qps máximo y el tiempo de respuesta mínimo, en lugar de fijar aproximadamente la cantidad de subprocesos que pueden ingresar. ¿Por qué se puede calcular el número de hilos que pueden entrar a partir de estos dos valores? Puede buscar en línea un análisis del algoritmo tcp bbr. Es muy inteligente y no entraré en detalles.