RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad

В último artículo Analizamos la agrupación en clústeres RabbitMQ para lograr tolerancia a fallas y alta disponibilidad. Ahora profundicemos en Apache Kafka.

Aquí la unidad de replicación es la partición. Cada tema tiene una o más secciones. Cada sección tiene un líder con o sin seguidores. Al crear un tema, especifica el número de particiones y el coeficiente de replicación. El valor habitual es 3, lo que significa tres réplicas: un líder y dos seguidores.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 1. Cuatro secciones distribuidas entre tres corredores.

Todas las solicitudes de lectura y escritura van al líder. Los seguidores envían periódicamente solicitudes al líder para recibir los mensajes más recientes. Los consumidores nunca recurren a seguidores; estos últimos existen sólo por motivos de redundancia y tolerancia a fallos.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad

Fallo de partición

Cuando un corredor fracasa, los líderes de varias secciones suelen fracasar. En cada uno de ellos, un seguidor de otro nodo se convierte en líder. De hecho, no siempre es así, ya que también influye el factor de sincronización: si hay seguidores sincronizados, y en caso contrario, si se permite cambiar a una réplica no sincronizada. Pero no compliquemos las cosas por ahora.

El corredor 3 abandona la red y se elige un nuevo líder para la sección 2 en el corredor 2.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 2. El corredor 3 muere y su seguidor del corredor 2 es elegido como nuevo líder de la partición 2

Luego el intermediario 1 se marcha y la sección 1 también pierde a su líder, cuyo rol pasa al intermediario 2.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 3. Queda un corredor. Todos los líderes trabajan con un corredor sin redundancia

Cuando el intermediario 1 vuelve a estar en línea, agrega cuatro seguidores, lo que proporciona cierta redundancia a cada partición. Pero todos los líderes permanecieron en el corredor 2.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 4. Los líderes permanecen en el corredor 2

Cuando aparece el intermediario 3, volvemos a tener tres réplicas por partición. Pero todos los líderes todavía están en el corredor 2.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 5. Colocación desequilibrada de los líderes tras la restauración de los corredores 1 y 3

Kafka tiene una herramienta para reequilibrar mejor a los líderes que RabbitMQ. Allí, había que utilizar un complemento o script de terceros que cambiara las políticas para migrar el nodo maestro al reducir la redundancia durante la migración. Además, para colas grandes tuvimos que aceptar la indisponibilidad durante la sincronización.

Kafka tiene el concepto de “réplicas preferidas” para el rol de líder. Cuando se crean particiones de temas, Kafka intenta distribuir los líderes de manera uniforme entre los nodos y marca esos primeros líderes como preferidos. Con el tiempo, debido a reinicios del servidor, fallas y cortes de conectividad, los líderes pueden terminar en otros nodos, como en el caso extremo descrito anteriormente.

Para solucionar este problema, Kafka ofrece dos opciones:

  • Opcion auto.leader.rebalance.enable=verdadero permite que el nodo controlador reasigne automáticamente los líderes a las réplicas preferidas y así restaurar la distribución uniforme.
  • El administrador puede ejecutar el script. kafka-replica-preferred-election.sh para reasignación manual.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 6. Réplicas después del reequilibrio

Esta fue una versión simplificada del fracaso, pero la realidad es más compleja, aunque aquí no hay nada demasiado complicado. Todo se reduce a réplicas sincronizadas (réplicas In-Sync, ISR).

Réplicas sincronizadas (ISR)

Un ISR es un conjunto de réplicas de una partición que se considera "sincronizada" (in-sync). Hay un líder, pero puede que no haya seguidores. Un seguidor se considera sincronizado si ha hecho copias exactas de todos los mensajes del líder antes de que expire el intervalo. réplica.lag.time.max.ms.

Un seguidor se elimina del conjunto ISR si:

  • no realizó una solicitud para seleccionar para el intervalo réplica.lag.time.max.ms (dado por muerto)
  • no logró actualizar durante el intervalo réplica.lag.time.max.ms (considerado lento)

Los seguidores realizan solicitudes de muestreo en el intervalo. réplica.fetch.wait.max.ms, cuyo valor predeterminado es 500 ms.

Para explicar claramente el propósito de ISR, debemos observar las confirmaciones del productor y algunos escenarios de falla. Los productores pueden elegir cuándo el corredor envía la confirmación:

  • acks=0, la confirmación no se envía
  • acks=1, la confirmación se envía después de que el líder haya escrito un mensaje en su registro local
  • acks=all, la confirmación se envía después de que todas las réplicas en el ISR hayan escrito el mensaje en los registros locales

En terminología de Kafka, si el ISR ha guardado un mensaje, está "confirmado". Acks=all es la opción más segura, pero también agrega demora adicional. Veamos dos ejemplos de fallas y cómo las diferentes opciones de "acks" interactúan con el concepto ISR.

Confirmaciones = 1 e ISR

En este ejemplo, veremos que si el líder no espera a que se guarden todos los mensajes de todos los seguidores, es posible que se pierdan datos si el líder falla. La navegación hacia un seguidor no sincronizado se puede habilitar o deshabilitar configurando habilitación.de.elección.de.líder.impuro.

En este ejemplo, el fabricante tiene el valor acks=1. La sección se distribuye entre los tres corredores. El corredor 3 está detrás, se sincronizó con el líder hace ocho segundos y ahora tiene 7456 mensajes de retraso. El corredor 1 estaba sólo un segundo por detrás. Nuestro productor envía un mensaje y recibe rápidamente un respuesta, sin la sobrecarga de seguidores lentos o muertos que el líder no está esperando.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 7. ISR con tres réplicas

El corredor 2 falla y el productor recibe un error de conexión. Después de que el liderazgo pasa al intermediario 1, perdemos 123 mensajes. El seguidor del corredor 1 era parte del ISR, pero no estaba completamente sincronizado con el líder cuando cayó.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 8. Los mensajes se pierden cuando falla

En configuración bootstrap.servidores El fabricante tiene varios corredores en la lista y puede preguntar a otro corredor quién es el nuevo líder de sección. Luego establece una conexión con el intermediario 1 y continúa enviando mensajes.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 9. El envío de mensajes se reanuda después de un breve descanso.

El corredor 3 está aún más atrás. Realiza solicitudes de recuperación pero no se puede sincronizar. Esto puede deberse a una conexión de red lenta entre los corredores, un problema de almacenamiento, etc. Se elimina del ISR. Ahora el ISR consta de una réplica: ¡el líder! El fabricante continúa enviando mensajes y recibiendo confirmaciones.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 10. El seguidor del corredor 3 se elimina del ISR

¡El corredor 1 cae y el rol de liderazgo pasa al corredor 3 con la pérdida de 15286 mensajes! El fabricante recibe un mensaje de error de conexión. La transición a un líder fuera del ISR sólo fue posible debido al entorno unclean.leader.election.enable=verdadero. Si está instalado en false, entonces la transición no ocurriría y todas las solicitudes de lectura y escritura serían rechazadas. En este caso, esperamos a que el broker 1 regrese con sus datos intactos en la réplica, que volverá a tomar el liderazgo.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 11. El corredor 1 cae. Cuando ocurre una falla, se pierde una gran cantidad de mensajes

El productor establece conexión con el último corredor y ve que ahora es el líder de la sección. Comienza a enviar mensajes al corredor 3.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 12. Después de un breve descanso, los mensajes se envían nuevamente a la sección 0

Vimos que, aparte de breves interrupciones para establecer nuevas conexiones y buscar un nuevo líder, el fabricante enviaba mensajes constantemente. Esta configuración garantiza la disponibilidad a expensas de la coherencia (seguridad de los datos). Kafka perdió miles de mensajes pero siguió aceptando nuevos escritos.

Confirmaciones = todas e ISR

Repitamos este escenario nuevamente, pero con acks=todos. El corredor 3 tiene una latencia promedio de cuatro segundos. El fabricante envía un mensaje con acks=todos, y ahora no recibe una respuesta rápida. El líder espera a que todas las réplicas del ISR guarden el mensaje.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 13. ISR con tres réplicas. Uno es lento, lo que provoca retrasos en la grabación.

Después de cuatro segundos de retraso adicional, el corredor 2 envía un acuse de recibo. Todas las réplicas ahora están completamente actualizadas.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 14. Todas las réplicas guardan mensajes y envían acuse de recibo.

El corredor 3 ahora se queda aún más atrás y es eliminado del ISR. La latencia se reduce significativamente porque no quedan réplicas lentas en el ISR. El corredor 2 ahora espera solo al corredor 1 y tiene un retraso promedio de 500 ms.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 15. La réplica del corredor 3 se elimina del ISR.

Luego el intermediario 2 cae y el liderazgo pasa al intermediario 1 sin pérdida de mensajes.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 16. El corredor 2 cae

El fabricante encuentra un nuevo líder y comienza a enviarle mensajes. ¡La latencia se reduce aún más porque el ISR ahora consta de una réplica! Por lo tanto la opción acks=todos no añade redundancia.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 17. La réplica del corredor 1 toma la delantera sin perder mensajes

Luego, el corredor 1 falla y el liderazgo pasa al corredor 3 con una pérdida de 14238 mensajes.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 18. El corredor 1 muere y la transición de liderazgo con una configuración poco limpia genera una gran pérdida de datos

No pudimos instalar la opción. habilitación.de.elección.de.líder.impuro en significado verdadero. Por defecto es igual false. Ajustes acks=todos с unclean.leader.election.enable=verdadero proporciona accesibilidad con cierta seguridad de datos adicional. Pero como puedes ver, aún podemos perder mensajes.

Pero ¿y si queremos aumentar la seguridad de los datos? Puedes poner unclean.leader.election.enable = falso, pero esto no necesariamente nos protegerá de la pérdida de datos. Si el líder cayó y se llevó los datos consigo, entonces los mensajes aún se pierden y además se pierde la disponibilidad hasta que el administrador restablezca la situación.

Es mejor asegurarse de que todos los mensajes sean redundantes y, de lo contrario, descartar la grabación. Entonces, al menos desde el punto de vista del corredor, la pérdida de datos sólo es posible en caso de dos o más fallos simultáneos.

Acks=todos, min.insync.replicas e ISR

Con configuración de tema min.insync.réplicas Estamos aumentando el nivel de seguridad de los datos. Repasemos de nuevo la última parte del escenario anterior, pero esta vez con min.insync.réplicas=2.

Entonces, el corredor 2 tiene una réplica del líder y el seguidor del corredor 3 se elimina del ISR.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 19. ISR de dos réplicas.

El broker 2 cae y el liderazgo pasa al broker 1 sin pérdida de mensajes. Pero ahora el ISR consta de una sola réplica. Este no cumple con el número mínimo para recibir registros y por lo tanto el broker responde al intento de escritura con un error. NoEnoughReplicas.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 20. La cantidad de ISR es uno menor que el especificado en min.insync.replicas

Esta configuración sacrifica la disponibilidad en aras de la coherencia. Antes de reconocer un mensaje, nos aseguramos de que esté escrito en al menos dos réplicas. Esto le da mucha más confianza al fabricante. Aquí, la pérdida de mensajes solo es posible si dos réplicas fallan simultáneamente en un intervalo corto hasta que el mensaje se replica a un seguidor adicional, lo cual es poco probable. Pero si eres muy paranoico, puedes establecer el factor de replicación en 5 y min.insync.réplicas por 3. ¡Aquí deben caer tres corredores al mismo tiempo para perder el récord! Por supuesto, usted paga por esta confiabilidad en latencia adicional.

Cuando la accesibilidad es necesaria para la seguridad de los datos

Como en caso con RabbitMQ, a veces la accesibilidad es necesaria para la seguridad de los datos. Esto es en lo que debes pensar:

  • ¿Puede el editor simplemente devolver un error y hacer que el servicio ascendente o el usuario vuelvan a intentarlo más tarde?
  • ¿Puede el editor guardar el mensaje localmente o en una base de datos para volver a intentarlo más tarde?

Si la respuesta es no, optimizar la disponibilidad mejora la seguridad de los datos. Perderás menos datos si eliges disponibilidad en lugar de no grabar. Por tanto, todo se reduce a encontrar un equilibrio y la decisión depende de la situación concreta.

El significado de ISR

La suite ISR le permite elegir el equilibrio óptimo entre seguridad de datos y latencia. Por ejemplo, asegurar la disponibilidad en caso de fallo de la mayoría de réplicas, minimizando el impacto de réplicas muertas o lentas en términos de latencia.

Nosotros mismos elegimos el significado. réplica.lag.time.max.ms según sus necesidades. Esencialmente, este parámetro significa cuánto retraso estamos dispuestos a aceptar cuando acks=todos. El valor predeterminado es diez segundos. Si esto es demasiado largo para usted, puede reducirlo. Entonces la frecuencia de cambios en el ISR aumentará, ya que se eliminarán y agregarán seguidores con más frecuencia.

RabbitMQ es simplemente un conjunto de espejos que deben replicarse. Los espejos lentos introducen latencia adicional y los espejos inactivos pueden esperar hasta que los paquetes que verifican la disponibilidad de cada nodo (tick de red) respondan. ISR es una forma interesante de evitar estos problemas de latencia. Pero corremos el riesgo de perder redundancia ya que el ISR sólo puede reducirse al líder. Para evitar este riesgo, utilice la configuración min.insync.réplicas.

Garantía de conexión del cliente

En la configuración bootstrap.servidores El productor y el consumidor pueden especificar varios intermediarios para conectar a los clientes. La idea es que cuando un nodo cae, quedan varios de repuesto con los que el cliente puede abrir una conexión. Estos no son necesariamente líderes de sección, sino simplemente un trampolín para la carga inicial. El cliente puede preguntarles qué nodo aloja el líder de la partición de lectura/escritura.

En RabbitMQ, los clientes pueden conectarse a cualquier nodo y el enrutamiento interno envía la solicitud a donde debe ir. Esto significa que puede instalar un equilibrador de carga delante de RabbitMQ. Kafka requiere que los clientes se conecten al nodo que aloja el líder de partición correspondiente. En tal situación, no puede instalar un equilibrador de carga. Lista bootstrap.servidores Es fundamental que los clientes puedan acceder y encontrar los nodos correctos después de una falla.

Arquitectura del consenso de Kafka

Hasta ahora, no hemos considerado cómo el grupo se entera de la caída del corredor y cómo se elige un nuevo líder. Para comprender cómo funciona Kafka con particiones de red, primero debe comprender la arquitectura de consenso.

Cada clúster de Kafka se implementa junto con un clúster de Zookeeper, que es un servicio de consenso distribuido que permite al sistema llegar a un consenso sobre un estado determinado, priorizando la coherencia sobre la disponibilidad. Se requiere el consentimiento de la mayoría de los nodos de Zookeeper para aprobar las operaciones de lectura y escritura.

Zookeeper almacena el estado del clúster:

  • Lista de temas, secciones, configuración, réplicas líderes actuales, réplicas preferidas.
  • Miembros del cluster. Cada corredor hace ping al clúster Zookeeper. Si no recibe un ping dentro de un período de tiempo específico, Zookeeper registra al corredor como no disponible.
  • Seleccionar los nodos principal y de repuesto para el controlador.

El nodo controlador es uno de los intermediarios de Kafka que se encarga de elegir los líderes de réplica. Zookeeper envía notificaciones al controlador sobre la membresía del clúster y los cambios de temas, y el controlador debe actuar en función de estos cambios.

Por ejemplo, tomemos un tema nuevo con diez particiones y un factor de replicación de 3. El controlador debe elegir un líder para cada partición, tratando de distribuir de manera óptima los líderes entre los brokers.

Para cada controlador de sección:

  • actualiza información en Zookeeper sobre ISR y líder;
  • Envía un LeaderAndISRCommand a cada corredor que aloja una réplica de esta partición, informando a los corredores sobre el ISR y el líder.

Cuando un corredor con un líder cae, Zookeeper envía una notificación al controlador y este elige un nuevo líder. Nuevamente, el controlador primero actualiza Zookeeper y luego envía un comando a cada corredor notificándoles el cambio de liderazgo.

Cada líder es responsable de reclutar ISR. Ajustes réplica.lag.time.max.ms determina quién entrará allí. Cuando el ISR cambia, el líder transmite nueva información a Zookeeper.

Zookeeper siempre está informado de cualquier cambio para que, en caso de falla, la administración pase sin problemas a un nuevo líder.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 21. El consenso de Kafka

Protocolo de replicación

Comprender los detalles de la replicación le ayuda a comprender mejor los posibles escenarios de pérdida de datos.

Consultas de muestreo, desplazamiento final de registro (LEO) y marca de nivel máximo (HW)

Consideramos que los seguidores envían periódicamente solicitudes de búsqueda al líder. El intervalo predeterminado es 500 ms. Esto se diferencia de RabbitMQ en que en RabbitMQ la replicación no la inicia el espejo de la cola sino el maestro. El maestro empuja los cambios a los espejos.

El líder y todos los seguidores guardan la etiqueta Log End Offset (LEO) y Highwater (HW). La marca LEO almacena el desplazamiento del último mensaje en la réplica local y el HW almacena el desplazamiento de la última confirmación. Recuerde que para el estado de confirmación, el mensaje debe persistir en todas las réplicas ISR. Esto significa que LEO suele estar ligeramente por delante de HW.

Cuando el líder recibe un mensaje, lo almacena localmente. El seguidor realiza una solicitud de recuperación transmitiendo su LEO. Luego, el líder envía un lote de mensajes a partir de este LEO y también transmite el HW actual. Cuando el líder recibe información de que todas las réplicas han almacenado el mensaje en el desplazamiento dado, mueve la marca HW. Sólo el líder puede mover el HW, por lo que todos los seguidores sabrán el valor actual en las respuestas a su solicitud. Esto significa que los seguidores pueden quedarse atrás del líder tanto en el mensaje como en el conocimiento del hardware. Los consumidores reciben mensajes solo hasta el HW actual.

Tenga en cuenta que "persistente" significa escrito en la memoria, no en el disco. Para mejorar el rendimiento, Kafka se sincroniza con el disco en un intervalo específico. RabbitMQ también tiene ese intervalo, pero enviará un acuse de recibo al editor solo después de que el maestro y todos los espejos hayan escrito el mensaje en el disco. Los desarrolladores de Kafka, por razones de rendimiento, decidieron enviar un acuse de recibo tan pronto como el mensaje se escribe en la memoria. Kafka apuesta a que la redundancia compensa el riesgo de almacenar brevemente mensajes reconocidos sólo en la memoria.

Fracaso del líder

Cuando un líder cae, Zookeeper notifica al controlador y éste selecciona una nueva réplica del líder. El nuevo líder establece una nueva marca HW según su LEO. Luego, los seguidores reciben información sobre el nuevo líder. Dependiendo de la versión de Kafka, el seguidor elegirá uno de dos escenarios:

  1. Truncará el registro local a un HW conocido y enviará una solicitud al nuevo líder para recibir mensajes después de esta marca.
  2. Enviará una solicitud al líder para averiguar el HW en el momento en que fue elegido líder y luego truncará el registro a este desplazamiento. Luego comenzará a realizar solicitudes de recuperación periódicas a partir de este desplazamiento.

Es posible que un seguidor necesite truncar el registro por los siguientes motivos:

  • Cuando un líder falla, el primer seguidor del conjunto ISR registrado con Zookeeper gana la elección y se convierte en líder. Todos los seguidores de ISR, aunque se consideran "sincronizados", es posible que no hayan recibido copias de todos los mensajes del exlíder. Es muy posible que el seguidor destacado no tenga la copia más actualizada. Kafka se asegura de que no haya divergencia entre las réplicas. Así, para evitar discrepancias, cada seguidor debe truncar su registro al valor HW del nuevo líder en el momento de su elección. Esta es otra razón por la cual establecer acks=todos tan importante para la coherencia.
  • Los mensajes se escriben periódicamente en el disco. Si todos los nodos del clúster fallan al mismo tiempo, se almacenarán en los discos réplicas con diferentes compensaciones. Es posible que cuando los corredores vuelvan a estar en línea, el nuevo líder elegido esté detrás de sus seguidores porque fue guardado en el disco antes que los demás.

Reunión con el cluster

Al volver a unirse al clúster, las réplicas hacen lo mismo que cuando falla un líder: verifican la réplica del líder y truncan su registro a su HW (en el momento de la elección). En comparación, RabbitMQ trata igualmente los nodos reunidos como completamente nuevos. En ambos casos, el corredor descarta cualquier estado existente. Si se utiliza la sincronización automática, entonces el maestro debe replicar absolutamente todo el contenido actual en el nuevo espejo en un método de "dejar que todo el mundo espere". El maestro no acepta ninguna operación de lectura o escritura durante esta operación. Este enfoque crea problemas en colas grandes.

Kafka es un registro distribuido y, en general, almacena más mensajes que una cola RabbitMQ, donde los datos se eliminan de la cola después de leerlos. Las colas activas deberían seguir siendo relativamente pequeñas. Pero Kafka es un registro con su propia política de retención, que puede fijar un periodo de días o semanas. El enfoque de bloqueo de colas y sincronización completa es absolutamente inaceptable para un registro distribuido. En cambio, los seguidores de Kafka simplemente truncan su registro al HW del líder (en el momento de su elección) si su copia está por delante del líder. En el caso más probable, cuando el seguidor está atrasado, simplemente comienza a realizar solicitudes de recuperación comenzando con su LEO actual.

Los seguidores nuevos o reincorporados comienzan fuera del ISR y no participan en confirmaciones. Simplemente trabajan junto al grupo, recibiendo mensajes lo más rápido que pueden hasta que alcanzan al líder e ingresan al ISR. No hay ningún bloqueo ni necesidad de desechar todos sus datos.

Pérdida de conectividad

Kafka tiene más componentes que RabbitMQ, por lo que tiene un conjunto de comportamientos más complejo cuando el clúster se desconecta. Pero Kafka fue diseñado originalmente para clusters, por lo que las soluciones están muy bien pensadas.

A continuación se muestran varios escenarios de falla de conectividad:

  • Escenario 1: el seguidor no ve al líder, pero aún ve al cuidador del zoológico.
  • Escenario 2: el líder no ve ningún seguidor, pero aún ve a Zookeeper.
  • Escenario 3: el seguidor ve al líder, pero no al cuidador del zoológico.
  • Escenario 4: el líder ve a los seguidores, pero no al cuidador del zoológico.
  • Escenario 5: el seguidor está completamente separado de los otros nodos de Kafka y de Zookeeper.
  • Escenario 6: el líder está completamente separado de los otros nodos de Kafka y de Zookeeper.
  • Escenario 7: el nodo controlador de Kafka no puede ver otro nodo de Kafka.
  • Escenario 8: el controlador Kafka no ve Zookeeper.

Cada escenario tiene su propio comportamiento.

Escenario 1: el seguidor no ve al líder, pero aún ve al cuidador del zoológico

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 22. Escenario 1: ISR de tres réplicas

La falla de conectividad separa al corredor 3 de los corredores 1 y 2, pero no de Zookeeper. El corredor 3 ya no puede enviar solicitudes de recuperación. Después de que el tiempo haya pasado réplica.lag.time.max.ms se elimina del ISR y no participa en las confirmaciones de mensajes. Una vez que se restablezca la conectividad, reanudará las solicitudes de búsqueda y se unirá al ISR cuando alcance al líder. Zookeeper seguirá recibiendo pings y asumirá que el corredor está sano y salvo.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 23. Escenario 1: el intermediario se elimina del ISR si no se recibe ninguna solicitud de recuperación dentro del intervalo replica.lag.time.max.ms

No hay suspensión de nodos ni cerebro dividido como en RabbitMQ. En cambio, se reduce la redundancia.

Escenario 2: el líder no ve ningún seguidor, pero aún ve a Zookeeper

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 24. Escenario 2. Líder y dos seguidores

Una falla en la conectividad de la red separa al líder de los seguidores, pero el corredor aún puede ver a Zookeeper. Como en el primer escenario, el ISR se reduce, pero esta vez solo al líder, ya que todos los seguidores dejan de enviar solicitudes de recuperación. Una vez más, no existe una división lógica. En cambio, hay una pérdida de redundancia para los mensajes nuevos hasta que se restablezca la conectividad. Zookeeper continúa recibiendo pings y cree que el corredor está vivo y coleando.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 25. Escenario 2. El ISR se ha reducido solo al líder

Escenario 3. El seguidor ve al líder, pero no al cuidador del zoológico.

El seguidor está separado de Zookeeper, pero no del intermediario con el líder. Como resultado, el seguidor continúa realizando solicitudes de recuperación y siendo miembro del ISR. Zookeeper ya no recibe pings y registra una falla del corredor, pero como solo es un seguidor, no hay consecuencias después de la recuperación.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 26. Escenario 3: el seguidor continúa enviando solicitudes de recuperación al líder

Escenario 4. El líder ve seguidores, pero no ve a Zookeeper

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 27. Escenario 4. Líder y dos seguidores

El líder está separado de Zookeeper, pero no de los intermediarios con seguidores.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 28. Escenario 4: Líder aislado de Zookeeper

Después de un tiempo, Zookeeper registrará una falla del corredor y notificará al controlador al respecto. Elegirá un nuevo líder entre sus seguidores. Sin embargo, el líder original seguirá pensando que es el líder y seguirá aceptando entradas de ataques = 1. Los seguidores ya no le envían solicitudes de recuperación, por lo que las considerará muertas e intentará reducir el ISR a sí mismo. Pero como no tiene conexión con Zookeeper, no podrá hacer esto y en ese momento se negará a aceptar más entradas.

mensajes acks=todos no recibirá una confirmación porque el ISR primero activa todas las réplicas y los mensajes no les llegan. Cuando el líder original intente eliminarlos del ISR, no podrá hacerlo y dejará de aceptar mensajes.

Los clientes pronto notan el cambio de líder y comienzan a enviar registros al nuevo servidor. Una vez que se restaura la red, el líder original ve que ya no es un líder y trunca su registro al valor de HW que tenía el nuevo líder en el momento del fallo para evitar la divergencia del registro. Luego comenzará a enviar solicitudes de recuperación al nuevo líder. Todos los registros del líder original que no se replican en el nuevo líder se pierden. Es decir, los mensajes que no fueron reconocidos por el líder original en esos pocos segundos en los que dos líderes estaban trabajando se perderán.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 29. Escenario 4. El líder del corredor 1 se convierte en seguidor después de que se restablece la red.

Escenario 5: el seguidor está completamente separado de los otros nodos de Kafka y de Zookeeper

El seguidor está completamente aislado de los otros nodos de Kafka y de Zookeeper. Simplemente se retira del ISR hasta que se restablece la red y luego se pone al día con los demás.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 30. Escenario 5: el seguidor aislado se elimina de ISR

Escenario 6: el líder está completamente separado de los otros nodos de Kafka y de Zookeeper

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 31. Escenario 6. Líder y dos seguidores

El líder está completamente aislado de sus seguidores, el controlador y el cuidador del zoológico. Durante un breve periodo seguirá aceptando inscripciones de ataques = 1.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 32. Escenario 6: Aislar al líder de otros nodos Kafka y Zookeeper

No haber recibido solicitudes después del vencimiento réplica.lag.time.max.ms, intentará reducir el ISR a sí mismo, pero no podrá hacerlo porque no hay comunicación con Zookeeper, entonces dejará de aceptar escrituras.

Mientras tanto, Zookeeper marcará al corredor aislado como muerto y el controlador elegirá un nuevo líder.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 33. Escenario 6. Dos líderes

El líder original puede aceptar entradas durante unos segundos, pero luego deja de aceptar mensajes. Los clientes se actualizan cada 60 segundos con los metadatos más recientes. Se les informará del cambio de líder y comenzarán a enviar entradas al nuevo líder.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 34. Escenario 6: Los fabricantes cambian a un nuevo líder

Se perderán todas las entradas confirmadas realizadas por el líder original desde la pérdida de conectividad. Una vez que se restablezca la red, el líder original descubrirá a través de Zookeeper que ya no es el líder. Luego truncará su registro al HW del nuevo líder en el momento de la elección y comenzará a enviar solicitudes como seguidor.

RabbitMQ vs Kafka: tolerancia a fallos y alta disponibilidad
Arroz. 35. Escenario 6: el líder original se convierte en seguidor después de que se restablece la conectividad de la red

En esta situación, la separación lógica puede ocurrir por un período corto, pero sólo si ataques = 1 и min.insync.réplicas también 1. La separación lógica finaliza automáticamente después de que se restablece la red, cuando el líder original se da cuenta de que ya no es el líder, o cuando todos los clientes se dan cuenta de que el líder ha cambiado y comienzan a escribirle al nuevo líder, lo que ocurra primero. En cualquier caso, algunos mensajes se perderán, pero sólo con ataques = 1.

Existe otra variante de este escenario en la que, justo antes de que la red se dividiera, los seguidores se quedaron atrás y el líder comprimió el ISR solo para él. Luego queda aislado debido a la pérdida de conectividad. Se elige un nuevo líder, pero el líder original continúa aceptando entradas, incluso acks=todos, porque no hay nadie más en ISR excepto él. Estos registros se perderán una vez que se restablezca la red. La única manera de evitar esta opción es min.insync.réplicas = 2.

Escenario 7: el nodo controlador de Kafka no puede ver otro nodo de Kafka

En general, una vez que se pierde la conexión con un nodo Kafka, el controlador no podrá transmitirle ninguna información de cambio de líder. En el peor de los casos, esto conducirá a una separación lógica a corto plazo, como en el escenario 6. La mayoría de las veces, el corredor simplemente no se convertirá en candidato para el liderazgo si éste fracasa.

Escenario 8: el controlador Kafka no ve Zookeeper

Zookeeper no recibirá un ping del controlador caído y seleccionará un nuevo nodo Kafka como controlador. El controlador original puede seguir presentándose como tal, pero no recibe notificaciones de Zookeeper, por lo que no tendrá ninguna tarea que realizar. Una vez que se restablezca la red, se dará cuenta de que ya no es un controlador, sino que se ha convertido en un nodo Kafka normal.

Conclusiones de los escenarios.

Vemos que la pérdida de conectividad del seguidor no resulta en la pérdida de mensajes, sino que simplemente reduce temporalmente la redundancia hasta que se restablezca la red. Esto, por supuesto, puede provocar la pérdida de datos si se pierden uno o más nodos.

Si el líder se separa de Zookeeper debido a una pérdida de conectividad, esto podría resultar en la pérdida de mensajes. ataques = 1. La falta de comunicación con Zookeeper provoca una breve división lógica con los dos líderes. Este problema se resuelve con el parámetro acks=todos.

Parámetro min.insync.réplicas en dos o más réplicas proporciona una seguridad adicional de que dichos escenarios a corto plazo no darán lugar a la pérdida de mensajes como en el Escenario 6.

Resumen de mensajes perdidos

Enumeremos todas las formas en que puede perder datos en Kafka:

  • Cualquier falla del líder si los mensajes se confirmaron usando ataques = 1
  • Cualquier transición de liderazgo sucia, es decir, a un seguidor fuera del ISR, incluso con acks=todos
  • Aislar al líder de Zookeeper si los mensajes se confirmaron usando ataques = 1
  • Aislamiento total del líder que ya ha reducido el grupo ISR a él mismo. Todos los mensajes se perderán, incluso acks=todos. Esto sólo es cierto si min.insync.réplicas=1.
  • Fallos simultáneos de todos los nodos de partición. Debido a que los mensajes se confirman desde la memoria, es posible que algunos aún no se hayan escrito en el disco. Después de reiniciar los servidores, es posible que falten algunos mensajes.

Las transiciones de liderazgo impuras se pueden evitar prohibiéndolas o garantizando al menos dos despidos. La configuración más duradera es una combinación acks=todos и min.insync.réplicas más 1.

Comparación directa de la confiabilidad de RabbitMQ y Kafka

Para garantizar confiabilidad y alta disponibilidad, ambas plataformas implementan un sistema de replicación primario y secundario. Sin embargo, RabbitMQ tiene un talón de Aquiles. Al volver a conectarse después de una falla, los nodos descartan sus datos y se bloquea la sincronización. Este doble golpe pone en duda la longevidad de las grandes colas en RabbitMQ. Tendrá que aceptar una redundancia reducida o tiempos de bloqueo prolongados. La reducción de la redundancia aumenta el riesgo de pérdida masiva de datos. Pero si las colas son pequeñas, entonces, en aras de la redundancia, se pueden solucionar períodos cortos de indisponibilidad (unos pocos segundos) mediante intentos repetidos de conexión.

Kafka no tiene este problema. Descarta datos sólo desde el punto de divergencia entre el líder y el seguidor. Todos los datos compartidos se guardan. Además, la replicación no bloquea el sistema. El líder continúa aceptando publicaciones mientras el nuevo seguidor se pone al día, por lo que para los desarrolladores, unirse o volver a unirse al clúster se convierte en una tarea trivial. Por supuesto, todavía existen problemas como el ancho de banda de la red durante la replicación. Si agrega varios seguidores al mismo tiempo, es posible que encuentre un límite de ancho de banda.

RabbitMQ es superior a Kafka en confiabilidad cuando fallan varios servidores en un clúster al mismo tiempo. Como ya hemos dicho, RabbitMQ envía una confirmación al editor solo después de que el maestro y todos los espejos escriben el mensaje en el disco. Pero esto añade latencia adicional por dos motivos:

  • fsync cada pocos cientos de milisegundos
  • El fallo del mirror sólo se puede notar después de que haya expirado la vida útil de los paquetes que comprueban la disponibilidad de cada nodo (net tick). Si el espejo se desacelera o cae, esto agrega un retraso.

La apuesta de Kafka es que si un mensaje se almacena en varios nodos, puede reconocer los mensajes tan pronto como lleguen a la memoria. Debido a esto, existe el riesgo de perder mensajes de cualquier tipo (incluso acks=todos, min.insync.réplicas=2) en caso de fallo simultáneo.

En general, Kafka muestra un mejor rendimiento del software y está diseñado desde cero para clústeres. El número de seguidores se puede aumentar a 11 si es necesario para mayor confiabilidad. Factor de replicación 5 y número mínimo de réplicas en sincronización min.insync.réplicas=3 hará que la pérdida de mensajes sea un evento muy raro. Si su infraestructura puede admitir esta tasa de replicación y nivel de redundancia, puede elegir esta opción.

La agrupación en clústeres RabbitMQ es buena para colas pequeñas. Pero incluso las colas pequeñas pueden crecer rápidamente cuando hay mucho tráfico. Una vez que las colas aumentan, tendrá que tomar decisiones difíciles entre disponibilidad y confiabilidad. La agrupación en clústeres de RabbitMQ es más adecuada para situaciones atípicas en las que los beneficios de la flexibilidad de RabbitMQ superan cualquier desventaja de su agrupación.

Un antídoto a la vulnerabilidad de RabbitMQ a las colas grandes es dividirlas en muchas colas más pequeñas. Si no necesita realizar el pedido completo de toda la cola, sino solo los mensajes relevantes (por ejemplo, mensajes de un cliente específico), o no solicita nada en absoluto, entonces esta opción es aceptable: mire mi proyecto Reequilibrador para dividir la cola (el proyecto aún se encuentra en una etapa temprana).

Finalmente, no se olvide de una serie de errores en los mecanismos de agrupación y replicación tanto de RabbitMQ como de Kafka. Con el tiempo, los sistemas se han vuelto más maduros y estables, ¡pero ningún mensaje estará 100% a salvo de pérdidas! Además, ¡se producen accidentes a gran escala en los centros de datos!

Si me perdí algo, cometí un error o no estás de acuerdo con alguno de los puntos, no dudes en escribir un comentario o contactarme.

A menudo me preguntan: "¿Qué elegir, Kafka o RabbitMQ?", "¿Qué plataforma es mejor?". La verdad es que realmente depende de tu situación, experiencia actual, etc. Dudo en dar mi opinión porque sería demasiado simplificador recomendar una plataforma para todos los casos de uso y posibles limitaciones. Escribí esta serie de artículos para que puedas formarte tu propia opinión.

Quiero decir que ambos sistemas son líderes en este ámbito. Puede que sea un poco parcial porque, según mi experiencia con proyectos, tiendo a valorar cosas como el orden garantizado de los mensajes y la confiabilidad.

Veo otras tecnologías que carecen de esta confiabilidad y orden garantizado, luego miro RabbitMQ y Kafka y me doy cuenta del increíble valor de ambos sistemas.

Fuente: habr.com

Añadir un comentario