Simplemente comprenda la estrategia de confiabilidad de mensajes de Kafka

Autor: hymanzhang, Ingeniero de desarrollo de Tencent de operadores de IEG

antecedentes

En el proceso de desarrollo de una actividad recientemente, los compañeros de desarrollo del departamento deben prestar atención a mucha lógica de fondo de la aplicación y capturar la activación de varios eventos. En el diseño, pretendemos utilizar la cola de mensajes de Kafka para desacoplar la lógica empresarial, de modo que el desarrollo de la actividad y el trabajo de los estudiantes de desarrollo en segundo plano estén separados. Sin embargo, los estudiantes que lo utilizan no están muy familiarizados con el principio y se preocupan por los siguientes problemas:

  • ¿En qué escenarios comerciales utilizo las colas de mensajes?

  • ¿Debo esperar una respuesta cuando envío un mensaje?

  • Después de enviar un mensaje, ¿lo recibirán los consumidores?

  • Después de solicitar la instancia de Kafka de Tencent Cloud, ¿cómo configurar varios parámetros?

  • ¿Se perderán mis mensajes al encontrar varios fallos?

  • ¿Recibirá el consumidor varios mensajes? ¿Se perderán los mensajes después de que se reinicie el svr del consumidor?

Estos problemas son normales y siempre habrá problemas de un tipo u otro al contactarlos y usarlos por primera vez. En circunstancias normales, es posible trabajar sin comprender y utilizar varios valores recomendados predeterminados. Pero tenemos que mejorar con gracia nuestra postura (conocimiento) e impulso (conocimiento). Aprenda los principios detrás de él, al menos cuando se encuentre con problemas generales, sea capaz de analizar y tratar los problemas y ser consciente de ellos.

¿Cuándo usar la cola de mensajes?

En pocas palabras, las 3 palabras clave, asincrónica / eliminación de picos / desacoplamiento , se pueden entender como:

  • No me importa después de que lo termine

  • Demasiado trabajo, déjame cuidarlo lentamente

  • No me importa cómo pasó / No me importa cómo lidiar con eso

Tome la siguiente imagen como ejemplo:

Después de que un usuario envía un comentario, después de que se escribe en la base de datos, hay varios pasos lógicos que necesitan capturar el evento de comentario. Es muy engorroso procesar diferentes pasos secuencialmente durante el procesamiento de la interfaz. Podemos notificar cada paso en lotes (asincrónicamente), sin volver a procesar directamente la otra lógica del pago actual (desacoplamiento). Parece ser mucho más refrescante. Además, la cola de mensajes también se puede utilizar como un búfer para almacenar temporalmente los mensajes enviados. Ya no es necesario considerar los escenarios anormales de la lógica de retardo de llamar a cada paso.

Este artículo toma el diseño de confiabilidad en Kafka como ejemplo y la selección de otras colas de mensajes no está involucrada.

Conceptos básicos de Kafka

Antes de responder a las preguntas anteriores del artículo, necesito presentar brevemente varios conceptos. Kafka tiene los siguientes roles topológicos:

  • Consumidor: los consumidores, generalmente existen en forma de API en cada svr comercial

  • Productor: Productor, generalmente en forma de API en cada svr comercial.

  • Agente de Kafka: el servidor en el clúster de kafka, los datos del mensaje en el tema se almacenan en él

El productor envía el mensaje al corredor enviando un push, y el corredor lo almacena. El consumidor usa el modo de extracción para suscribirse y consumir mensajes.

Como se muestra en la figura, Kafka tiene los siguientes roles de la estructura de almacenamiento:

  • Tema: Una colección lógica de mensajes procesados ​​por Kafka, que puede entenderse como una tabla. Escribir sobre diferentes temas significa escribir sobre diferentes tablas.

  • Partición: agrupación física en Tema, un tema se puede dividir en varias particiones, cada partición es una cola ordenada (archivo grande). Cada mensaje de Partition tiene un desplazamiento ordenado.

  • Msg: Mensaje, la unidad básica de comunicación. Cada mensaje tiene solo una copia para diferentes particiones bajo el tema, y ​​hay un desplazamiento único en la partición para el posicionamiento.

  • Réplica: Réplica, copia de seguridad de redundancia de datos de partición, utilizada para lograr la confiabilidad de los datos distribuidos, pero presenta el problema de la coherencia de los datos entre diferentes réplicas, lo que trae un cierto grado de complejidad.

  • Líder / seguidor: la función de réplica, la réplica de líder se utiliza para proporcionar servicios de lectura y escritura para la partición. El seguidor sigue escribiendo mensajes sincrónicamente desde el lado del líder. El estado del mensaje entre ellos se resuelve mediante una estrategia de coherencia.

Formato de almacenamiento Kakfa

Para facilitar una mejor comprensión de la estrategia de coherencia del estado del mensaje en el intermediario, debemos presentar brevemente el formato de almacenamiento de mensajes. Cuando el Productor envía un mensaje al corredor, este elegirá en qué partición almacenar de acuerdo con las reglas de partición. Si las reglas de partición se establecen razonablemente, el mensaje se distribuirá uniformemente a diferentes particiones, logrando así la expansión horizontal.

Pruducer puede pensar en la partición como un gran archivo en serie, y a msg se le asigna un desplazamiento único cuando se almacena. El desplazamiento es un desplazamiento lógico que se utiliza para distinguir cada mensaje.

Como archivo, la partición en sí puede tener múltiples réplicas (líder / seguidor). Se distribuyen múltiples réplicas en diferentes corredores. Si desea responder cómo asegurarse de que los mensajes almacenados y el estado no se pierdan entre los intermediarios, debe responder cómo resolver la coherencia del estado del mensaje de cada réplica entre los intermediarios, incluidos los mensajes que ha enviado el productor, los mensajes que han llegado y los mensajes No se perderá después de la falla del nodo.

Garantía de fiabilidad del mensaje al enviar de forma asincrónica

Volviendo a las preguntas mencionadas al principio del artículo, ¿cómo garantizar la fiabilidad de los mensajes cuando se utiliza la cola de mensajes de Kafka para el envío asincrónico? ¿Cómo responder a las primeras preguntas? Hay tres partes para explicar la garantía de fiabilidad.

Garantía de fiabilidad del productor

Responda la garantía de confiabilidad del productor, es decir, responda:

  1. ¿Hay un ack después de enviar el mensaje?

  2. Después de enviar un mensaje y recibir una confirmación, ¿no se pierde el mensaje?

    Kafka está configurado para especificar la estrategia de confirmación del productor al enviar mensajes:

Request.required.acks=-1 (全量同步确认,强可靠性保证)
Request.required.acks = 1(leader 确认收到, 默认)
Request.required.acks = 0 (不确认,但是吞吐量大)

Si desea configurar kafka como un sistema CP (Consistencia y tolerancia de partición), la configuración debe ser la siguiente:

request.required.acks=-1
min.insync.replicas = ${N/2 + 1}
unclean.leader.election.enable = false

Como se muestra en la figura, en el caso de acks = -1, el nuevo mensaje solo se devolverá al ack después de que todos los seguidores (f1 y f2, f3) en el ISR (f1 y f2, f3) se hayan copiado del líder, independientemente del tipo de falla de la máquina ( Todo o parte), el msg4 escrito no se perderá y el estado del mensaje cumple con los requisitos de consistencia C.

En circunstancias normales, después de copiar todos los seguidores, el líder regresa al reconocimiento del productor.

En condiciones anormales, si se envían algunas copias de datos al líder (f1 y f2 están sincronizados), ¿el líder se bloquea? En este momento, cualquier seguidor puede convertirse en un nuevo líder, el productor devolverá una excepción y el productor volverá a enviar los datos, pero los datos pueden estar duplicados (pero no perdidos). La duplicación de datos no se considera por el momento.

El parámetro min.insync.replicas se utiliza para asegurar el número de seguidores de réplicas en el clúster actual en un estado de sincronización normal. Cuando el valor real es menor que el valor configurado, el clúster deja de servir. Si la configuración es N / 2 + 1, que es la mitad del número, entonces el algoritmo garantizará una fuerte coherencia en esta condición. Cuando no se cumple el número de configuración, el servicio se detiene a expensas de la disponibilidad.

En circunstancias anormales, el líder cuelga y el líder debe ser reelegido de entre los seguidores en este momento. Puede ser f2 o f3.

Si se elige f3 como el nuevo líder, el mensaje puede truncarse porque f3 aún no ha sincronizado los datos de msg4. Kafka usa unclean.leader.election.enable para controlar si f3 puede ser elegido como líder en este caso. El valor predeterminado es verdadero en la versión anterior y falso en una versión determinada, para evitar el truncamiento del mensaje en este caso.

Mediante la cooperación de ack y min.insync.replicas y unclean.leader.election.enable, se garantiza que cuando kafka se configura como un sistema CP, no funciona o, una vez obtenido el ack, el mensaje no se perderá y el estado del mensaje es coherente.

El valor predeterminado del parámetro min.insync.replicas es 1, lo que significa que se cumple una alta disponibilidad, siempre que haya uno en funcionamiento. Pero el estado del corredor de trabajo puede no ser correcto en este momento (puedo imaginar por qué)

Si desea implementar la configuración de Kafka como sistema AP (disponibilidad y tolerancia de partición):

request.required.acks=1
min.insync.replicas = 1
unclean.leader.election.enable = false

Cuando la configuración es acks = 1, es decir, el líder regresa ack después de recibir el mensaje. En este momento, habrá un problema de pérdida de mensaje: si el líder recibe el cuarto mensaje, no se ha sincronizado con el seguidor en este momento, y la máquina líder se cuelga, uno de ellos. Si el seguidor es seleccionado como líder, el cuarto mensaje se pierde. Por supuesto, esto también requiere que el parámetro unclean.leader.election.enable esté configurado como falso para cooperar. Sin embargo, en el caso de que el líder reconozca, la probabilidad de que el seguidor no esté sincronizado aumentará considerablemente.

Mediante la configuración de la estrategia del productor y la configuración de los parámetros generales del clúster Kafka, se puede realizar una configuración razonable de los parámetros de acuerdo con las características de su propio sistema comercial, y se puede encontrar un cierto equilibrio entre el rendimiento de la comunicación y la confiabilidad del mensaje.

Garantía de fiabilidad del corredor

Después de que el mensaje se envía al corredor a través del productor, todavía hay muchos problemas:

  • El líder de partición se escribe correctamente, ¿cuándo se sincronizará el seguidor?

  • Leader escribe con éxito, ¿cuándo pueden los consumidores leer este mensaje?

  • Una vez que el líder escribe correctamente, el líder se reinicia ¿Es normal el estado del mensaje después del reinicio?

  • El líder reinicia, ¿cómo elegir un nuevo líder?

Estos problemas se centran en qué mecanismo utiliza el clúster para garantizar la coherencia del estado del mensaje creado por diferentes réplicas después de que el mensaje cae en el intermediario.

Copia de seguridad y sincronización de mensajes de Kafka

Kafka resuelve el problema de la copia de seguridad de mensajes mediante una estrategia de copia múltiple particionada. Los logotipos HW y LEO corresponden a los conceptos de ISR y OSR, y se utilizan para comparar algoritmos de consenso para resolver el problema de la coherencia de la sincronización de datos.

Las copias múltiples de la partición son las réplicas de la partición mencionada anteriormente, que se distribuyen en máquinas diferentes de la partición, y la redundancia de datos garantiza la conmutación por error automática. El estado de las diferentes copias forma el concepto de ISR y OSR.

  • ISR: la copia del seguidor que la réplica del líder mantiene una cierta cantidad de sincronización, incluida la réplica del líder en sí, denominada réplica en sincronización.

  • AR: Todas las réplicas se denominan colectivamente réplicas asignadas o AR

  • OSR: el seguidor y el líder sincronizan datos con algunos nodos de retardo

ISR es un concepto único en la estrategia de sincronización de Kafka, que es diferente de los algoritmos de consenso como balsa. Raft requiere N / 2 + 1 unidades en el grupo para ser normal. Bajo esta condición, utiliza algoritmos complejos para asegurar que el nuevo líder elegido se ajuste al estado consistente. La estrategia de sincronización de ISR de Kafka, a través de la escalabilidad de la lista de ISR y la actualización de HW & LEO, resuelve el equilibrio entre la coherencia de los mensajes y el rendimiento del rendimiento hasta cierto punto.

ISR expresa el estado de sincronización de los mensajes a través de los conceptos de HW y LEO:

  • HW : Highwater, comúnmente conocido como nivel de agua alto, representa una compensación de mensaje específica (compensación), en una partición, el consumidor solo puede extraer el mensaje antes de la compensación (esta compensación no es un concepto con compensación de consumidor);

  • LEO: LogEndOffset , el desplazamiento del final del registro, utilizado para representar el desplazamiento del siguiente mensaje de escritura en el archivo de registro actual;

  • líder HW : el LEO mínimo de todas las copias del Partititon;

  • seguidor HW: min (propio LEO del seguidor y líder HW);

  • Leader HW = el LEO mínimo de todas las réplicas;

  • Seguidor HW = min (propio LEO del seguidor y líder HW).

Leader no solo guarda su propio HW & LEO sino también la copia remota de HW & LEO

En pocas palabras, cada réplica tiene almacenamiento HW y LEO, y el líder no solo guarda su propio HW y LEO, sino que también guarda el LEO de cada réplica remota. Se utiliza para calcular el valor cuando se actualiza su propio HW. Se puede observar que debido a las características del almacenamiento remoto de LEO, existirá una diferencia numérica a corto plazo entre el LEO real de la copia y el LEO almacenado por el líder, lo que provocará algunos problemas, que se comentarán más adelante.

La estrategia de actualización de HW y LEO es la siguiente:

Proceso de actualización de HW / LEO para una solicitud de escritura completa:

1. Estado inicial

Todos los HW y LEO del líder son 0, el seguidor establece una conexión con el líder y todos los HW y LEO del líder de búsqueda de seguidores y el seguidor son 0

2. Primera búsqueda del seguidor:

El productor envía un mensaje al líder. En este momento, el LEO del líder = 1, el seguidor comienza la búsqueda con su propio HW y LEO (todos son 0), el HW del líder = min (todos los LEO del seguidor) = 0 y el líder registra el LEO del seguidor = 0 ; El seguidor saca un mensaje, con el mensaje y el HW (0) y LEO (1) del líder vuelven a sí mismo, actualiza su propio LEO = 1, actualiza su propio HW = min (el propio LEO (1) y el HW del líder (0) del seguidor ) = 0

3. Segunda recuperación del seguidor:

El seguidor trae su propio HW (0) y LEO (1) para solicitar al líder. En este momento, el HW del líder se actualiza a 1, el LEO del seguidor guardado por el líder se actualiza a 1 y el HW (1) y LEO (1) del líder se devuelve a sí mismo , Actualice su HW y LEO

En este punto, volviendo al problema que acabamos de mencionar, esta estrategia de actualización de HW y LEO tiene un problema obvio, es decir , la actualización de HW del seguidor requiere que se actualice el líder en las 2 recuperaciones del seguidor, y se ha actualizado el HW del líder . Mientras tanto, si el nodo del seguidor y el líder fallan, el HW del seguidor y el HW del líder estarán en un estado inconsistente, lo que provocará más problemas de consistencia. Por ejemplo, el siguiente escenario:

  • Después de que el líder actualiza el HW de la partición, el HW del seguidor aún no se ha actualizado, en este momento el seguidor se reinicia

  • Después de que el seguidor se reinicia, LEO se establece en el valor HW del seguidor anterior (0) y el mensaje se trunca (estado temporal) en este momento.

  • El seguidor vuelve a sincronizar el líder, en este momento el líder está caído, no estará disponible si no es elegido

  • El seguidor es elegido como líder, luego el mensaje 1 se pierde permanentemente

En el caso de Kafka configurado como un sistema AP, dado que min.insync.replicas es 1, la probabilidad de truncamiento del seguidor después del reinicio aumentará enormemente, y la situación puede ser aún peor cuando existen múltiples réplicas. Para solucionar este defecto de actualización del mecanismo de sincronización HW & LEO, la nueva versión de kafka introduce el concepto de Epoch.

Leader epoch consta de dos partes:

  • Época: número de versión. Siempre que cambie el liderazgo de copia, se incrementará el número de versión. El líder del número de versión menor se considera un líder caducado y el poder de líder ya no se puede ejercer.

  • Comience Offset. El desplazamiento del primer mensaje escrito por la copia del líder sobre el valor de Época.

La época del líder (1, 120) indica que el número de versión de este líder es 1, y la posición inicial de la versión es el mensaje número 120. Kafka Broker almacenará en caché los datos de Leader Epoch para cada partición en la memoria y también conservará esta información periódicamente en un archivo de punto de control. Cuando la copia líder escribe un mensaje en el disco, el corredor intentará actualizar esta parte del caché. Si el líder escribe el mensaje por primera vez, el corredor agregará una entrada de la época del líder a la caché; de lo contrario, no la actualizará. De esta forma, cada vez que haya un cambio de Líder, la nueva copia de Líder consultará esta parte de la caché y eliminará el desplazamiento inicial de la Época de Líder correspondiente para evitar la pérdida de datos y la inconsistencia.

El diagrama es el siguiente:

Kafka utiliza el mecanismo de sincronización y la estrategia de optimización de ISR, y utiliza HW y LEO para garantizar que los datos no se pierdan ni se produzcan. La gestión de ISR eventualmente será retroalimentada a Zookeeper, y su implementación y estrategia de elección de líderes no se repetirá.

Estrategia de confiabilidad del consumidor

La estrategia de confiabilidad del consumidor se centra en la semántica de entrega del consumidor, a saber:

  • ¿Cuándo consumir y qué consumir?

  • ¿Se perderá por consumo?

  • ¿Se repetirá el consumo?

Estos escenarios semánticos se pueden configurar a través de algunos parámetros de los consumidores de kafka. En resumen, hay tres escenarios:

1. AutoCommit (como máximo una vez, colgar después de confirmar, en realidad se perderá)

enable.auto.commit = true

auto.commit.interval.ms

El consumidor configurado como arriba devolverá el mensaje correcto al corredor después de recibir el mensaje, pero si la lógica de negocios no se completa e interrumpe, el mensaje no se consume con éxito. Este escenario es adecuado para servicios con requisitos de baja confiabilidad. Entre ellos, auto.commit.interval.ms representa el intervalo de envío automático. Por ejemplo, si está configurado para enviar una vez en 1 s, el reinicio por falla dentro de 1 s se volverá a consumir desde la compensación de consumo actual, y el mensaje que no se ha enviado dentro de 1 s pero que se ha consumido se volverá a consumir.

2. Confirmación manual (al menos una vez, cuelgue antes de confirmar, se repetirá y se perderá el reinicio)

enable.auto.commit = false

En el escenario en el que se configura el envío manual, los desarrolladores comerciales deben enviar manualmente después de que se complete todo el proceso de consumo de mensajes para el procesamiento de la lógica empresarial de mensajes. Si se produce un reinicio cuando el proceso no se procesa, los mensajes no confirmados que se consumieron previamente se consumirán nuevamente, es decir, los mensajes obviamente se entregarán varias veces. La aplicación y la lógica empresarial aquí obviamente se da cuenta del uso en escenarios idempotentes.

Se debe prestar especial atención a la configuración de varios parámetros de la biblioteca sarama en golang:

sarama.offset.initial (oldest, newest)
offsets.retention.minutes

intitial = ancient representa el mensaje más antiguo del tema al que puede acceder el consumidor, que es más grande que la posición de confirmación pero más pequeño que HW. Al mismo tiempo, también se ve afectado por el tiempo de retención de mensajes y el tiempo de retención de desplazamiento en el corredor. No hay garantía de que se consuma el mensaje al principio del tema.

Si se establece en el más reciente, representa el siguiente mensaje para visitar la ubicación de confirmación. Si el consumidor se reinicia y la confirmación automática no se establece en falso, los mensajes anteriores se perderán y ya no se consumirán. Se debe prestar especial atención a los escenarios en los que el entorno empresarial es particularmente inestable o instancias de consumidores no persistentes.

En general, los minutos de retención de compensaciones son 1440 segundos.

3. Exactamente una vez, es difícil, la persistencia y el compromiso de msg son atómicos

La semántica de la entrega de mensajes solo una vez es difícil de lograr. En primer lugar, el mensaje debe consumirse y enviarse para garantizar que no se entregará repetidamente y, en segundo lugar, la lógica empresarial general debe completarse antes del envío del procesamiento del mensaje. En el caso de que Kafka en sí no proporcione una interfaz semántica para este escenario, esto es casi imposible de lograr de manera efectiva. La solución general es realizar el almacenamiento de mensajes atómicos y la lógica empresarial de forma asíncrona y sacar mensajes del almacenamiento para su procesamiento.

Supongo que te gusta

Origin blog.csdn.net/Tencent_TEG/article/details/110015834
Recomendado
Clasificación