RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade

В último artigo analisamos o cluster RabbitMQ para tolerância a falhas e alta disponibilidade. Agora vamos nos aprofundar no Apache Kafka.

Aqui a unidade de replicação é a partição. Cada tópico possui uma ou mais seções. Cada seção tem um líder com ou sem seguidores. Ao criar um tópico, você especifica o número de partições e o coeficiente de replicação. O valor usual é 3, o que significa três réplicas: um líder e dois seguidores.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 1. Quatro seções são distribuídas entre três corretores

Todas as solicitações de leitura e gravação vão para o líder. Os seguidores enviam periodicamente solicitações ao líder para receber as últimas mensagens. Os consumidores nunca recorrem aos seguidores; estes existem apenas para redundância e tolerância a falhas.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade

Falha na partição

Quando um corretor falha, os líderes de diversas seções geralmente falham. Em cada um deles, um seguidor de outro nó torna-se o líder. Na verdade, nem sempre é assim, pois o fator de sincronização também influencia: se existem seguidores sincronizados e, caso contrário, se é permitida a mudança para uma réplica não sincronizada. Mas não vamos complicar as coisas por enquanto.

O corretor 3 sai da rede e um novo líder é eleito para a seção 2 do corretor 2.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 2. O corretor 3 morre e seu seguidor no corretor 2 é eleito o novo líder da partição 2

Então o corretor 1 sai e a seção 1 também perde seu líder, cuja função passa para o corretor 2.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 3. Resta um corretor. Todos os líderes estão em um corretor com redundância zero

Quando o corretor 1 volta a ficar online, ele adiciona quatro seguidores, proporcionando alguma redundância a cada partição. Mas todos os líderes ainda permaneceram no corretor 2.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 4. Os líderes permanecem na corretora 2

Quando o corretor 3 aparece, voltamos a ter três réplicas por partição. Mas todos os líderes ainda estão no corretor 2.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 5. Colocação desequilibrada de líderes após a restauração das corretoras 1 e 3

Kafka possui uma ferramenta para melhor reequilíbrio de líderes do que o RabbitMQ. Lá, você tinha que usar um plugin ou script de terceiros que alterasse as políticas de migração do nó mestre, reduzindo a redundância durante a migração. Além disso, para filas grandes tivemos que aceitar a indisponibilidade durante a sincronização.

Kafka tem o conceito de “réplicas preferenciais” para o papel de líder. Quando as partições de tópicos são criadas, o Kafka tenta distribuir os líderes uniformemente entre os nós e marca os primeiros líderes como preferenciais. Com o tempo, devido a reinicializações de servidores, falhas e falhas de conectividade, os líderes podem acabar em outros nós, como no caso extremo descrito acima.

Para corrigir isso, Kafka oferece duas opções:

  • Opção auto.leader.rebalance.enable=true permite que o nó controlador reatribua automaticamente os líderes de volta às réplicas preferenciais e, assim, restaure a distribuição uniforme.
  • O administrador pode executar o script kafka-preferred-replica-election.sh para reatribuição manual.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 6. Réplicas após rebalanceamento

Esta foi uma versão simplificada da falha, mas a realidade é mais complexa, embora não haja nada muito complicado aqui. Tudo se resume a réplicas sincronizadas (Réplicas In-Sync, ISR).

Réplicas Sincronizadas (ISR)

Um ISR é um conjunto de réplicas de uma partição considerada “sincronizada” (em sincronia). Existe um líder, mas pode não haver seguidores. Um seguidor é considerado sincronizado se tiver feito cópias exatas de todas as mensagens do líder antes que o intervalo expire réplica.lag.time.max.ms.

Um seguidor é removido do conjunto ISR se:

  • não fez uma solicitação para selecionar o intervalo réplica.lag.time.max.ms (morte presumida)
  • não conseguiu atualizar durante o intervalo réplica.lag.time.max.ms (considerado lento)

Seguidores fazem pedidos de amostragem no intervalo réplica.fetch.wait.max.ms, cujo padrão é 500 ms.

Para explicar claramente o propósito do ISR, precisamos analisar as confirmações do produtor e alguns cenários de falha. Os produtores podem escolher quando o corretor envia a confirmação:

  • acks=0, a confirmação não é enviada
  • acks=1, a confirmação é enviada depois que o líder escreve uma mensagem em seu log local
  • acks=all, a confirmação é enviada após todas as réplicas no ISR terem gravado a mensagem nos logs locais

Na terminologia Kafka, se o ISR salvou uma mensagem, ela está “confirmada”. Acks=all é a opção mais segura, mas também adiciona atraso adicional. Vejamos dois exemplos de falha e como as diferentes opções de 'acks' interagem com o conceito ISR.

Acks = 1 e ISR

Neste exemplo, veremos que se o líder não esperar que todas as mensagens de todos os seguidores sejam salvas, então a perda de dados será possível se o líder falhar. A navegação para um seguidor não sincronizado pode ser ativada ou desativada configurando impuro.líder.eleição.enable.

Neste exemplo, o fabricante possui o valor acks=1. A seção é distribuída por todos os três corretores. O corretor 3 está atrás, sincronizou com o líder há oito segundos e agora está 7456 mensagens atrás. O corretor 1 estava apenas um segundo atrás. Nosso produtor envia uma mensagem e recebe rapidamente um retorno, sem a sobrecarga de seguidores lentos ou mortos que o líder não está esperando.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 7. ISR com três réplicas

O corretor 2 falha e o produtor recebe um erro de conexão. Após a liderança passar para o corretor 1, perdemos 123 mensagens. O seguidor na corretora 1 fazia parte do ISR, mas não estava totalmente sincronizado com o líder quando este caiu.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 8. As mensagens são perdidas quando ele trava

Na configuração servidores bootstrap O fabricante possui vários corretores listados e pode perguntar a outro corretor quem é o novo líder da seção. Em seguida, estabelece uma conexão com o corretor 1 e continua enviando mensagens.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 9. O envio de mensagens é retomado após um breve intervalo

O corretor 3 está ainda mais atrás. Faz solicitações de busca, mas não consegue sincronizar. Isso pode ser devido à conexão de rede lenta entre corretores, problema de armazenamento, etc. Ele foi removido do ISR. Agora o ISR consiste em uma réplica - o líder! O fabricante continua enviando mensagens e recebendo confirmações.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 10. Seguidor na corretora 3 é removido do ISR

O corretor 1 cai e a função de liderança vai para o corretor 3 com a perda de 15286 mensagens! O fabricante recebe uma mensagem de erro de conexão. A transição para um líder fora do ISR só foi possível devido ao cenário impuro.leader.election.enable=true. Se estiver instalado em falso, a transição não ocorreria e todas as solicitações de leitura e gravação seriam rejeitadas. Neste caso, esperamos que o corretor 1 retorne com seus dados intactos na réplica, que assumirá novamente a liderança.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 11. Corretor 1 cai. Quando ocorre uma falha, um grande número de mensagens é perdido

O produtor estabelece ligação com o último corretor e vê que ele agora é o líder da seção. Ele começa a enviar mensagens para o corretor 3.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 12. Após um breve intervalo, as mensagens são enviadas novamente para a seção 0

Vimos que, além de pequenas interrupções para estabelecer novas conexões e buscar um novo líder, a fabricante enviava mensagens constantemente. Esta configuração garante a disponibilidade em detrimento da consistência (segurança dos dados). Kafka perdeu milhares de mensagens, mas continuou aceitando novas escritas.

Acks = todos e ISR

Vamos repetir esse cenário novamente, mas com acks = todos. O Broker 3 tem uma latência média de quatro segundos. O fabricante envia uma mensagem com acks = todos, e agora não recebe uma resposta rápida. O líder espera que a mensagem seja salva por todas as réplicas no ISR.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 13. ISR com três réplicas. Um é lento, resultando em atrasos na gravação

Após quatro segundos de atraso adicional, o corretor 2 envia uma confirmação. Todas as réplicas agora estão totalmente atualizadas.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 14. Todas as réplicas salvam mensagens e enviam confirmação

O corretor 3 agora fica ainda mais para trás e é removido do ISR. A latência é significativamente reduzida porque não há mais réplicas lentas no ISR. O corretor 2 agora espera apenas pelo corretor 1 e ele tem um atraso médio de 500 ms.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 15. A réplica no corretor 3 é removida do ISR

Então o corretor 2 cai e a liderança passa para o corretor 1 sem perda de mensagens.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 16. Corretor 2 cai

O fabricante encontra um novo líder e começa a enviar mensagens para ele. A latência é ainda mais reduzida porque o ISR agora consiste em uma réplica! Portanto a opção acks = todos não adiciona redundância.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 17. A réplica no corretor 1 assume a liderança sem perder mensagens

Então o corretor 1 trava e o lead vai para o corretor 3 com uma perda de 14238 mensagens!

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 18. O corretor 1 morre e a transição de liderança com ambiente sujo resulta em extensa perda de dados

Não foi possível instalar a opção impuro.líder.eleição.enable em significado verdadeiro. Por padrão é igual falso. Configurações acks = todos с impuro.leader.election.enable=true fornece acessibilidade com alguma segurança de dados adicional. Mas como você pode ver, ainda podemos perder mensagens.

Mas e se quisermos aumentar a segurança dos dados? Você pode colocar impuro.leader.election.enable = falso, mas isso não nos protegerá necessariamente da perda de dados. Se o líder se apegou e levou os dados consigo, as mensagens ainda serão perdidas, além da disponibilidade ser perdida até que o administrador restaure a situação.

É melhor garantir que todas as mensagens sejam redundantes e, caso contrário, descartar a gravação. Então, pelo menos do ponto de vista da corretora, a perda de dados só é possível no caso de duas ou mais falhas simultâneas.

Acks = todos, min.insync.replicas e ISR

Com configuração de tópico min.insync.replicas Estamos aumentando o nível de segurança dos dados. Vamos repassar a última parte do cenário anterior, mas desta vez com min.insync.replicas=2.

Portanto, o corretor 2 tem uma réplica líder e o seguidor do corretor 3 é removido do ISR.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 19. ISR de duas réplicas

O corretor 2 cai e a liderança passa para o corretor 1 sem perda de mensagens. Mas agora o ISR consiste em apenas uma réplica. Isso não atende ao número mínimo para receber registros e, portanto, o corretor responde à tentativa de gravação com um erro NotEnoughReplicas.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 20. O número de ISRs é menor que o especificado em min.insync.replicas

Essa configuração sacrifica a disponibilidade em prol da consistência. Antes de confirmar uma mensagem, garantimos que ela seja gravada em pelo menos duas réplicas. Isso dá ao fabricante muito mais confiança. Aqui, a perda de mensagem só é possível se duas réplicas falharem simultaneamente em um curto intervalo até que a mensagem seja replicada para um seguidor adicional, o que é improvável. Mas se você for super paranóico, poderá definir o fator de replicação para 5 e min.insync.replicas por 3. Aqui três corretores devem cair ao mesmo tempo para perder o recorde! Claro, você paga por essa confiabilidade com latência adicional.

Quando a acessibilidade é necessária para a segurança dos dados

Como em caso com RabbitMQ, às vezes a acessibilidade é necessária para a segurança dos dados. Aqui está o que você precisa pensar:

  • O editor pode simplesmente retornar um erro e fazer com que o serviço ou usuário upstream tente novamente mais tarde?
  • O editor pode salvar a mensagem localmente ou em um banco de dados para tentar novamente mais tarde?

Se a resposta for não, otimizar a disponibilidade melhora a segurança dos dados. Você perderá menos dados se escolher a disponibilidade em vez de não gravar. Assim, tudo se resume a encontrar um equilíbrio, e a decisão depende da situação específica.

O significado de ISR

O conjunto ISR permite escolher o equilíbrio ideal entre segurança de dados e latência. Por exemplo, garantir a disponibilidade em caso de falha da maioria das réplicas, minimizando o impacto de réplicas mortas ou lentas em termos de latência.

Nós mesmos escolhemos o significado réplica.lag.time.max.ms de acordo com suas necessidades. Essencialmente, este parâmetro significa quanto atraso estamos dispostos a aceitar quando acks = todos. O valor padrão é dez segundos. Se for muito longo para você, você pode reduzi-lo. Então a frequência das alterações no ISR aumentará, pois os seguidores serão removidos e adicionados com mais frequência.

RabbitMQ é simplesmente um conjunto de espelhos que precisam ser replicados. Os espelhos lentos introduzem latência adicional e os espelhos mortos podem esperar até que os pacotes que verificam a disponibilidade de cada nó (net tick) respondam. O ISR é uma forma interessante de evitar esses problemas de latência. Mas corremos o risco de perder redundância, uma vez que o ISR só pode encolher até se tornar o líder. Para evitar esse risco, use a configuração min.insync.replicas.

Garantia de conexão do cliente

Nas configurações servidores bootstrap produtor e consumidor podem especificar vários corretores para conectar clientes. A ideia é que quando um nó cair, restem vários sobressalentes com os quais o cliente possa abrir uma conexão. Estes não são necessariamente líderes de seção, mas simplesmente um trampolim para o carregamento inicial. O cliente pode perguntar qual nó hospeda o líder da partição de leitura/gravação.

No RabbitMQ, os clientes podem se conectar a qualquer nó e o roteamento interno envia a solicitação para onde ela precisa ir. Isso significa que você pode instalar um balanceador de carga na frente do RabbitMQ. Kafka exige que os clientes se conectem ao nó que hospeda o líder da partição correspondente. Nessa situação, não é possível instalar um balanceador de carga. Lista servidores bootstrap É fundamental que os clientes possam acessar e encontrar os nós corretos após uma falha.

Arquitetura de consenso Kafka

Até agora, não consideramos como o cluster fica sabendo da queda do corretor e como um novo líder é eleito. Para entender como o Kafka funciona com partições de rede, primeiro você precisa entender a arquitetura de consenso.

Cada cluster Kafka é implantado junto com um cluster Zookeeper, que é um serviço de consenso distribuído que permite ao sistema chegar a um consenso sobre um determinado estado, priorizando a consistência em vez da disponibilidade. O consentimento da maioria dos nós Zookeeper é necessário para aprovar operações de leitura e gravação.

Zookeeper armazena o estado do cluster:

  • Lista de tópicos, seções, configuração, réplicas líderes atuais, réplicas preferenciais.
  • Membros do cluster. Cada corretor faz ping no cluster Zookeeper. Se não receber um ping dentro de um período de tempo especificado, o Zookeeper registrará o corretor como indisponível.
  • Selecionando os nós principais e sobressalentes para o controlador.

O nó controlador é um dos corretores Kafka responsável por eleger os líderes das réplicas. O Zookeeper envia notificações ao controlador sobre membros do cluster e alterações de tópico, e o controlador deve agir de acordo com essas alterações.

Por exemplo, vamos pegar um novo tópico com dez partições e um fator de replicação de 3. O controlador deve eleger um líder para cada partição, tentando distribuir de forma otimizada os líderes entre os corretores.

Para cada controlador de seção:

  • atualiza informações no Zookeeper sobre ISR e líder;
  • Envia um LeaderAndISRCommand para cada corretor que hospeda uma réplica desta partição, informando os corretores sobre o ISR e o líder.

Quando um corretor com líder cai, o Zookeeper envia uma notificação ao controlador e elege um novo líder. Novamente, o controlador primeiro atualiza o Zookeeper e depois envia um comando para cada corretor notificando-os sobre a mudança de liderança.

Cada líder é responsável por recrutar ISRs. Configurações réplica.lag.time.max.ms determina quem entrará lá. Quando o ISR muda, o líder transmite novas informações ao Zookeeper.

O Zookeeper é sempre informado sobre quaisquer alterações para que, em caso de falha, a gestão transite sem problemas para um novo líder.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 21. Consenso de Kafka

Protocolo de replicação

Compreender os detalhes da replicação ajuda a compreender melhor os possíveis cenários de perda de dados.

Consultas de amostragem, Log End Offset (LEO) e Highwater Mark (HW)

Consideramos que os seguidores enviam periodicamente solicitações de busca ao líder. O intervalo padrão é 500ms. Isso difere do RabbitMQ porque no RabbitMQ a replicação não é iniciada pelo espelho da fila, mas pelo mestre. O mestre envia alterações para os espelhos.

O líder e todos os seguidores salvam o Log End Offset (LEO) e o rótulo Highwater (HW). A marca LEO armazena o deslocamento da última mensagem na réplica local e o HW armazena o deslocamento do último commit. Lembre-se de que para o status de confirmação, a mensagem deve persistir em todas as réplicas ISR. Isso significa que o LEO geralmente está um pouco à frente do HW.

Quando o líder recebe uma mensagem, ele a armazena localmente. O seguidor faz uma solicitação de busca transmitindo seu LEO. O líder então envia um lote de mensagens a partir deste LEO e também transmite o HW atual. Quando o líder recebe a informação de que todas as réplicas armazenaram a mensagem em um determinado deslocamento, ele move a marca HW. Somente o líder pode movimentar o HW, e assim todos os seguidores saberão o valor atual nas respostas à sua solicitação. Isso significa que os seguidores podem ficar atrás do líder tanto em termos de mensagem quanto de conhecimento de hardware. Os consumidores recebem mensagens apenas até o HW atual.

Observe que "persistido" significa gravado na memória, não no disco. Para desempenho, o Kafka sincroniza com o disco em um intervalo específico. O RabbitMQ também possui esse intervalo, mas enviará uma confirmação ao editor somente depois que o mestre e todos os espelhos tiverem gravado a mensagem no disco. Os desenvolvedores do Kafka, por questões de desempenho, decidiram enviar uma confirmação assim que a mensagem for gravada na memória. Kafka aposta que a redundância compensa o risco de armazenar brevemente mensagens reconhecidas apenas na memória.

Falha do líder

Quando um líder cai, o Zookeeper notifica o controlador e seleciona uma nova réplica do líder. O novo líder define uma nova marca de HW de acordo com seu LEO. Os seguidores então recebem informações sobre o novo líder. Dependendo da versão do Kafka, o seguidor escolherá um dos dois cenários:

  1. Ele truncará o log local para um HW conhecido e enviará uma solicitação ao novo líder para mensagens após esta marca.
  2. Enviará uma solicitação ao líder para descobrir o HW no momento em que foi eleito líder e, em seguida, truncará o log para esse deslocamento. Em seguida, ele começará a fazer solicitações de busca periódicas a partir desse deslocamento.

Um seguidor pode precisar truncar o log pelos seguintes motivos:

  • Quando um líder falha, o primeiro seguidor no conjunto ISR registrado no Zookeeper vence a eleição e se torna o líder. Todos os seguidores do ISR, embora considerados “sincronizados”, podem não ter recebido cópias de todas as mensagens do antigo líder. É perfeitamente possível que o seguidor em destaque não tenha a cópia mais atualizada. Kafka garante que não haja divergência entre as réplicas. Assim, para evitar discrepâncias, cada seguidor deve truncar seu log para o valor de HW do novo líder no momento de sua eleição. Esta é outra razão pela qual definir acks = todos tão importante para a consistência.
  • As mensagens são gravadas periodicamente no disco. Se todos os nós do cluster falharem ao mesmo tempo, as réplicas com deslocamentos diferentes serão armazenadas nos discos. É possível que, quando os corretores voltarem a ficar online, o novo líder eleito esteja atrás de seus seguidores porque foi salvo em disco antes dos outros.

Reunião com o cluster

Ao ingressar novamente no cluster, as réplicas fazem o mesmo que quando um líder falha: elas verificam a réplica do líder e truncam seu log para seu HW (no momento da eleição). Em comparação, o RabbitMQ trata igualmente os nós reunidos como completamente novos. Em ambos os casos, o corretor descarta qualquer estado existente. Se a sincronização automática for usada, então o mestre deverá replicar absolutamente todo o conteúdo atual para o novo espelho em um método “deixe o mundo inteiro esperar”. O mestre não aceita nenhuma operação de leitura ou gravação durante esta operação. Essa abordagem cria problemas em filas grandes.

Kafka é um log distribuído e em geral armazena mais mensagens do que uma fila RabbitMQ, onde os dados são removidos da fila após serem lidos. As filas ativas devem permanecer relativamente pequenas. Mas Kafka é um log com política de retenção própria, que pode definir um período de dias ou semanas. A abordagem de bloqueio de fila e sincronização completa é absolutamente inaceitável para um log distribuído. Em vez disso, os seguidores de Kafka simplesmente truncam seu log para o HW do líder (no momento de sua eleição) se sua cópia estiver à frente do líder. No caso mais provável, quando o seguidor está atrasado, ele simplesmente começa a fazer solicitações de busca começando com seu LEO atual.

Seguidores novos ou reingressados ​​começam fora do ISR e não participam de commits. Eles simplesmente trabalham junto com o grupo, recebendo mensagens o mais rápido que podem até alcançarem o líder e entrarem no ISR. Não há aprisionamento e nem necessidade de jogar fora todos os seus dados.

Perda de conectividade

O Kafka possui mais componentes que o RabbitMQ, portanto, possui um conjunto mais complexo de comportamentos quando o cluster é desconectado. Mas o Kafka foi originalmente projetado para clusters, então as soluções são muito bem pensadas.

Abaixo estão vários cenários de falha de conectividade:

  • Cenário 1: O seguidor não vê o líder, mas ainda vê o Zookeeper.
  • Cenário 2: O líder não vê nenhum seguidor, mas ainda vê o Zookeeper.
  • Cenário 3: O seguidor vê o líder, mas não vê o Zookeeper.
  • Cenário 4: O líder vê os seguidores, mas não vê o Zookeeper.
  • Cenário 5: O seguidor está completamente separado dos outros nós Kafka e do Zookeeper.
  • Cenário 6: O líder está completamente separado dos outros nós Kafka e do Zookeeper.
  • Cenário 7: O nó controlador Kafka não pode ver outro nó Kafka.
  • Cenário 8: O controlador Kafka não vê o Zookeeper.

Cada cenário tem seu próprio comportamento.

Cenário 1: Seguidor não vê o líder, mas ainda vê o Zookeeper

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 22. Cenário 1: ISR de três réplicas

A falha de conectividade separa o corretor 3 dos corretores 1 e 2, mas não do Zookeeper. O Broker 3 não pode mais enviar solicitações de busca. Depois que o tempo passou réplica.lag.time.max.ms ele é removido do ISR e não participa de confirmações de mensagens. Assim que a conectividade for restaurada, ele retomará as solicitações de busca e se juntará ao ISR quando alcançar o líder. O Zookeeper continuará recebendo pings e presumirá que o corretor está vivo e bem.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 23. Cenário 1: O corretor é removido do ISR se nenhuma solicitação de busca for recebida dentro do intervalo replica.lag.time.max.ms

Não há divisão de cérebro ou suspensão de nó como no RabbitMQ. Em vez disso, a redundância é reduzida.

Cenário 2: O líder não vê nenhum seguidor, mas ainda vê o Zookeeper

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 24. Cenário 2. Líder e dois seguidores

Uma falha na conectividade da rede separa o líder dos seguidores, mas o corretor ainda pode ver o Zookeeper. Como no primeiro cenário, o ISR diminui, mas desta vez apenas para o líder, pois todos os seguidores param de enviar solicitações de busca. Novamente, não há divisão lógica. Em vez disso, há uma perda de redundância para novas mensagens até que a conectividade seja restaurada. O Zookeeper continua recebendo pings e acredita que o corretor está vivo e bem.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 25. Cenário 2. ISR encolheu apenas para o líder

Cenário 3. O seguidor vê o líder, mas não vê o Zookeeper

O seguidor é separado do Zookeeper, mas não do corretor com o líder. Como resultado, o seguidor continua a fazer solicitações de busca e a ser membro do ISR. O Zookeeper não recebe mais pings e registra travamento do corretor, mas como é apenas um seguidor, não há consequências após a recuperação.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 26. Cenário 3: O seguidor continua a enviar solicitações de busca ao líder

Cenário 4. O líder vê os seguidores, mas não vê o Zookeeper

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 27. Cenário 4. Líder e dois seguidores

O líder está separado do Zookeeper, mas não dos corretores com seguidores.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 28. Cenário 4: Líder isolado do Zookeeper

Depois de algum tempo, o Zookeeper registrará uma falha do corretor e notificará o controlador sobre isso. Ele escolherá um novo líder entre seus seguidores. No entanto, o líder original continuará a pensar que é o líder e continuará a aceitar inscrições de acks = 1. Os seguidores não estão mais enviando solicitações de busca, então ele irá considerá-los mortos e tentar reduzir o ISR para si mesmo. Mas como não tem ligação ao Zookeeper, não será capaz de fazer isso e, nesse momento, recusar-se-á a aceitar quaisquer outras entradas.

mensagens acks = todos não receberá uma confirmação porque o ISR primeiro ativa todas as réplicas e as mensagens não chegam até elas. Quando o líder original tentar removê-los do ISR, não conseguirá fazê-lo e deixará de aceitar qualquer mensagem.

Os clientes logo percebem a mudança de líder e começam a enviar registros para o novo servidor. Uma vez restaurada a rede, o líder original vê que não é mais um líder e trunca seu log para o valor de HW que o novo líder tinha no momento da falha para evitar divergência de log. Em seguida, ele começará a enviar solicitações de busca ao novo líder. Todos os registros do líder original que não forem replicados para o novo líder serão perdidos. Ou seja, as mensagens que não foram reconhecidas pelo líder original naqueles poucos segundos em que dois líderes estavam trabalhando serão perdidas.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 29. Cenário 4. O líder no corretor 1 torna-se um seguidor após a restauração da rede

Cenário 5: o seguidor está completamente separado dos outros nós Kafka e do Zookeeper

O seguidor está completamente isolado dos outros nós Kafka e do Zookeeper. Ele simplesmente se retira do ISR até que a rede seja restaurada e então alcança os outros.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 30. Cenário 5: Seguidor isolado é removido do ISR

Cenário 6: O líder está completamente separado dos outros nós Kafka e do Zookeeper

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 31. Cenário 6. Líder e dois seguidores

O líder está completamente isolado de seus seguidores, do controlador e do Zookeeper. Por um curto período continuará a aceitar inscrições de acks = 1.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 32. Cenário 6: Isolando o líder de outros nós Kafka e Zookeeper

Não tendo recebido solicitações após a expiração réplica.lag.time.max.ms, ele tentará reduzir o ISR para si mesmo, mas não será capaz de fazê-lo porque não há comunicação com o Zookeeper, então ele irá parar de aceitar gravações.

Enquanto isso, o Zookeeper marcará o corretor isolado como morto e o controlador elegerá um novo líder.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 33. Cenário 6. Dois líderes

O líder original pode aceitar entradas por alguns segundos, mas depois para de aceitar qualquer mensagem. Os clientes são atualizados a cada 60 segundos com os metadados mais recentes. Eles serão informados da mudança de líder e começarão a enviar inscrições para o novo líder.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 34. Cenário 6: Os fabricantes mudam para um novo líder

Todas as entradas confirmadas feitas pelo líder original desde a perda de conectividade serão perdidas. Assim que a rede for restaurada, o líder original descobrirá através do Zookeeper que não é mais o líder. Em seguida, ele truncará seu log para o HW do novo líder no momento da eleição e começará a enviar solicitações como seguidor.

RabbitMQ vs Kafka: tolerância a falhas e alta disponibilidade
Arroz. 35. Cenário 6: O líder original torna-se um seguidor após a restauração da conectividade de rede

Nesta situação, a separação lógica pode ocorrer por um curto período, mas apenas se acks = 1 и min.insync.replicas também 1. A separação lógica termina automaticamente após a restauração da rede, quando o líder original percebe que não é mais o líder ou quando todos os clientes percebem que o líder mudou e começam a escrever para o novo líder - o que acontecer primeiro. Em qualquer caso, algumas mensagens serão perdidas, mas apenas com acks = 1.

Há outra variante deste cenário em que, pouco antes da divisão da rede, os seguidores ficaram para trás e o líder comprimiu o ISR apenas para si mesmo. Em seguida, fica isolado devido à perda de conectividade. Um novo líder é eleito, mas o líder original continua a aceitar inscrições, mesmo acks = todos, porque não há mais ninguém no ISR além dele. Esses registros serão perdidos assim que a rede for restaurada. A única maneira de evitar esta opção é min.insync.replicas = 2.

Cenário 7: o nó do controlador Kafka não consegue ver outro nó Kafka

Em geral, uma vez perdida a conexão com um nó Kafka, o controlador não será capaz de transmitir a ele nenhuma informação de mudança de líder. Na pior das hipóteses, isto levará a uma separação lógica de curto prazo, como no cenário 6. Na maioria das vezes, o corretor simplesmente não se tornará um candidato à liderança se esta falhar.

Cenário 8: o controlador Kafka não vê o Zookeeper

O Zookeeper não receberá um ping do controlador caído e selecionará um novo nó Kafka como controlador. O controlador original pode continuar a se apresentar como tal, mas não recebe notificações do Zookeeper, portanto não terá nenhuma tarefa a realizar. Assim que a rede for restaurada, ele perceberá que não é mais um controlador, mas se tornou um nó Kafka normal.

Conclusões dos cenários

Vemos que a perda de conectividade do seguidor não resulta em perda de mensagem, mas simplesmente reduz temporariamente a redundância até que a rede seja restaurada. É claro que isso pode levar à perda de dados se um ou mais nós forem perdidos.

Se o líder se separar do Zookeeper devido a uma perda de conectividade, isso poderá resultar na perda de mensagens do acks = 1. A falta de comunicação com o Zookeeper causa uma breve divisão lógica entre os dois líderes. Este problema é resolvido pelo parâmetro acks = todos.

Parâmetro min.insync.replicas em duas ou mais réplicas fornece garantia adicional de que tais cenários de curto prazo não resultarão em mensagens perdidas como no Cenário 6.

Resumo de mensagens perdidas

Vamos listar todas as maneiras pelas quais você pode perder dados no Kafka:

  • Qualquer falha do líder se as mensagens forem confirmadas usando acks = 1
  • Qualquer transição impura de liderança, isto é, para um seguidor fora da ISR, mesmo com acks = todos
  • Isolando o líder do Zookeeper se as mensagens foram confirmadas usando acks = 1
  • Isolamento completo do líder que já reduziu o grupo ISR a si mesmo. Todas as mensagens serão perdidas, mesmo acks = todos. Isto só é verdade se min.insync.replicas=1.
  • Falhas simultâneas de todos os nós de partição. Como as mensagens são confirmadas na memória, algumas podem ainda não ter sido gravadas no disco. Após a reinicialização dos servidores, algumas mensagens podem desaparecer.

As transições impuras de liderança podem ser evitadas proibindo-as ou assegurando pelo menos duas redundâncias. A configuração mais durável é uma combinação acks = todos и min.insync.replicas mais de 1.

Comparação direta da confiabilidade do RabbitMQ e Kafka

Para garantir confiabilidade e alta disponibilidade, ambas as plataformas implementam um sistema de replicação primário e secundário. No entanto, RabbitMQ tem calcanhar de Aquiles. Ao reconectar após uma falha, os nós descartam seus dados e a sincronização é bloqueada. Esse golpe duplo questiona a longevidade de grandes filas no RabbitMQ. Você terá que aceitar redundância reduzida ou longos tempos de bloqueio. A redução da redundância aumenta o risco de perda massiva de dados. Mas se as filas forem pequenas, então, por uma questão de redundância, curtos períodos de indisponibilidade (alguns segundos) podem ser resolvidos usando repetidas tentativas de conexão.

Kafka não tem esse problema. Descarta dados apenas do ponto de divergência entre o líder e o seguidor. Todos os dados compartilhados são salvos. Além disso, a replicação não bloqueia o sistema. O líder continua aceitando postagens enquanto o novo seguidor o alcança, portanto, para devops, ingressar ou reingressar no cluster torna-se uma tarefa trivial. Claro, ainda existem problemas como largura de banda da rede durante a replicação. Se você adicionar vários seguidores ao mesmo tempo, poderá encontrar um limite de largura de banda.

RabbitMQ é superior ao Kafka em confiabilidade quando vários servidores em um cluster falham ao mesmo tempo. Como já dissemos, o RabbitMQ envia uma confirmação ao editor somente após a mensagem ser gravada no disco pelo mestre e por todos os espelhos. Mas isso adiciona latência adicional por dois motivos:

  • fsync a cada algumas centenas de milissegundos
  • A falha do espelho só pode ser percebida após expirar o tempo de vida dos pacotes que verificam a disponibilidade de cada nó (net tick). Se o espelho desacelerar ou cair, isso adicionará um atraso.

A aposta de Kafka é que, se uma mensagem for armazenada em vários nós, ela poderá reconhecer as mensagens assim que elas atingirem a memória. Por isso, existe o risco de perder mensagens de qualquer tipo (mesmo acks = todos, min.insync.replicas=2) em caso de falha simultânea.

No geral, o Kafka apresenta melhor desempenho de software e foi projetado desde o início para clusters. O número de seguidores pode ser aumentado para 11, se necessário, para maior confiabilidade. Fator de replicação 5 e número mínimo de réplicas em sincronização min.insync.replicas=3 tornará a perda de mensagens um evento muito raro. Se a sua infraestrutura puder suportar essa taxa de replicação e nível de redundância, você poderá escolher esta opção.

O clustering RabbitMQ é bom para filas pequenas. Mas mesmo as filas pequenas podem crescer rapidamente quando há tráfego intenso. Quando as filas ficarem grandes, você terá que fazer escolhas difíceis entre disponibilidade e confiabilidade. O clustering RabbitMQ é mais adequado para situações atípicas em que os benefícios da flexibilidade do RabbitMQ superam quaisquer desvantagens de seu clustering.

Um antídoto para a vulnerabilidade do RabbitMQ a filas grandes é dividi-las em muitas filas menores. Se você não precisa de uma ordenação completa de toda a fila, mas apenas das mensagens relevantes (por exemplo, mensagens de um cliente específico), ou não pede nada, então esta opção é aceitável: veja meu projeto Rebalanceador para dividir a fila (o projeto ainda está em fase inicial).

Por fim, não se esqueça de vários bugs nos mecanismos de clustering e replicação do RabbitMQ e do Kafka. Com o tempo, os sistemas tornaram-se mais maduros e estáveis, mas nenhuma mensagem estará 100% protegida contra perda! Além disso, ocorrem acidentes em grande escala em data centers!

Se eu perdi alguma coisa, cometi um erro ou você discorda de algum dos pontos, fique à vontade para escrever um comentário ou entrar em contato comigo.

Muitas vezes me perguntam: “Qual escolher, Kafka ou RabbitMQ?”, “Qual plataforma é melhor?”. A verdade é que isso realmente depende da sua situação, experiência atual, etc. Hesito em dar minha opinião porque seria uma simplificação exagerada recomendar uma plataforma para todos os casos de uso e possíveis limitações. Escrevi esta série de artigos para que você possa formar sua própria opinião.

Quero dizer que ambos os sistemas são líderes nesta área. Posso ser um pouco tendencioso porque, pela minha experiência com projetos, tendo a valorizar coisas como ordem garantida de mensagens e confiabilidade.

Vejo outras tecnologias que carecem dessa confiabilidade e ordenação garantida, então olho para RabbitMQ e Kafka e percebo o valor incrível de ambos os sistemas.

Fonte: habr.com

Adicionar um comentário