{"id":52541,"date":"2019-11-11T00:00:00","date_gmt":"2019-11-10T21:00:00","guid":{"rendered":"https:\/\/prohoster.info\/blog\/blog_prohoster\/rabbitmq-protiv-kafka-otkazoustojchivost-i-vysokaya-dostupnost"},"modified":"2020-02-18T14:00:17","modified_gmt":"2020-02-18T11:00:17","slug":"rabbitmq-protiv-kafka-otkazoustojchivost-i-vysokaya-dostupnost","status":"publish","type":"post","link":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/rabbitmq-protiv-kafka-otkazoustojchivost-i-vysokaya-dostupnost","title":{"rendered":"RabbitMQ vs Kafka: Fault Tolerance and High Availability","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/6557ce69c2b3070622feca8b3c228b09.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEm <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/itsumma\/blog\/471858\/\">artigo anterior<\/a><\/noindex> N\u00f3s examinamos a clusteriza\u00e7\u00e3o do RabbitMQ para garantir resili\u00eancia e alta disponibilidade. Agora, vamos nos aprofundar no Apache Kafka.<\/p>\n<p>Aqui, a unidade de replica\u00e7\u00e3o \u00e9 a parti\u00e7\u00e3o (partition). Cada t\u00f3pico possui uma ou mais parti\u00e7\u00f5es. Em cada parti\u00e7\u00e3o, h\u00e1 um l\u00edder com seguidores ou sem eles. Ao criar um t\u00f3pico, especifica-se o n\u00famero de parti\u00e7\u00f5es e o fator de replica\u00e7\u00e3o. O valor usual \u00e9 3, o que significa tr\u00eas r\u00e9plicas: um l\u00edder e dois seguidores.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/36deb6d506223c2ee2ec147d5c215789.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figura 1. Quatro parti\u00e7\u00f5es distribu\u00eddas entre tr\u00eas corretores<\/i><\/p>\n<p>Todas as solicita\u00e7\u00f5es de leitura e escrita v\u00e3o para o l\u00edder. Os seguidores periodicamente enviam requisi\u00e7\u00f5es ao l\u00edder para obter as \u00faltimas mensagens. Os consumidores nunca se conectam aos seguidores, que existem apenas para redund\u00e2ncia e resili\u00eancia.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/715c51d75cb45863cfad4b37e81b9a9a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h1>Falha da parti\u00e7\u00e3o<\/h1>\n<p>\nQuando um corretor falha, frequentemente os l\u00edderes de v\u00e1rias parti\u00e7\u00f5es tamb\u00e9m ficam fora de opera\u00e7\u00e3o. Em cada uma delas, o l\u00edder se torna um seguidor de outro n\u00f3. Na verdade, isso nem sempre acontece, pois outro fator influencia: se existem seguidores sincronizados e, caso contr\u00e1rio, se a mudan\u00e7a para uma r\u00e9plica n\u00e3o sincronizada \u00e9 permitida. Mas n\u00e3o vamos complicar por enquanto.<\/p>\n<p>O corretor 3 sai da rede \u2014 e para a parti\u00e7\u00e3o 2, um novo l\u00edder \u00e9 eleito no corretor 2.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/b8cfce64cf6b848b0659de023f9d9b63.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figura 2. O corretor 3 falha, e seu seguidor no corretor 2 \u00e9 eleito novo l\u00edder da parti\u00e7\u00e3o 2<\/i><\/p>\n<p>Em seguida, o corretor 1 sai e a parti\u00e7\u00e3o 1 tamb\u00e9m perde seu l\u00edder, cuja fun\u00e7\u00e3o passa a ser do corretor 2.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/9f5409c723da7ff059b93f9b23e7d5f6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figura 3. Permanece apenas um corretor. Todos os l\u00edderes est\u00e3o em um \u00fanico corretor com zero redund\u00e2ncia<\/i><\/p>\n<p>Quando o corretor 1 retorna \u00e0 rede, ele adiciona quatro seguidores, fornecendo alguma redund\u00e2ncia para cada parti\u00e7\u00e3o. Mas todos os l\u00edderes ainda permanecem no corretor 2.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/f9c8e42f51258b7fd7f6f35dc7b8cc3b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figura 4. Os l\u00edderes permanecem no corretor 2<\/i><\/p>\n<p>Quando o corretor 3 se reinicia, retornamos a tr\u00eas r\u00e9plicas por parti\u00e7\u00e3o. Mas todos os l\u00edderes ainda est\u00e3o no corretor 2.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/9c8c02be4161f8468b5dbc1e3f6ecb3a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figura 5. Distribui\u00e7\u00e3o desequilibrada dos l\u00edderes ap\u00f3s a recupera\u00e7\u00e3o dos corretores 1 e 3<\/i><\/p>\n<p>O Kafka tem uma ferramenta para reequilibrar l\u00edderes de forma mais eficiente do que o RabbitMQ. Nesse caso, era necess\u00e1rio usar um plugin ou script externo que alterava as pol\u00edticas para migrar o n\u00f3 principal \u00e0 custa da redu\u00e7\u00e3o da redund\u00e2ncia durante a migra\u00e7\u00e3o. Al\u00e9m disso, para grandes filas, era preciso aceitar a indisponibilidade durante a sincroniza\u00e7\u00e3o.<\/p>\n<p>O Kafka tem o conceito de \"r\u00e9plicas preferidas\" para o papel de l\u00edder. Quando as parti\u00e7\u00f5es de um t\u00f3pico s\u00e3o criadas, o Kafka tenta distribuir os l\u00edderes uniformemente entre os n\u00f3s e marca esses primeiros l\u00edderes como preferidos. Com o tempo, devido a reinicializa\u00e7\u00f5es de servidores, falhas e interrup\u00e7\u00f5es de conectividade, os l\u00edderes podem acabar em diferentes n\u00f3s, como no caso extremo descrito acima.<\/p>\n<p>Para corrigir isso, o Kafka oferece duas op\u00e7\u00f5es:<\/p>\n<ul>\n<li>Op\u00e7\u00e3o <i>auto.leader.rebalance.enable=true<\/i> permite que o n\u00f3 do controlador reatribua automaticamente os l\u00edderes de volta \u00e0s r\u00e9plicas preferidas, restaurando assim a distribui\u00e7\u00e3o uniforme.\n<\/li>\n<li>O administrador pode executar o script <i>kafka-preferred-replica-election.sh<\/i> para reatribuir manualmente.<\/li>\n<\/ul>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/831930b06809637018fecb6d7d5a558d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 6. R\u00e9plicas ap\u00f3s rebalanceamento<\/i><\/p>\n<p>Esta foi uma vers\u00e3o simplificada da falha, mas a realidade \u00e9 mais complexa, embora aqui n\u00e3o haja nada muito complicado. Tudo se resume a r\u00e9plicas sincronizadas (In-Sync Replicas, ISR).<\/p>\n<h1>R\u00e9plicas sincronizadas (ISR)<\/h1>\n<p>\nISR \u00e9 um conjunto de r\u00e9plicas de parti\u00e7\u00e3o que \u00e9 considerado \"sincronizado\" (in-sync). Aqui existe um l\u00edder, e pode n\u00e3o haver seguidores. Um seguidor \u00e9 considerado sincronizado se ele fez c\u00f3pias exatas de todas as mensagens do l\u00edder antes do t\u00e9rmino do intervalo <i>replica.lag.time.max.ms<\/i>.<\/p>\n<p>Um seguidor \u00e9 removido do conjunto ISR se:<\/p>\n<ul>\n<li>n\u00e3o fez a solicita\u00e7\u00e3o de busca durante o intervalo <i>replica.lag.time.max.ms<\/i> (considerado morto)\n<\/li>\n<li>n\u00e3o conseguiu se atualizar durante o intervalo <i>replica.lag.time.max.ms<\/i> (considerado lento)<\/li>\n<\/ul>\n<p>\nOs seguidores fazem solicita\u00e7\u00f5es de busca dentro do intervalo <i>replica.fetch.wait.max.ms<\/i>, que por padr\u00e3o \u00e9 500 ms.<\/p>\n<p>Para explicar claramente o objetivo do ISR, \u00e9 necess\u00e1rio olhar para as confirma\u00e7\u00f5es do produtor e alguns cen\u00e1rios de falha. Os produtores podem escolher quando o corretor envia a confirma\u00e7\u00e3o:<\/p>\n<ul>\n<li>acks=0, confirma\u00e7\u00e3o n\u00e3o \u00e9 enviada\n<\/li>\n<li>acks=1, confirma\u00e7\u00e3o \u00e9 enviada ap\u00f3s o l\u00edder gravar a mensagem em seu log local\n<\/li>\n<li>acks=all, confirma\u00e7\u00e3o \u00e9 enviada ap\u00f3s todas as r\u00e9plicas em ISR gravarem a mensagem em seus logs locais<\/li>\n<\/ul>\n<p>\nNa terminologia do Kafka, se o ISR tiver armazenado a mensagem, ocorre o seu \"commit\". Acks=all \u00e9 a op\u00e7\u00e3o mais segura, mas tamb\u00e9m gera uma lat\u00eancia adicional. Vamos considerar dois exemplos de falha e como as diferentes op\u00e7\u00f5es de 'acks' interagem com o conceito de ISR.<\/p>\n<h3>Acks=1 e ISR<\/h3>\n<p>\nNeste exemplo, veremos que se o l\u00edder n\u00e3o espera a confirma\u00e7\u00e3o de cada mensagem de todos os seguidores, a perda de dados pode ocorrer em caso de falha do l\u00edder. A transi\u00e7\u00e3o para um seguidor n\u00e3o sincronizado pode ser permitida ou negada pela configura\u00e7\u00e3o. <i>unclean.leader.election.enable<\/i>.<\/p>\n<p>Neste exemplo, o produtor tem o valor de acks=1. A parti\u00e7\u00e3o est\u00e1 distribu\u00edda entre os tr\u00eas corretores. O corretor 3 est\u00e1 atrasado, ele sincronizou com o l\u00edder h\u00e1 oito segundos e agora est\u00e1 atrasado em 7456 mensagens. O corretor 1 est\u00e1 atrasado apenas por um segundo. Nosso produtor envia uma mensagem e rapidamente recebe a confirma\u00e7\u00e3o, sem sobrecarga de seguidores lentos ou mortos que o l\u00edder n\u00e3o espera.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/f194e6309b732b772574392eff482a8b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 7. ISR com tr\u00eas r\u00e9plicas<\/i><\/p>\n<p>O corretor 2 falha, e o produtor recebe um erro de conex\u00e3o. Ap\u00f3s a transi\u00e7\u00e3o de lideran\u00e7a para o corretor 1, perdemos 123 mensagens. O seguidor no corretor 1 estava no ISR, mas n\u00e3o estava completamente sincronizado com o l\u00edder quando ele falhou.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/367f219daebafefe585059f67fdedf6f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 8. Mensagens s\u00e3o perdidas em caso de falha<\/i><\/p>\n<p>Na configura\u00e7\u00e3o <i>bootstrap.servers<\/i> o produtor lista v\u00e1rios corretores e pode perguntar a outro corretor quem se tornou o novo l\u00edder da parti\u00e7\u00e3o. Em seguida, ele estabelece uma conex\u00e3o com o corretor 1 e continua enviando mensagens.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/ba45c51f4ce1f63f10b2fa0e1487b223.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 9. O envio de mensagens \u00e9 retomado ap\u00f3s uma breve interrup\u00e7\u00e3o<\/i><\/p>\n<p>O corretor 3 est\u00e1 ainda mais atrasado. Ele faz solicita\u00e7\u00f5es de recupera\u00e7\u00e3o, mas n\u00e3o consegue se sincronizar. Isso pode ser devido a uma conex\u00e3o de rede lenta entre os corretores, problemas de armazenamento, etc. Ele \u00e9 removido do ISR. Agora, o ISR consiste em uma \u00fanica r\u00e9plica - o l\u00edder! O produtor continua enviando mensagens e recebendo confirma\u00e7\u00f5es.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/592c74632e3a8d80c2b4fc15bde5d401.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 10. O seguidor no corretor 3 \u00e9 removido do ISR<\/i><\/p>\n<p>O corretor 1 falha, e o papel de l\u00edder passa para o corretor 3 com a perda de 15286 mensagens! O produtor recebe uma mensagem de erro de conex\u00e3o. A transi\u00e7\u00e3o para um l\u00edder fora do ISR foi poss\u00edvel apenas devido \u00e0 configura\u00e7\u00e3o <i>unclean.leader.election.enable=true<\/i>. Se estiver configurada para <i>falso<\/i>, a transi\u00e7\u00e3o n\u00e3o teria ocorrido e todas as solicita\u00e7\u00f5es de leitura e grava\u00e7\u00e3o teriam sido rejeitadas. Nesse caso, aguardamos o retorno do corretor 1 com seus dados intocados na r\u00e9plica, que reassumir\u00e1 a lideran\u00e7a.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/30f01ca715ccc194890ae061a3ef7396.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 11. O corretor 1 falha. Uma grande quantidade de mensagens \u00e9 perdida em caso de falha.<\/i><\/p>\n<p>O produtor estabelece uma conex\u00e3o com o \u00faltimo corretor e v\u00ea que agora ele \u00e9 o l\u00edder da se\u00e7\u00e3o. Ele come\u00e7a a enviar mensagens para o corretor 3.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/986532d9b22b6514b6039c8460b1beb4.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 12. Ap\u00f3s uma breve pausa, as mensagens s\u00e3o novamente enviadas para a se\u00e7\u00e3o 0.<\/i><\/p>\n<p>Vimos que, al\u00e9m das breves interrup\u00e7\u00f5es para estabelecer novas conex\u00f5es e buscar um novo l\u00edder, o produtor estava constantemente enviando mensagens. Essa configura\u00e7\u00e3o garante disponibilidade \u00e0 custa da consist\u00eancia (seguran\u00e7a dos dados). O Kafka perdeu milhares de mensagens, mas continuou a receber novas grava\u00e7\u00f5es.<\/p>\n<h3>Acks=all e ISR<\/h3>\n<p>\nVamos repetir esse cen\u00e1rio mais uma vez, mas com <i>acks=all<\/i>. O atraso do corretor 3 \u00e9 em m\u00e9dia de quatro segundos. O produtor envia uma mensagem com <i>acks=all<\/i>, e agora n\u00e3o recebe uma resposta r\u00e1pida. O l\u00edder espera at\u00e9 que a mensagem seja salva por todas as r\u00e9plicas no ISR.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/95b1abdc92e699f7bc41ebab249a2e08.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 13. ISR com tr\u00eas r\u00e9plicas. Uma est\u00e1 funcionando lentamente, o que resulta em atraso na grava\u00e7\u00e3o.<\/i><\/p>\n<p>Ap\u00f3s quatro segundos de atraso adicional, o corretor 2 envia ack. Todas as r\u00e9plicas agora est\u00e3o completamente atualizadas.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/64356dc8d2641a3e22947126dd047f39.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 14. Todas as r\u00e9plicas mant\u00eam as mensagens e um ack \u00e9 enviado.<\/i><\/p>\n<p>O corretor 3 agora est\u00e1 ainda mais atrasado e \u00e9 removido do ISR. O atraso diminui significativamente, pois n\u00e3o restam r\u00e9plicas lentas no ISR. O corretor 2 agora aguarda apenas o corretor 1, que tem um atraso m\u00e9dio de 500 ms.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/5d3bd67dc53cb868fa40b358ed483a1d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 15. A r\u00e9plica no corretor 3 \u00e9 removida do ISR.<\/i><\/p>\n<p>Em seguida, o corretor 2 falha, e a lideran\u00e7a passa para o corretor 1 sem perda de mensagens.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/e3f0417aa7714ea5eae8a8e8d61662bd.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 16. O corretor 2 falha.<\/i><\/p>\n<p>O produtor encontra um novo l\u00edder e come\u00e7a a enviar mensagens para ele. O atraso diminui ainda mais, j\u00e1 que agora o ISR consiste em uma \u00fanica r\u00e9plica! Portanto, a op\u00e7\u00e3o <i>acks=all<\/i> n\u00e3o adiciona redund\u00e2ncia.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/fec9aae9977757d5f61c2909ceae0536.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 17. A r\u00e9plica no corretor 1 assume a lideran\u00e7a sem perda de mensagens.<\/i><\/p>\n<p>Em seguida, o corretor 1 falha, e a lideran\u00e7a passa para o corretor 3 com a perda de 14238 mensagens!<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/730b3951fb75ab3a782fc6d064615212.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 18. O corretor 1 morre, e a transi\u00e7\u00e3o de lideran\u00e7a com a configura\u00e7\u00e3o unclean resulta em extensa perda de dados.<\/i><\/p>\n<p>Poder\u00edamos n\u00e3o definir a op\u00e7\u00e3o <i>unclean.leader.election.enable<\/i> como valor <i>verdadeiro<\/i>. Por padr\u00e3o, ela \u00e9 igual a <i>falso<\/i>. A configura\u00e7\u00e3o <i>acks=all<\/i> com <i>unclean.leader.election.enable=true<\/i> garante disponibilidade com um pouco de seguran\u00e7a adicional dos dados. Mas, como voc\u00ea pode ver, ainda podemos perder mensagens.<\/p>\n<p>Mas e se quisermos aumentar a seguran\u00e7a dos dados? Podemos definir <i>unclean.leader.election.enable = false<\/i>, mas isso n\u00e3o ir\u00e1 necessariamente nos proteger contra a perda de dados. Se o l\u00edder falhar de forma severa e levar os dados consigo, as mensagens ainda estar\u00e3o perdidas, al\u00e9m de haver perda de disponibilidade at\u00e9 que o administrador recupere a situa\u00e7\u00e3o.<\/p>\n<p>\u00c9 melhor garantir a redund\u00e2ncia de todas as mensagens, ou ent\u00e3o abrir m\u00e3o do registro. Dessa forma, pelo menos do ponto de vista do broker, a perda de dados s\u00f3 \u00e9 poss\u00edvel em caso de duas ou mais falhas simult\u00e2neas.<\/p>\n<h3>Acks=all, min.insync.replicas e ISR<\/h3>\n<p>\nCom a configura\u00e7\u00e3o do t\u00f3pico <i>min.insync.replicas<\/i> aumentamos o n\u00edvel de seguran\u00e7a dos dados. Vamos rever mais uma vez a \u00faltima parte do cen\u00e1rio anterior, mas desta vez com <i>min.insync.replicas=2<\/i>.<\/p>\n<p>Ent\u00e3o, o broker 2 tem um l\u00edder de r\u00e9plica, e o seguidor no broker 3 foi removido do ISR.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/5831463293f1837d3232756894e97162.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 19. ISR de duas r\u00e9plicas<\/i><\/p>\n<p>O broker 2 falha, e a lideran\u00e7a passa para o broker 1 sem perda de mensagens. Mas agora o ISR consiste apenas em uma r\u00e9plica. Isso n\u00e3o atende ao n\u00famero m\u00ednimo para receber registros, e portanto o broker responde a uma tentativa de grava\u00e7\u00e3o com um erro. <i>NotEnoughReplicas<\/i>.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/6b2ee477f4c33ec84f3068b792814e5d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 20. O n\u00famero de ISR \u00e9 um a menos do que o indicado em min.insync.replicas<\/i><\/p>\n<p>Esta configura\u00e7\u00e3o sacrifica a disponibilidade em prol da consist\u00eancia. Antes de confirmar a mensagem, garantimos que ela seja gravada em pelo menos duas r\u00e9plicas. Isso d\u00e1 ao produtor muito mais confian\u00e7a. Aqui, a perda de mensagens \u00e9 poss\u00edvel apenas se ocorrer uma falha simult\u00e2nea de duas r\u00e9plicas em um curto intervalo, antes que a mensagem seja replicada para um seguidor adicional, o que \u00e9 improv\u00e1vel. Mas se voc\u00ea for um superparanoico, pode definir um fator de replica\u00e7\u00e3o de 5, e <i>min.insync.replicas<\/i> o no 3. Aqui, tr\u00eas brokers devem falhar simultaneamente para perder um registro! Claro, por essa confiabilidade voc\u00ea pagar\u00e1 com um adicional de lat\u00eancia.<\/p>\n<h1>Quando a disponibilidade \u00e9 necess\u00e1ria para a seguran\u00e7a dos dados<\/h1>\n<p>\nAssim como no <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/itsumma\/blog\/471858\/\">no caso do RabbitMQ<\/a><\/noindex>, \u00e0s vezes a disponibilidade \u00e9 necess\u00e1ria para a seguran\u00e7a dos dados. Voc\u00ea precisa considerar o seguinte:<\/p>\n<ul>\n<li>O publisher pode simplesmente retornar um erro, e o servi\u00e7o ou usu\u00e1rio de n\u00edvel superior pode tentar novamente mais tarde?\n<\/li>\n<li>Um publisher pode salvar a mensagem localmente ou em um banco de dados, para tentar novamente mais tarde?<\/li>\n<\/ul>\n<p>\nSe a resposta for n\u00e3o, ent\u00e3o a otimiza\u00e7\u00e3o da disponibilidade aumenta a seguran\u00e7a dos dados. Voc\u00ea perder\u00e1 menos dados se optar pela disponibilidade em vez de recusar o registro. Assim, tudo se resume a encontrar um equil\u00edbrio, e a solu\u00e7\u00e3o depende da situa\u00e7\u00e3o espec\u00edfica.<\/p>\n<h1>O sentido do ISR<\/h1>\n<p>\nO conjunto ISR permite escolher o equil\u00edbrio ideal entre seguran\u00e7a de dados e lat\u00eancia. Por exemplo, garantir a disponibilidade em caso de falha da maioria das r\u00e9plicas, minimizando o impacto de r\u00e9plicas mortas ou lentas em termos de lat\u00eancia.<\/p>\n<p>N\u00f3s escolhemos o valor <i>replica.lag.time.max.ms<\/i> de acordo com nossas necessidades. Essencialmente, esse par\u00e2metro indica qual lat\u00eancia estamos dispostos a aceitar ao <i>acks=all<\/i>. O valor padr\u00e3o \u00e9 de dez segundos. Se isso for muito longo para voc\u00ea, pode reduzi-lo. Nesse caso, a frequ\u00eancia de altera\u00e7\u00f5es no ISR aumentar\u00e1, pois os seguidores ser\u00e3o removidos e adicionados com mais frequ\u00eancia.<\/p>\n<p>No RabbitMQ, existe apenas um conjunto de espelhos que precisam ser replicados. Espelhos lentos introduzem lat\u00eancia adicional, e a resposta de espelhos mortos pode ser aguardada at\u00e9 o tempo de vida dos pacotes que verificam a disponibilidade de cada n\u00f3 (net tick). O ISR \u00e9 uma maneira interessante de evitar esses problemas de lat\u00eancia aumentada. Por\u00e9m, corremos o risco de perder a redund\u00e2ncia, j\u00e1 que o ISR pode ser reduzido apenas ao l\u00edder. Para evitar esse risco, utilize a configura\u00e7\u00e3o <i>min.insync.replicas<\/i>.<\/p>\n<h1>Garantia de conex\u00e3o de clientes<\/h1>\n<p>\nNas configura\u00e7\u00f5es <i>bootstrap.servers<\/i> do produtor e do consumidor, voc\u00ea pode especificar v\u00e1rios brokers para conectar clientes. A ideia \u00e9 que, se um n\u00f3 falhar, haja v\u00e1rios backups com os quais o cliente pode estabelecer conex\u00e3o. Isso n\u00e3o precisa ser apenas l\u00edderes de parti\u00e7\u00f5es, mas simplesmente um ponto de partida para o carregamento inicial. O cliente pode perguntar a eles em qual n\u00f3 o l\u00edder da parti\u00e7\u00e3o est\u00e1 hospedado para leitura\/grava\u00e7\u00e3o.<\/p>\n<p>No RabbitMQ, os clientes podem conectar a qualquer n\u00f3, e o roteamento interno envia a solicita\u00e7\u00e3o para onde precisa ir. Isso significa que voc\u00ea pode instalar um balanceador de carga na frente do RabbitMQ. O Kafka exige que os clientes se conectem ao n\u00f3 onde o l\u00edder da parti\u00e7\u00e3o correspondente est\u00e1 hospedado. Nessa situa\u00e7\u00e3o, um balanceador de carga n\u00e3o pode ser colocado. A lista <i>bootstrap.servers<\/i> \u00e9 crucial para que os clientes possam se conectar aos n\u00f3s corretos e encontr\u00e1-los ap\u00f3s uma falha.<\/p>\n<h1>Arquitetura de consenso do Kafka<\/h1>\n<p>\nAt\u00e9 agora, n\u00e3o examinamos como o cluster descobre sobre a queda de um broker e como um novo l\u00edder \u00e9 escolhido. Para entender como o Kafka lida com as divis\u00f5es de rede, \u00e9 necess\u00e1rio primeiro compreender a arquitetura de consenso.<\/p>\n<p>Cada cluster Kafka \u00e9 implantado juntamente com um cluster Zookeeper \u2014 um servi\u00e7o de consenso distribu\u00eddo que permite que o sistema atinja consenso sobre um determinado estado, priorizando a consist\u00eancia em vez da disponibilidade. Para a aprova\u00e7\u00e3o de opera\u00e7\u00f5es de leitura e grava\u00e7\u00e3o, \u00e9 necess\u00e1rio o consentimento da maioria dos n\u00f3s Zookeeper.<\/p>\n<p>O Zookeeper armazena o estado do cluster:<\/p>\n<ul>\n<li>Lista de t\u00f3picos, parti\u00e7\u00f5es, configura\u00e7\u00f5es, r\u00e9plicas l\u00edderes atuais, r\u00e9plicas preferenciais.\n<\/li>\n<li>Membros do cluster. Cada corretor envia pings para o cluster Zookeeper. Se n\u00e3o receber um ping dentro de um per\u00edodo de tempo definido, o Zookeeper registra o corretor como indispon\u00edvel.\n<\/li>\n<li>Escolha de n\u00f3s prim\u00e1rio e reserva para o controlador.<\/li>\n<\/ul>\n<p>\nO n\u00f3 controlador \u00e9 um dos corretores Kafka respons\u00e1vel pela elei\u00e7\u00e3o dos l\u00edderes das r\u00e9plicas. O Zookeeper envia notifica\u00e7\u00f5es ao controlador sobre mudan\u00e7as na membresia do cluster e mudan\u00e7as nos t\u00f3picos, e o controlador deve agir de acordo com essas mudan\u00e7as.<\/p>\n<p>Por exemplo, vamos considerar um novo t\u00f3pico com dez parti\u00e7\u00f5es e um fator de replica\u00e7\u00e3o de 3. O controlador deve escolher um l\u00edder para cada parti\u00e7\u00e3o, tentando distribuir os l\u00edderes entre os corretores de forma otimizada. <\/p>\n<p>Para cada parti\u00e7\u00e3o, o controlador:<\/p>\n<ul>\n<li>atualiza as informa\u00e7\u00f5es no Zookeeper sobre ISR e l\u00edder;\n<\/li>\n<li>envia o comando LeaderAndISRCommand a cada corretor que hospeda uma r\u00e9plica dessa parti\u00e7\u00e3o, informando os corretores sobre ISR e l\u00edder.<\/li>\n<\/ul>\n<p>\nQuando um corretor com o l\u00edder falha, o Zookeeper envia uma notifica\u00e7\u00e3o ao controlador, e este escolhe um novo l\u00edder. Novamente, o controlador atualiza primeiro o Zookeeper e, em seguida, envia um comando a cada corretor, informando-os sobre a mudan\u00e7a de lideran\u00e7a.<\/p>\n<p>Cada l\u00edder \u00e9 respons\u00e1vel pelo conjunto de ISR. A configura\u00e7\u00e3o <i>replica.lag.time.max.ms<\/i> determina quem estar\u00e1 inclu\u00eddo. Ao mudar o ISR, o l\u00edder comunica ao Zookeeper as novas informa\u00e7\u00f5es.<\/p>\n<p>O Zookeeper est\u00e1 sempre informado sobre quaisquer mudan\u00e7as, para que em caso de falha a lideran\u00e7a transite suavemente para o novo l\u00edder.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/3adb1d204b28e3ed85bef3530fa2b738.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 21. Consenso Kafka<\/i><\/p>\n<h1>Protocolo de replica\u00e7\u00e3o<\/h1>\n<p>\nEntender os detalhes da replica\u00e7\u00e3o ajuda a compreender melhor os cen\u00e1rios potenciais de perda de dados.<\/p>\n<h3>Solicita\u00e7\u00f5es de coleta, Log End Offset (LEO) e Highwater Mark (HW)<\/h3>\n<p>\nAnalisamos que os followers periodicamente enviam solicita\u00e7\u00f5es ao l\u00edder para busca (fetch). O intervalo padr\u00e3o \u00e9 de 500 ms. Isso difere do RabbitMQ, pois, no RabbitMQ, a replica\u00e7\u00e3o \u00e9 iniciada n\u00e3o pelo espelho da fila, mas pelo mestre. O mestre envia as altera\u00e7\u00f5es para os espelhos.<\/p>\n<p>O l\u00edder e todos os followers mant\u00eam o deslocamento do final do log (Log End Offset, LEO) e a marca Highwater (HW). A marca LEO armazena o deslocamento da \u00faltima mensagem na r\u00e9plica local, enquanto a HW armazena o deslocamento do \u00faltimo commit. Lembre-se de que, para o status 'commit', a mensagem deve ser salva em todas as r\u00e9plicas ISR. Isso significa que o LEO geralmente est\u00e1 ligeiramente \u00e0 frente da HW.<\/p>\n<p>Quando o l\u00edder recebe uma mensagem, ele a salva localmente. O follower faz uma solicita\u00e7\u00e3o de busca, enviando seu LEO. O l\u00edder ent\u00e3o envia um pacote de mensagens, come\u00e7ando a partir desse LEO, e tamb\u00e9m envia a HW atual. Quando o l\u00edder recebe a informa\u00e7\u00e3o de que todas as r\u00e9plicas salvaram a mensagem com o deslocamento especificado, ele move a marca HW. Apenas o l\u00edder pode mover a HW, e assim todos os followers conseguem saber o valor atual nas respostas \u00e0s suas solicita\u00e7\u00f5es. Isso significa que os followers podem ficar atr\u00e1s do l\u00edder tanto em mensagens quanto em rela\u00e7\u00e3o ao conhecimento da HW. Os consumidores recebem mensagens apenas at\u00e9 a HW atual.<\/p>\n<p>Observe que 'persistido' significa gravado na mem\u00f3ria, e n\u00e3o no disco. Para desempenho, o Kafka sincroniza no disco com um intervalo espec\u00edfico. O RabbitMQ tamb\u00e9m possui esse intervalo, mas enviar\u00e1 a confirma\u00e7\u00e3o ao publisher apenas depois que o mestre e todos os espelhos gravarem a mensagem no disco. Os desenvolvedores do Kafka decidiram, por motivos de desempenho, enviar ack assim que a mensagem estiver gravada na mem\u00f3ria. O Kafka aposta que a redund\u00e2ncia compensa o risco de armazenar confirmados apenas na mem\u00f3ria a curto prazo.<\/p>\n<h1>Falha do l\u00edder<\/h1>\n<p>\nQuando o l\u00edder falha, o Zookeeper notifica o controlador, que escolhe uma nova r\u00e9plica para l\u00edder. O novo l\u00edder estabelece uma nova marca HW de acordo com seu LEO. Em seguida, as informa\u00e7\u00f5es sobre o novo l\u00edder s\u00e3o recebidas pelos followers. Dependendo da vers\u00e3o do Kafka, o follower escolher\u00e1 um dos dois cen\u00e1rios:<\/p>\n<ol>\n<li>Truncar\u00e1 o log local at\u00e9 a HW conhecida e enviar\u00e1 ao novo l\u00edder uma solicita\u00e7\u00e3o por mensagens ap\u00f3s essa marca.\n<\/li>\n<li>Envie uma solicita\u00e7\u00e3o ao l\u00edder para verificar o HW no momento em que foi escolhido como l\u00edder e, em seguida, truncar\u00e1 o log at\u00e9 esse deslocamento. Em seguida, come\u00e7ar\u00e1 a fazer solicita\u00e7\u00f5es peri\u00f3dicas de amostragem, come\u00e7ando a partir desse deslocamento.<\/li>\n<\/ol>\n<p>\nO seguidor pode precisar truncar o log por v\u00e1rios motivos:<\/p>\n<ul>\n<li>Quando ocorre uma falha do l\u00edder, o primeiro seguidor do conjunto ISR registrado no Zookeeper vence as elei\u00e7\u00f5es e se torna o l\u00edder. Todos os seguidores no ISR, embora considerados \"sincronizados\", podem n\u00e3o ter recebido copias de todas as mensagens do antigo l\u00edder. \u00c9 muito poss\u00edvel que o seguidor escolhido n\u00e3o tenha a c\u00f3pia mais atualizada. Kafka garante que n\u00e3o h\u00e1 discrep\u00e2ncias entre as r\u00e9plicas. Assim, para evitar diverg\u00eancias, cada seguidor deve truncar seu log at\u00e9 o valor HW do novo l\u00edder no momento de sua elei\u00e7\u00e3o. Essa \u00e9 mais uma raz\u00e3o pela qual a configura\u00e7\u00e3o <i>acks=all<\/i> \u00e9 importante para a consist\u00eancia.\n<\/li>\n<li>As mensagens s\u00e3o periodicamente gravadas no disco. Se todos os n\u00f3s do cluster falharem ao mesmo tempo, as r\u00e9plicas ter\u00e3o deslocamentos diferentes nos discos. \u00c9 bem poss\u00edvel que, quando os corretores voltem \u00e0 rede, o novo l\u00edder a ser eleito fique atr\u00e1s de seus seguidores, pois ele foi salvo no disco antes dos outros.<\/li>\n<\/ul>\n<p><\/p>\n<h3>Reconectando-se ao cluster<\/h3>\n<p>\nAo reconectar-se ao cluster, as r\u00e9plicas s\u00e3o tratadas da mesma forma que em caso de falha do l\u00edder: verificam a r\u00e9plica do l\u00edder e truncam seu log at\u00e9 seu HW (no momento da elei\u00e7\u00e3o). Em contraste, o RabbitMQ considera que n\u00f3s reconectados s\u00e3o completamente novos. Em ambos os casos, o corretor descarta qualquer estado existente. Se a sincroniza\u00e7\u00e3o autom\u00e1tica estiver sendo utilizada, o mestre deve replicar absolutamente todo o conte\u00fado atual para o novo espelho de forma que \"e que o mundo espere\". Durante essa opera\u00e7\u00e3o, o mestre n\u00e3o aceita nenhuma opera\u00e7\u00e3o de leitura ou grava\u00e7\u00e3o. Essa abordagem cria problemas em grandes filas.<\/p>\n<p>Kafka \u00e9 um log distribu\u00eddo e, de forma geral, ele armazena mais mensagens do que uma fila RabbitMQ, onde os dados s\u00e3o removidos da fila ap\u00f3s serem lidos. Filas ativas devem permanecer relativamente pequenas. No entanto, o Kafka \u00e9 um log com sua pr\u00f3pria pol\u00edtica de armazenamento, que pode definir um prazo de dias ou semanas. A abordagem com bloqueio de filas e sincroniza\u00e7\u00e3o completa \u00e9 absolutamente inaceit\u00e1vel para um log distribu\u00eddo. Em vez disso, os followers do Kafka simplesmente cortam seu log at\u00e9 o l\u00edder HW (no momento de sua elei\u00e7\u00e3o) caso sua c\u00f3pia ultrapasse o l\u00edder. No caso mais prov\u00e1vel, onde o follower est\u00e1 atrasado, ele simplesmente come\u00e7a a fazer solicita\u00e7\u00f5es de recupera\u00e7\u00e3o, come\u00e7ando pelo seu LEO atual.<\/p>\n<p>Novos ou reassociados followers come\u00e7am fora do ISR e n\u00e3o participam dos commits. Eles simplesmente trabalham ao lado do grupo, recebendo mensagens t\u00e3o rapidamente quanto conseguem, at\u00e9 alcan\u00e7arem o l\u00edder e entrarem no ISR. Aqui n\u00e3o h\u00e1 bloqueio e n\u00e3o \u00e9 necess\u00e1rio descartar todos os seus dados.<\/p>\n<h1>Divis\u00e3o de Coes\u00e3o<\/h1>\n<p>\nO Kafka tem mais componentes do que o RabbitMQ, portanto, h\u00e1 um conjunto mais complexo de comportamentos quando a conectividade do cluster \u00e9 interrompida. Mas o Kafka foi projetado originalmente para clusters, ent\u00e3o as solu\u00e7\u00f5es s\u00e3o muito bem pensadas.<\/p>\n<p>Abaixo est\u00e3o alguns cen\u00e1rios de interrup\u00e7\u00e3o de conectividade:<\/p>\n<ul>\n<li>Cen\u00e1rio 1. O follower n\u00e3o v\u00ea o l\u00edder, mas ainda v\u00ea o Zookeeper.\n<\/li>\n<li>Cen\u00e1rio 2. O l\u00edder n\u00e3o v\u00ea nenhum follower, mas ainda v\u00ea o Zookeeper.\n<\/li>\n<li>Cen\u00e1rio 3. O follower v\u00ea o l\u00edder, mas n\u00e3o v\u00ea o Zookeeper.\n<\/li>\n<li>Cen\u00e1rio 4. O l\u00edder v\u00ea os followers, mas n\u00e3o v\u00ea o Zookeeper.\n<\/li>\n<li>Cen\u00e1rio 5. O follower est\u00e1 completamente isolado tanto dos outros n\u00f3s Kafka quanto do Zookeeper.\n<\/li>\n<li>Cen\u00e1rio 6. O l\u00edder est\u00e1 completamente isolado tanto dos outros n\u00f3s Kafka quanto do Zookeeper.\n<\/li>\n<li>Cen\u00e1rio 7. O n\u00f3 Controller do Kafka n\u00e3o v\u00ea outro n\u00f3 Kafka.\n<\/li>\n<li>Cen\u00e1rio 8. O Controller do Kafka n\u00e3o v\u00ea o Zookeeper.<\/li>\n<\/ul>\n<p>\nPara cada cen\u00e1rio, h\u00e1 um comportamento espec\u00edfico.<\/p>\n<h3>Cen\u00e1rio 1. O follower n\u00e3o v\u00ea o l\u00edder, mas ainda v\u00ea o Zookeeper.<\/h3>\n<p>\n<img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/5f51ae679933b2b5a69e21831465d121.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 22. Cen\u00e1rio 1. ISR de tr\u00eas r\u00e9plicas.<\/i><\/p>\n<p>A interrup\u00e7\u00e3o de conectividade isola o broker 3 dos brokers 1 e 2, mas n\u00e3o do Zookeeper. O broker 3 n\u00e3o pode mais fazer solicita\u00e7\u00f5es de recupera\u00e7\u00e3o. Ap\u00f3s um certo tempo. <i>replica.lag.time.max.ms<\/i> ele \u00e9 removido do ISR e n\u00e3o participa dos commits de mensagens. Assim que a conectividade for restaurada, ele reiniciar\u00e1 as solicita\u00e7\u00f5es de recupera\u00e7\u00e3o e se juntar\u00e1 ao ISR quando alcan\u00e7ar o l\u00edder. O Zookeeper continuar\u00e1 recebendo pings e considerar\u00e1 que o corretor est\u00e1 vivo e saud\u00e1vel.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/976b7ff080ee6a6d76a165f614f40e95.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 23. Cen\u00e1rio 1. O corretor \u00e9 removido do ISR se n\u00e3o houver solicita\u00e7\u00e3o de recupera\u00e7\u00e3o recebida dentro do intervalo replica.lag.time.max.ms<\/i><\/p>\n<p>N\u00e3o h\u00e1 nenhuma divis\u00e3o l\u00f3gica (split-brain) ou suspens\u00e3o do n\u00f3, como no RabbitMQ. Em vez disso, a redund\u00e2ncia diminui. <\/p>\n<h3>Cen\u00e1rio 2. O l\u00edder n\u00e3o v\u00ea nenhum follower, mas ainda v\u00ea o Zookeeper<\/h3>\n<p>\n<img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/ff6aaa053d73e8b7c97111979bcf97aa.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 24. Cen\u00e1rio 2. O l\u00edder e dois followers<\/i><\/p>\n<p>A perda de conectividade de rede separa o l\u00edder dos followers, mas o corretor ainda v\u00ea o Zookeeper. Como no primeiro cen\u00e1rio, o ISR \u00e9 comprimido, mas desta vez apenas at\u00e9 o l\u00edder, uma vez que todos os followers param de enviar solicita\u00e7\u00f5es de recupera\u00e7\u00e3o. Novamente, n\u00e3o h\u00e1 divis\u00e3o l\u00f3gica. Em vez disso, h\u00e1 uma perda de redund\u00e2ncia para novas mensagens, at\u00e9 que a conectividade seja restaurada. O Zookeeper continua recebendo pings e considera que o corretor est\u00e1 vivo e saud\u00e1vel.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/3c69e8327da241407f76719fc022c37a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 25. Cen\u00e1rio 2. O ISR se comprimiu apenas at\u00e9 o l\u00edder<\/i><\/p>\n<h3>Cen\u00e1rio 3. O follower v\u00ea o l\u00edder, mas n\u00e3o v\u00ea o Zookeeper<\/h3>\n<p>\nO follower \u00e9 separado do Zookeeper, mas n\u00e3o do corretor com o l\u00edder. Como resultado, o follower continua fazendo solicita\u00e7\u00f5es de recupera\u00e7\u00e3o e sendo membro do ISR. O Zookeeper n\u00e3o recebe mais pings e registra a queda do corretor, mas como este \u00e9 apenas um follower, n\u00e3o h\u00e1 consequ\u00eancias ap\u00f3s a recupera\u00e7\u00e3o.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/1183bcfe45a3225ae3ef1a0651f61350.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 26. Cen\u00e1rio 3. O follower continua enviando solicita\u00e7\u00f5es de recupera\u00e7\u00e3o ao l\u00edder<\/i><\/p>\n<h3>Cen\u00e1rio 4. O l\u00edder v\u00ea os followers, mas n\u00e3o v\u00ea o Zookeeper<\/h3>\n<p>\n<img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/b3bf27fcb0eb806b27ad00f098e50a26.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 27. Cen\u00e1rio 4. O l\u00edder e dois followers<\/i><\/p>\n<p>O l\u00edder est\u00e1 separado do Zookeeper, mas n\u00e3o dos corretores com os followers. <\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/82d9f2e5868566678befc414d1885bfd.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 28. Cen\u00e1rio 4. O l\u00edder est\u00e1 isolado do Zookeeper<\/i><\/p>\n<p>Ap\u00f3s algum tempo, o Zookeeper registrar\u00e1 a queda do corretor e notificar\u00e1 o controlador. Este escolher\u00e1 um novo l\u00edder entre os followers. No entanto, o l\u00edder original continuar\u00e1 pensando que \u00e9 o l\u00edder e continuar\u00e1 aceitando registros com <i>acks=1<\/i>. Os followers n\u00e3o lhe enviam mais solicita\u00e7\u00f5es de recupera\u00e7\u00e3o, ent\u00e3o ele os considerar\u00e1 mortos e tentar\u00e1 comprimir o ISR at\u00e9 si mesmo. Mas como ele n\u00e3o tem conex\u00e3o com o Zookeeper, n\u00e3o conseguir\u00e1 fazer isso e, a esse ponto, desistir\u00e1 de aceitar mais registros. <\/p>\n<p>Mensagens <i>acks=all<\/i> n\u00e3o receber\u00e3o confirma\u00e7\u00f5es, porque inicialmente o ISR inclui todas as r\u00e9plicas, e as mensagens n\u00e3o chegam a elas. Quando o l\u00edder original tentar remov\u00ea-las do ISR, n\u00e3o conseguir\u00e1 e, de fato, deixar\u00e1 de aceitar qualquer mensagem.<\/p>\n<p>Os clientes logo percebem a troca de l\u00edder e come\u00e7am a enviar registros para o novo servidor. Assim que a rede se restabelece, o l\u00edder original v\u00ea que n\u00e3o \u00e9 mais o l\u00edder e corta seu log para o valor do HW que o novo l\u00edder tinha no momento da falha, para evitar a diverg\u00eancia de logs. Ent\u00e3o, come\u00e7ar\u00e1 a enviar solicita\u00e7\u00f5es para o novo l\u00edder. Todos os registros do l\u00edder original que n\u00e3o foram replicados para o novo l\u00edder se perdem. Ou seja, mensagens que n\u00e3o foram confirmadas pelo l\u00edder original nos poucos segundos em que funcionaram dois l\u00edderes ser\u00e3o perdidas.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/d88d6f33c13dccb814c0f206ec72512b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 29. Cen\u00e1rio 4. O l\u00edder no broker 1 torna-se follower ap\u00f3s a recupera\u00e7\u00e3o da rede<\/i><\/p>\n<h3>Cen\u00e1rio 5. O follower est\u00e1 completamente isolado tanto de outros n\u00f3s Kafka quanto do Zookeeper<\/h3>\n<p>\nO follower est\u00e1 completamente isolado tanto de outros n\u00f3s Kafka quanto do Zookeeper. Ele simplesmente \u00e9 removido do ISR at\u00e9 que a rede se restabele\u00e7a, e depois alcan\u00e7a os demais.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/b092607f777014fd945f18734dd7f4e7.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 30. Cen\u00e1rio 5. O follower isolado \u00e9 removido do ISR<\/i><\/p>\n<h3>Cen\u00e1rio 6. O l\u00edder est\u00e1 totalmente isolado de outros n\u00f3s Kafka e do Zookeeper<\/h3>\n<p>\n<img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/bb808d534dbf65748eb0b481f86b4926.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 31. Cen\u00e1rio 6. L\u00edder e dois followers<\/i><\/p>\n<p>O l\u00edder est\u00e1 completamente isolado de seus followers, do controlador e do Zookeeper. Por um breve per\u00edodo, continuar\u00e1 aceitando registros com <i>acks=1<\/i>.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/6fda78bcd26ef6b916579d447e9fb1f0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 32. Cen\u00e1rio 6. Isolamento do l\u00edder de outros n\u00f3s Kafka e do Zookeeper<\/i><\/p>\n<p>N\u00e3o recebendo solicita\u00e7\u00f5es ap\u00f3s <i>replica.lag.time.max.ms<\/i>, ele tentar\u00e1 contrair o ISR para si mesmo, mas n\u00e3o conseguir\u00e1, pois n\u00e3o h\u00e1 conex\u00e3o com o Zookeeper, ent\u00e3o ele deixar\u00e1 de aceitar registros. <\/p>\n<p>Enquanto isso, o Zookeeper marcar\u00e1 o broker isolado como morto, e o controlador escolher\u00e1 um novo l\u00edder.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/73d611a411fc64d835af2c714e9eba0a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 33. Cen\u00e1rio 6. Dois l\u00edderes<\/i><\/p>\n<p>O l\u00edder original pode aceitar registros por alguns segundos, mas depois para de aceitar quaisquer mensagens. Os clientes atualizam a cada 60 segundos com os \u00faltimos metadados. Eles ser\u00e3o informados sobre a troca de l\u00edder e come\u00e7ar\u00e3o a enviar registros para o novo l\u00edder.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/ae99380c8a84fac15f440b699b9c552b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 34. Cen\u00e1rio 6. Produtores mudam para o novo l\u00edder<\/i><\/p>\n<p>Todas as grava\u00e7\u00f5es confirmadas feitas pelo l\u00edder original desde a perda de conectividade ser\u00e3o perdidas. Assim que a rede for restaurada, o l\u00edder original, atrav\u00e9s do Zookeeper, descobrir\u00e1 que n\u00e3o \u00e9 mais o l\u00edder. Em seguida, ele truncar\u00e1 seu log at\u00e9 o HW do novo l\u00edder no momento da elei\u00e7\u00e3o e come\u00e7ar\u00e1 a enviar solicita\u00e7\u00f5es como seguidor.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ vs Kafka: Fault Tolerance and High Availability\" src=\"\/wp-content\/uploads\/2019\/11\/10f0983a829b03ca9bbc62e12cbf8a5d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 35. Cen\u00e1rio 6. O l\u00edder original se torna um seguidor ap\u00f3s a restaura\u00e7\u00e3o da conectividade da rede<\/i><\/p>\n<p>Nesta situa\u00e7\u00e3o, por um curto per\u00edodo, pode haver uma divis\u00e3o l\u00f3gica, mas apenas se <i>acks=1<\/i> e <i>min.insync.replicas<\/i> tamb\u00e9m 1. A divis\u00e3o l\u00f3gica se encerra automaticamente ou ap\u00f3s a restaura\u00e7\u00e3o da rede, quando o l\u00edder original percebe que n\u00e3o \u00e9 mais l\u00edder, ou quando todos os clientes entendem que o l\u00edder mudou e come\u00e7am a escrever ao novo l\u00edder \u2014 dependendo do que acontece primeiro. De qualquer forma, ocorrer\u00e1 a perda de algumas mensagens, mas apenas com <i>acks=1<\/i>.<\/p>\n<p>H\u00e1 outra varia\u00e7\u00e3o deste cen\u00e1rio, onde, imediatamente antes da divis\u00e3o da rede, os seguidores se atrasaram, e o l\u00edder reduziu o ISR a apenas ele mesmo. Em seguida, ele se isola devido \u00e0 perda de conectividade. Um novo l\u00edder \u00e9 eleito, mas o l\u00edder original continua recebendo grava\u00e7\u00f5es, mesmo <i>acks=all<\/i>, porque n\u00e3o h\u00e1 mais ningu\u00e9m no ISR al\u00e9m dele. Essas grava\u00e7\u00f5es ser\u00e3o perdidas ap\u00f3s a recupera\u00e7\u00e3o da rede. A \u00fanica maneira de evitar tal cen\u00e1rio \u00e9 <i>min.insync.replicas = 2<\/i>.<\/p>\n<h3>Cen\u00e1rio 7. O controlador Kafka n\u00e3o v\u00ea outro n\u00f3 Kafka<\/h3>\n<p>\nDe maneira geral, ap\u00f3s perder a conex\u00e3o com o n\u00f3 Kafka, o controlador n\u00e3o conseguir\u00e1 enviar qualquer informa\u00e7\u00e3o sobre a mudan\u00e7a de l\u00edder. No pior cen\u00e1rio, isso levar\u00e1 a uma divis\u00e3o l\u00f3gica de curto prazo, como no cen\u00e1rio 6. Na maioria das vezes, o broker simplesmente n\u00e3o se tornar\u00e1 um candidato a lideran\u00e7a em caso de falha do \u00faltimo.<\/p>\n<h3>Cen\u00e1rio 8. O controlador Kafka n\u00e3o v\u00ea o Zookeeper<\/h3>\n<p>\nO controlador que caiu n\u00e3o receber\u00e1 o ping do Zookeeper e eleger\u00e1 um novo n\u00f3 Kafka como controlador. O controlador original pode continuar se apresentando como tal, mas n\u00e3o receber\u00e1 notifica\u00e7\u00f5es do Zookeeper, portanto n\u00e3o ter\u00e1 tarefas a cumprir. Assim que a rede for restaurada, ele perceber\u00e1 que n\u00e3o \u00e9 mais o controlador e se tornou um n\u00f3 Kafka comum.<\/p>\n<h3>Conclus\u00f5es dos cen\u00e1rios<\/h3>\n<p>\nObservamos que a perda de conectividade dos seguidores n\u00e3o leva \u00e0 perda de mensagens, mas simplesmente reduz temporariamente a redund\u00e2ncia at\u00e9 que a rede seja restaurada. Isso, \u00e9 claro, pode resultar em perda de dados se um ou mais n\u00f3s forem perdidos.<\/p>\n<p>Se, devido \u00e0 perda de conectividade, o l\u00edder se desligar do Zookeeper, isso pode levar \u00e0 perda de mensagens com <i>acks=1<\/i>. A aus\u00eancia de conex\u00e3o com o Zookeeper provoca uma breve divis\u00e3o l\u00f3gica com dois l\u00edderes. Este problema \u00e9 resolvido pelo par\u00e2metro <i>acks=all<\/i>.<\/p>\n<p>Par\u00e2metro <i>min.insync.replicas<\/i> com duas ou mais r\u00e9plicas que oferece garantias adicionais de que tais cen\u00e1rios de curto prazo n\u00e3o levar\u00e3o \u00e0 perda de mensagens, como no cen\u00e1rio 6.<\/p>\n<h1>Resumo sobre a perda de mensagens<\/h1>\n<p>\nVamos listar todas as maneiras pelas quais os dados podem ser perdidos no Kafka:<\/p>\n<ul>\n<li>Qualquer falha do l\u00edder, se as mensagens forem confirmadas com <i>acks=1<\/i>\n<\/li>\n<li>Qualquer transi\u00e7\u00e3o suja (unclean) de lideran\u00e7a, ou seja, para um seguidor fora do ISR, mesmo com <i>acks=all<\/i>\n<\/li>\n<li>A exclus\u00e3o do l\u00edder do Zookeeper, se as mensagens forem confirmadas com <i>acks=1<\/i>\n<\/li>\n<li>Isolamento completo do l\u00edder, que j\u00e1 reduziu o grupo ISR apenas a si mesmo. Todas as mensagens ser\u00e3o perdidas, mesmo <i>acks=all<\/i>. Isso \u00e9 verdade apenas se <i>min.insync.replicas=1<\/i>.\n<\/li>\n<li>Falhas simult\u00e2neas de todos os n\u00f3s da parti\u00e7\u00e3o. Como as mensagens s\u00e3o confirmadas na mem\u00f3ria, algumas podem ainda n\u00e3o ter sido gravadas em disco. Ap\u00f3s a reinicializa\u00e7\u00e3o dos servidores, algumas mensagens podem estar ausentes.<\/li>\n<\/ul>\n<p>\nTransi\u00e7\u00f5es sujas de lideran\u00e7a podem ser evitadas, seja proibindo-as ou garantindo redund\u00e2ncia de pelo menos duas. A configura\u00e7\u00e3o mais robusta \u00e9 uma combina\u00e7\u00e3o de <i>acks=all<\/i> e <i>min.insync.replicas<\/i> mais de 1.<\/p>\n<h1>Compara\u00e7\u00e3o direta da confiabilidade entre RabbitMQ e Kafka<\/h1>\n<p>\nPara garantir confiabilidade e alta disponibilidade, ambas as plataformas implementam um sistema de replica\u00e7\u00e3o prim\u00e1ria e secund\u00e1ria. No entanto, o RabbitMQ possui um calcanhar de Aquiles. Ao se reconectar ap\u00f3s uma falha, os n\u00f3s descartam seus dados e a sincroniza\u00e7\u00e3o \u00e9 bloqueada. Esse duplo golpe questiona a durabilidade de grandes filas no RabbitMQ. Voc\u00ea ter\u00e1 que se contentar com a redu\u00e7\u00e3o da redund\u00e2ncia ou com longos bloqueios. A redu\u00e7\u00e3o da redund\u00e2ncia aumenta o risco de perda massiva de dados. Mas se as filas forem pequenas, para garantir redund\u00e2ncia com per\u00edodos curtos de indisponibilidade (alguns segundos), isso pode ser resolvido com tentativas de reconex\u00e3o.<\/p>\n<p>No Kafka n\u00e3o tem esse problema. Ela descarta dados apenas no ponto de diverg\u00eancia entre o l\u00edder e o seguidor. Todos os dados comuns s\u00e3o mantidos. Al\u00e9m disso, a replica\u00e7\u00e3o n\u00e3o bloqueia o sistema. O l\u00edder continua a aceitar grava\u00e7\u00f5es enquanto um novo seguidor o alcan\u00e7a, tornando a conex\u00e3o ou reconex\u00e3o do cluster uma tarefa trivial para os devops. Claro, ainda existem problemas, como a largura de banda da rede durante a replica\u00e7\u00e3o. Se v\u00e1rios seguidores s\u00e3o adicionados ao mesmo tempo, pode-se enfrentar o limite de largura de banda.<\/p>\n<p>RabbitMQ supera Kafka em confiabilidade durante a falha simult\u00e2nea de v\u00e1rios servidores em um cluster. Como j\u00e1 mencionamos, o RabbitMQ envia uma confirma\u00e7\u00e3o ao publicador somente ap\u00f3s gravar a mensagem no disco do mestre e em todas as c\u00f3pias. Mas isso adiciona uma lat\u00eancia extra por duas raz\u00f5es:<\/p>\n<ul>\n<li>fsync a cada algumas centenas de milissegundos\n<\/li>\n<li>Falhas nas c\u00f3pias s\u00f3 podem ser notadas ap\u00f3s o tempo de vida dos pacotes, que verificam a disponibilidade de cada n\u00f3 (net tick). Se a c\u00f3pia estiver lenta ou falhar, isso adiciona uma lat\u00eancia.<\/li>\n<\/ul>\n<p>\nKafka aposta que se a mensagem \u00e9 armazenada em v\u00e1rios n\u00f3s, pode-se confirmar mensagens assim que elas entram na mem\u00f3ria. Isso cria o risco de perda de mensagens de qualquer tipo (at\u00e9 mesmo <i>acks=all<\/i>, <i>min.insync.replicas=2<\/i>) em caso de falha simult\u00e2nea.<\/p>\n<p>De forma geral, a Kafka demonstra melhor desempenho e \u00e9 projetada inicialmente para clusters. O n\u00famero de seguidores pode ser aumentado para 11 se necess\u00e1rio para confiabilidade. Uma taxa de replica\u00e7\u00e3o de 5 e um n\u00famero m\u00ednimo de r\u00e9plicas em estado sincronizado <i>min.insync.replicas=3<\/i> tornam a perda de mensagens um evento muito raro. Se sua infraestrutura pode garantir tal taxa de replica\u00e7\u00e3o e n\u00edvel de redund\u00e2ncia, voc\u00ea pode escolher essa op\u00e7\u00e3o.<\/p>\n<p>A clusteriza\u00e7\u00e3o do RabbitMQ \u00e9 boa para filas pequenas. Mas at\u00e9 mesmo filas pequenas podem crescer rapidamente em grandes tr\u00e1fegos. Assim que as filas se tornam grandes, ser\u00e1 necess\u00e1rio fazer uma escolha dif\u00edcil entre disponibilidade e confiabilidade. A clusteriza\u00e7\u00e3o do RabbitMQ \u00e9 mais adequada para situa\u00e7\u00f5es menos t\u00edpicas, onde as vantagens da flexibilidade do RabbitMQ superam as desvantagens de sua clusteriza\u00e7\u00e3o.<\/p>\n<p>Uma das solu\u00e7\u00f5es para a vulnerabilidade do RabbitMQ em rela\u00e7\u00e3o a filas grandes \u00e9 dividi-las em v\u00e1rias menores. Se n\u00e3o exigir a completa ordena\u00e7\u00e3o de toda a fila, mas apenas das mensagens relevantes (por exemplo, mensagens de um cliente espec\u00edfico), ou at\u00e9 mesmo n\u00e3o ordenar nada, essa abordagem \u00e9 aceit\u00e1vel: veja meu projeto <noindex><a rel=\"nofollow\" href=\"https:\/\/jack-vanlightly.com\/blog\/2018\/7\/22\/creating-consumer-groups-in-rabbitmq-with-rebalanser-part-1\">Rebalanceador<\/a><\/noindex> para a divis\u00e3o da fila (o projeto ainda est\u00e1 em fase inicial). <\/p>\n<p>Por fim, n\u00e3o se esque\u00e7a de uma s\u00e9rie de bugs nos mecanismos de clusteriza\u00e7\u00e3o e replica\u00e7\u00e3o tanto do RabbitMQ quanto do Kafka. Com o tempo, os sistemas se tornaram mais maduros e est\u00e1veis, mas nenhuma mensagem estar\u00e1 100% protegida contra perda! Al\u00e9m disso, grandes falhas ocorrem nos data centers!<\/p>\n<p>Se eu perdi algo, cometi um erro ou voc\u00ea discorda de qualquer uma das afirma\u00e7\u00f5es, n\u00e3o hesite em deixar um coment\u00e1rio ou entrar em contato comigo.<\/p>\n<p>Muitas vezes me perguntam: \u201cO que escolher, Kafka ou RabbitMQ?\u201d, \u201cQual plataforma \u00e9 melhor?\u201d. A verdade \u00e9 que isso realmente depende da sua situa\u00e7\u00e3o, experi\u00eancia atual, etc. N\u00e3o me atrevo a expressar minha opini\u00e3o, pois seria uma grande simplifica\u00e7\u00e3o recomendar uma \u00fanica plataforma para todos os casos de uso e poss\u00edveis limita\u00e7\u00f5es. Escrevi esse ciclo de artigos para que voc\u00ea possa formar sua pr\u00f3pria opini\u00e3o.<\/p>\n<p>Quero destacar que ambos os sistemas s\u00e3o l\u00edderes na \u00e1rea. Talvez eu esteja um pouco enviesado, pois, com base na experi\u00eancia dos meus projetos, valorizo mais coisas como a garantia de ordena\u00e7\u00e3o de mensagens e confiabilidade. <\/p>\n<p>Vejo outras tecnologias que carecem dessa confiabilidade e garantia de ordena\u00e7\u00e3o, ent\u00e3o olho para o RabbitMQ e Kafka \u2014 e reconhe\u00e7o o valor incr\u00edvel de ambos esses sistemas.<br \/>\n<br \/>Fonte: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/itsumma\/blog\/474984\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u044e RabbitMQ \u0434\u043b\u044f \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f \u043e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u0438 \u0438 \u0432\u044b\u0441\u043e\u043a\u043e\u0439 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u0438. \u0422\u0435\u043f\u0435\u0440\u044c \u0433\u043b\u0443\u0431\u043e\u043a\u043e \u043f\u043e\u043a\u043e\u043f\u0430\u0435\u043c\u0441\u044f \u0432 Apache Kafka. \u0417\u0434\u0435\u0441\u044c \u0435\u0434\u0438\u043d\u0438\u0446\u0435\u0439 \u0440\u0435\u043f\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0440\u0430\u0437\u0434\u0435\u043b (partition). \u0423 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u043e\u043f\u0438\u043a\u0430 \u043e\u0434\u0438\u043d \u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u043e\u0432. \u0412 \u043a\u0430\u0436\u0434\u043e\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u0435\u0441\u0442\u044c \u043b\u0438\u0434\u0435\u0440 \u0441 \u0444\u043e\u043b\u043b\u043e\u0432\u0435\u0440\u0430\u043c\u0438 \u0438\u043b\u0438 \u0431\u0435\u0437 \u043d\u0438\u0445. \u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0442\u043e\u043f\u0438\u043a\u0430 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u043e\u0432 \u0438 \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0440\u0435\u043f\u043b\u0438\u043a\u0430\u0446\u0438\u0438. \u041e\u0431\u044b\u0447\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 3, \u044d\u0442\u043e [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-52541","post","type-post","status-publish","format-standard","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.3 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0412\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/rabbitmq-protiv-kafka-otkazoustojchivost-i-vysokaya-dostupnost\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"pt_PT\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47RabbitMQ \u043f\u0440\u043e\u0442\u0438\u0432 Kafka: \u043e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u044c \u0438 \u0432\u044b\u0441\u043e\u043a\u0430\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u044c | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/rabbitmq-protiv-kafka-otkazoustojchivost-i-vysokaya-dostupnost\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-11-10T21:00:00+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-02-18T11:00:17+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47RabbitMQ vs Kafka: toler\u00e2ncia a falhas e alta disponibilidade | ProHoster","description":"Em","canonical_url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/rabbitmq-protiv-kafka-otkazoustojchivost-i-vysokaya-dostupnost","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"pt_PT","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47RabbitMQ \u043f\u0440\u043e\u0442\u0438\u0432 Kafka: \u043e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u044c \u0438 \u0432\u044b\u0441\u043e\u043a\u0430\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u044c | ProHoster","og:description":"\u0412","og:url":"https:\/\/prohoster.info\/pt\/blog\/administrirovanie\/rabbitmq-protiv-kafka-otkazoustojchivost-i-vysokaya-dostupnost","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-11-10T21:00:00+00:00","article:modified_time":"2020-02-18T11:00:17+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"52541","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-24 03:57:21","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 20:41:24","updated":"2026-01-24 03:57:22","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/52541","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/comments?post=52541"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/posts\/52541\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/media?parent=52541"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/categories?post=52541"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/pt\/wp-json\/wp\/v2\/tags?post=52541"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}