Análisis del código fuente de las teclas de acceso rápido de JD
Primero observe el método de obtención de la entrada de caché. Cache JdHotKeyStore.getValue es un método para obtener claves de acceso rápido y accederá a algunos informes estadísticos. Si las claves de acceso rápido obtenidas no están vacías, estarán. de lo contrario, serán devueltos desde redis, obtiene y llama a JdHotKeyStore.smartSet para determinar si existe un smartSet. Si existe, establezca el valor y finalmente regrese.
JdHotKeyStore.getValue primero llamará a inRule para verificar si esta clave tiene una regla correspondiente. Si no hay una regla correspondiente, no se procesará y luego llamará a getValueSimple para obtener el objeto de almacenamiento de la clave de acceso rápido. de la memoria local. HotKeyPusher.push comienza a contar; si se obtiene, llamará a isNearExpire para determinar si está a punto de caducar. Si es así, también contará y luego extraerá el valor en ValueModel para ver si hay un conjunto de valores correspondiente. Si es así, volverá. Finalmente, llame a KeyHandlerFactory.getCounter().collect para contar las reglas correspondientes. A continuación se muestra un análisis paso a paso del proceso.
inRule obtendrá la regla correspondiente del caché KeyRule. Después de llamar al método KeyRuleHolder findByKey capa por capa, continuará llamando a su método findRule para seleccionar la KeyRule correspondiente. Si no hay KeyRule, regresará directamente. , de lo contrario obtendrá su duración. Si no hay KeyRule, se devolverá directamente; de lo contrario, se obtendrá su duración (tiempo de caché de teclas de acceso rápido) y se obtendrá la duración correspondiente en el caché local. De hecho, se utiliza get en lugar de contener por razones de versatilidad del método.
La lógica de findRule es bastante especial. El autor dejó una nota, dando prioridad a la coincidencia exacta -> coincidencia de prefijo -> * comodín. Esto se hace para seleccionar la regla correspondiente con mayor precisión. Por ejemplo, si la regla de prefijo sku_ está configurada, pero el tráfico de la sku de Maotai Liquor aumenta repentinamente, el tiempo de caché local para la sku de Maotai Liquor debe ser más largo para permitir que el sistema sobreviva el período pico sin problemas. En este momento, configure un. regla de coincidencia completa de sku_moutai_sku_id, para que no interfiera con las reglas de almacenamiento en caché de otras skus.
Entonces, ¿de dónde viene la regla KEY_RULES? Esto vuelve a etcd, que efectivamente puede considerarse como un cuidador del zoológico, pero también tiene la capacidad de configurar basura y notificar a los clientes. Esta es una doble garantía de cambios regulares de extracción y monitoreo. Esto es muy similar al método de manejo de Ctrip Apollo: no ponga los huevos en la misma canasta. La función de respaldo es realmente importante. Las reglas se extraen de etcd periódicamente cada 5 segundos. Cuando el oyente cambia, las reglas se extraen de etcd. fetchRuleFromEtcd obtiene las reglas de rule_path de ectd, luego las convierte en ruleList y continúa llamando a notifyRuleChange para el procesamiento local.
notifyRuleChange envía una notificación KeyRuleInfoChangeEvent al EventBus, que a su vez envía la notificación al método putRules de KeyRuleHolder, donde puede ver que KEY_RULES y RULE_CACHE_MAP se mantienen.
Volviendo al proceso original, el método getValueSimple implica un proceso largo, principalmente para obtener la duración correspondiente a través de las reglas de la clave y luego obtener el ValueModel de la duración correspondiente del caché local.
El siguiente es HotKeyPusher.push. Si se elimina, cree un nodo en etcd y luego elimínelo para lograr el efecto de eliminación del clúster. Si se trata de una detección y la clave está dentro del alcance de la regla, se llama a KeyHandlerFactory.getCollector().collect para realizar el recuento.
El método KeyHandlerFactory.getCollector().collect alterna el conteo entre las dos asignaciones para que no haya necesidad de hacer una pausa al limpiar la asignación, y el conteo alternativo es una forma efectiva de evitar pausas.
Continuando con lo anterior, también existe un KeyHandlerFactory.getCounter().collect que recopila el número de veces que se accede a una regla, obtiene la regla correspondiente y luego suma el número total de veces que se accede a la regla. Se accede, es decir, se trata de frecuencia tratada térmicamente.
Se ha analizado la recopilación de los dos indicadores, entonces, ¿cómo enviarla al Trabajador? Consulte PushSchedulerStarter, donde se iniciará un grupo de subprocesos programado para estos dos indicadores, y los métodos send y sendCount de NettyKeyPusher se llamarán periódicamente, respectivamente.
Los métodos send y sendCount de NettyKeyPusher seleccionan el trabajador correspondiente para las estadísticas y luego envían una solicitud, mientras que ChooseChannel simplemente realiza un hash a uno de los trabajadores según la clave y envía la solicitud.
Finalmente, cuando el trabajador cuenta las teclas de acceso rápido, el cliente necesita recibir las teclas de acceso rápido enviadas por el trabajador para su almacenamiento. Puede ver que NettyClientHandler envía el evento ReceiverNewKeyEvent a EventBus. Después de recibir este evento, RecibirNewKeyListener llamará a recibirNewKeyListener.newKey, guardará la tecla de acceso rápido en el caché local y el procesamiento del cliente finalizará.
De lo anterior podemos ver que la única interacción entre el cliente y el Trabajador es enviar datos estadísticos al Trabajador, el Trabajador recibe los resultados del procesamiento y finalmente envía las teclas de acceso rápido al cliente, y así sucesivamente. En el lado del trabajador, el análisis solo tiene dos partes: estadísticas resumidas y teclas de acceso rápido. La lógica está en HotKeyFilter, primero acumulará totalReceiveKeyCount y luego llamará a PublishMsg. Si las estadísticas caducan durante 1 segundo o están en la lista blanca, no se procesarán; de lo contrario, continuará llamando a keyProducer.push.
keyProducer .push coloca estadísticas no caducadas en la cola.
El trabajador abre el número especificado de KeyConsumers para continuar consumiendo estadísticas de la cola.
Los métodos removeKey y newKey de KeyListener se llamarán según el tipo de datos estadísticos.
Los métodos removeKey y newKey de KeyListener eliminan o acumulan SlidingWindow en el caché y luego lo eliminan o lo envían a todos los clientes seleccionados según el nombre de la aplicación.
El procesamiento de teclas de acceso rápido de JD.com utiliza el conteo para determinar dinámicamente si se trata de una tecla de acceso rápido y luego la almacena en caché en la memoria local para lograr una expansión a nivel de milisegundos.
Entonces ¿no hay otra solución?
1. Si se enfrenta a algunos escenarios en los que la clave de caché es muy pequeña, como la información de la página activa (no más de 1000 páginas activas al mismo tiempo), puede colocar el caché directamente en la memoria local. y luego actualice Recupere el caché más reciente de redis sin calcular dinámicamente las teclas de acceso rápido.
2. También es un juicio dinámico de las teclas de acceso rápido, pero las teclas de acceso rápido se migran a un clúster redis de teclas de acceso rápido dedicado con más nodos. Cada nodo del clúster tiene el mismo caché de teclas de acceso rápido. , las solicitudes se pueden dispersar para evitar que el tráfico fluya al mismo nodo de Redis. Si se determina que la tecla de acceso rápido es una tecla de acceso rápido, se colocará en el grupo de teclas de acceso rápido. No es necesario que los grupos de teclas de acceso rápido existan en la memoria local y son más fáciles de mantener.