O Apache Kafka é uma plataforma de fluxo de eventos altamente escalável de alto desempenho. Para liberar todo o potencial do Kafka, você precisa considerar cuidadosamente o projeto de sua aplicação. É muito fácil escrever aplicações Kafka que funcionam mal ou que acabam enfrentando um obstáculo de escalabilidade. Desde 2015, a IBM fornece o serviço IBM® Event Streams, que é um serviço Apache Kafka totalmente gerenciado executado no IBM Cloud. Desde então, o serviço ajudou muitos clientes, bem como equipes da IBM, a resolver problemas de escalabilidade e desempenho com as aplicações Kafka que eles escreveram.
Este artigo descreve alguns dos problemas comuns do Kafka e fornece algumas recomendações sobre como evitar problemas de escalabilidade em suas aplicações.
Algumas operações do Kafka funcionam pelo cliente enviando dados ao broker e aguardando uma resposta. Uma viagem de ida e volta completa pode levar 10 milissegundos, o que parece rápido, mas limita você a no máximo 100 operações por segundo. Por esse motivo, é recomendável que você tente evitar esses tipos de operações sempre que possível. Felizmente, os clientes do Kafka oferecem maneiras para que você evite esperar esses tempos de ida e volta. Você só precisa garantir que está aproveitando elas.
Dicas para maximizar o rendimento:
Se você leu o texto acima e pensou: "Ah, isso não vai deixar minha aplicação mais complexa?", a resposta é sim, provavelmente sim. Há um equilíbrio entre rendimento e complexidade da aplicação. O que torna o tempo de ida e volta da rede uma armadilha particularmente insidiosa é que, uma vez que você atingiu esse limite, pode ser necessário alterar extensamente a aplicação para alcançar melhorias adicionais na taxa de transferência.
Uma funcionalidade útil do Kafka é que ele monitora a "vivacidade" das aplicações de consumo e desconecta qualquer uma que possa ter falhado. Isso funciona fazendo com que o broker acompanhe quando cada cliente consumidor fez a última "pesquisa" (a terminologia do Kafka para solicitar mais mensagens). Se um cliente não fizer pesquisas com frequência suficiente, o broker ao qual está conectado conclui que ele deve ter falhado e o desconecta. Isso foi projetado para permitir que os clientes que não estão enfrentando problemas entrem e assumam o trabalho do cliente com problemas.
Infelizmente, com esse esquema, o broker do Kafka não consegue distinguir entre um cliente que está demorando muito para processar as mensagens recebidas e um cliente que realmente falhou. Considere uma aplicação que executa ciclos: 1) Chama pesquisas e recebe um lote de mensagens; ou 2) processa cada mensagem em lote, levando 1 segundo para processar cada mensagem.
Se esse consumidor estiver recebendo lotes de 10 mensagens, serão aproximadamente 10 segundos entre as chamadas para a pesquisa. Por padrão, o Kafka permite até 300 segundos (5 minutos) entre as pesquisas antes de desconectar o cliente, então tudo funcionaria bem nesse cenário. Mas o que acontece em um dia realmente movimentado quando um backlog de mensagens começa a se formar sobre o tópico que a aplicação está consumindo? Em vez de apenas receber 10 mensagens de cada chamada de pesquisa, sua aplicação recebe 500 mensagens (por padrão, esse é o número máximo de registros que podem ser retornados por uma chamada para pesquisa). Isso resultaria em tempo de processamento suficiente para o Kafka decidir que a instância da aplicação falhou e desconectá-la. Isso é uma má notícia.
Você ficará encantado em saber que a situação pode piorar. É possível que ocorra uma espécie de ciclo de feedback. À medida que o Kafka começa a desconectar clientes porque eles não estão chamando pesquisas com frequência suficiente, há menos instâncias da aplicação para processar as mensagens. A probabilidade de haver um grande backlog de mensagens sobre o tópico aumenta, levando a uma maior probabilidade de que mais clientes recebam grandes lotes de mensagens e demorem muito tempo para processá-las. Eventualmente, todas as instâncias da aplicação de consumo entram em um ciclo de reinicialização, e nenhum trabalho útil é feito.
Que medidas você pode tomar para evitar que isso aconteça com você?
Retornaremos ao tópico das falhas do consumidor mais adiante neste artigo, quando analisarmos como elas podem desencadear o reequilíbrio do grupo de consumidores e o efeito disruptivo que isso pode ter.
Detalhes técnicos, o protocolo usado pelo consumidor do Kafka para receber mensagens funciona enviando uma solicitação de “busca” a um broker do Kafka. Como parte dessa solicitação, o cliente indica o que o broker deve fazer se não houver mensagens para devolver, incluindo quanto tempo o broker deve esperar antes de enviar uma resposta vazia. Por padrão, os consumidores do Kafka instruem os brokers a esperar até 500 milissegundos (controlados pelo método "fetch.max.wait.ms" configuração do consumidor) para que pelo menos 1 byte de dados da mensagem se torne disponível (controlado com o comando "fetch.min.bytes" configuração).
Esperar 500 milissegundos não parece ser razoável, mas se a sua aplicação tiver consumidores que estão em sua maioria ociosos e escalar para 5.000 instâncias, isso representa potencialmente 2.500 solicitações por segundo para não fazer absolutamente nada. Cada uma dessas solicitações leva tempo da CPU no broker para ser processada e, em casos extremos, pode afetar o desempenho e a estabilidade dos clientes do Kafka que desejam realizar um trabalho útil.
Normalmente, a abordagem do Kafka para o dimensionamento é adicionar mais brokers e, em seguida, reequilibrar uniformemente as partições de tópicos em todos os brokers, tanto os antigos quanto os novos. Infelizmente, essa abordagem pode não ajudar se seus clientes estiverem bombardeando o Kafka com solicitações de busca desnecessárias. Cada cliente enviará solicitações de busca a todos os brokers que lideram uma partição de tópico da qual o cliente está consumindo mensagens. Portanto, é possível que, mesmo depois de dimensionar o cluster do Kafka e redistribuir as partições, a maioria de seus clientes envie solicitações de busca para a maioria dos brokers.
Então, o que você pode fazer?
Se você chega ao Kafka vindo de um histórico com outros sistemas de publicação-assinatura (por exemplo, Message Queuing Telemetry Transport, ou MQTT para abreviar), então pode você esperar que os tópicos do Kafka sejam muito leves, quase efêmeros. Mas não são. O Kafka fica muito mais confortável com um número de tópicos medidos em milhares. Também espera-se que os tópicos do Kafka tenham uma vida relativamente longa. Práticas como criar um tópico para receber uma única mensagem de resposta e, em seguida, excluir o tópico, são incomuns com o Kafka e não aproveitam os pontos fortes do Kafka.
Em vez disso, planeje tópicos de longa duração. Talvez eles compartilhem o tempo de vida de uma aplicação ou de uma atividade. Também procure limitar o número de tópicos a centenas ou talvez milhares. Isso pode exigir uma perspectiva diferente sobre quais mensagens são intercaladas sobre um determinado tópico.
Uma pergunta relacionada que surge com frequência é: "Quantas partições meu tópico deve ter?" Tradicionalmente, o conselho é superestimar, porque adicionar partições após a criação de um tópico não altera o particionamento dos dados existentes mantidos no tópico (e, portanto, pode afetar os consumidores que dependem do particionamento para oferecer ordenação de mensagens dentro de uma partição). Este é um bom conselho; no entanto, gostaríamos de sugerir algumas considerações adicionais:
A maioria das aplicações do Kafka que consomem mensagens aproveite os recursos do grupo de consumidores do Kafka para coordenar quais clientes consomem de quais partições de tópico. Se sua memória sobre os grupos de consumidores é um pouco imprecisa, aqui está uma atualização rápida sobre os pontos principais:
À medida que o Kafka amadureceu, algoritmos de reequilíbrio cada vez mais sofisticados foram (e continuam sendo) desenvolvidos. Nas versões iniciais do Kafka, quando um grupo de consumidores era reequilibrado, todos os clientes do grupo tinham que parar de consumir, as partições de tópicos eram redistribuídas entre os novos membros do grupo e todos os clientes começavam a consumir novamente. Essa abordagem tem duas desvantagens (não se preocupe, elas foram aprimoradas desde então):
Algoritmos de reequilíbrio mais recentes fizeram melhorias significativas, para usar a terminologia de Kafka, adicionando "aderência" e "cooperação":
Apesar dessas melhorias em algoritmos de reequilíbrio mais recentes, se suas aplicações estiverem frequentemente sujeitas a reequilíbrios de grupo de consumidores, você ainda verá um impacto na taxa de transferência geral das mensagens e desperdiçará largura de banda de rede à medida que os clientes descartam e buscam dados de mensagens em buffer. Veja aqui algumas sugestões sobre o que você pode fazer:
Mantenha-se atualizado sobre as tendências mais importantes (e intrigantes) do setor em IA, automação, dados e muito mais com o boletim informativo Think. Consulte a Declaração de privacidade da IBM.
Agora você é especialista em escalar aplicações do Kafka. Você está convidado a colocar esses pontos em prática e experimentar a oferta totalmente gerenciada do Kafka na IBM Cloud. Para quaisquer desafios na configuração, consulte o Guia de Introdução e as Perguntas Frequentes.
O IBM Event Streams é um software de fluxo de eventos construído no Apache Kafka de código aberto. Está disponível como um serviço totalmente gerenciado na IBM Cloud ou para auto-hospedagem.
Libere o potencial dos negócios com as soluções de integração da IBM, interligando aplicações e sistemas para acessar dados críticos com rapidez e segurança.
Libere novos recursos e aumente a agilidade dos negócios com os serviços de consultoria em nuvem da IBM.