![Search icon](https://hackernoon.imgix.net/search-new.png?w=19&h=19)
Neste artigo apresento um estudo comparando ambientes para Apache Kafka. O objetivo final é encontrar a configuração mais eficaz e alcançar a melhor relação preço-desempenho.
Nossa plataforma de dados fornece serviços gerenciados para construção de plataformas analíticas para grandes conjuntos de dados, competindo com outras soluções de mercado. Para nos mantermos competitivos, realizamos regularmente pesquisas internas para identificar e melhorar os nossos pontos fortes, garantindo melhores negócios. Este artigo apresenta um desses estudos. Atualmente, nossa plataforma oferece suporte a AWS e GCP como provedores de nuvem. Ambos oferecem múltiplas gerações de computação e duas arquiteturas de CPU (x86 com Intel e AMD e ARM). Comparo essas configurações usando várias Java Virtual Machines (JVMs) para avaliar o desempenho de novas versões em processadores mais recentes.
Se você quer um TL; DR: ARM é demais. Arquitetura moderna e cara nem sempre significa “melhor”. Você pode ir direto para os resultados ou saber mais sobre a metodologia e configuração.
Considerei testar o desempenho com nosso próprio serviço, mas queria compará-lo em diferentes ambientes para os quais ainda não oferecemos suporte. Eu queria conferir novas máquinas virtuais, regiões e até mesmo outros provedores de nuvem. Então, comecei implementando um projeto de brinquedo que usa Kafka básico com diferentes imagens de contêiner base. Dessa forma, posso executar ferramentas de benchmark em hardware específico e medir o desempenho.
Pretendo testar várias configurações para identificar os resultados mais interessantes. Para isso, utilizo a ideia da matriz de testes para filtrar os resultados iniciais. Analisarei essas descobertas em profundidade usando ferramentas como perf e eBPF para refinar ainda mais o desempenho.
Vamos primeiro descrever os objetivos do teste. Tenho muita experiência com OpenJDK JVM, mas hoje existem muitas alternativas da Microsoft, Amazon e outras empresas. O Amazon Correto, por exemplo, inclui recursos extras e patches otimizados para AWS. Como a maioria dos nossos clientes usa AWS, eu queria incluir o Amazon Correto nos testes para ver o desempenho dessas JVMs nessa plataforma.
Eu escolhi essas versões para a primeira comparação:
Definidas as versões, preparei alguns scripts para construir imagens Kafka usando Amazon Correto e OpenJDK .
Para os testes de benchmarking, alterei as configurações do Kafka para focar em métricas de desempenho específicas. Eu queria testar diferentes combinações de [JVM] x [instance_type] x [architecture] x [cloud_provider] , por isso era importante minimizar os efeitos da conectividade de rede e do desempenho do disco. Fiz isso executando contêineres com tmpfs para armazenamento de dados:
podman run -ti \ --network=host \ --mount type=tmpfs,destination=/tmp \ kfbench:3.6.1-21.0.2-amzn-arm64
Naturalmente, esta configuração não se destina à produção, mas foi necessário isolar os gargalos de CPU e memória. A melhor maneira é remover influências de rede e disco dos testes. Caso contrário, esses fatores distorceriam os resultados.
Usei a ferramenta de benchmark na mesma instância para garantir latência mínima e maior reprodutibilidade. Também tentei testes sem configurações de rede host e com redes virtuais isoladas em cgroup, mas isso apenas adicionou latência desnecessária e aumentou o uso da CPU para encaminhamento de pacotes.
Embora o tmpfs aloque memória dinamicamente e possa causar fragmentação e latência, ele foi adequado para nosso teste. Eu poderia ter usado o ramdisk, que aloca memória estaticamente e evita esses problemas, mas o tmpfs foi mais fácil de implementar e ainda forneceu os insights que procurávamos. Para os nossos propósitos, atingiu o equilíbrio certo.
Além disso, apliquei algumas configurações extras do Kafka para remover dados da memória com mais frequência:
############################# Benchmark Options ############################# # https://kafka.apache.org/documentation/#brokerconfigs_log.segment.bytes # Chaged from 1GB to 256MB to rotate files faster log.segment.bytes = 268435456 # https://kafka.apache.org/documentation/#brokerconfigs_log.retention.bytes # Changed from -1 (unlimited) to 1GB evict them because we run in tmpfs log.retention.bytes = 1073741824 # Changed from 5 minutes (300000ms) to delete outdated data faster log.retention.check.interval.ms=1000 # Evict all data after 15 seconds (default is -1 and log.retention.hours=168 which is ~7 days) log.retention.ms=15000 # https://kafka.apache.org/documentation/#brokerconfigs_log.segment.delete.delay.ms # Changed from 60 seconds delay to small value to prevent memory overflows log.segment.delete.delay.ms = 0
Aqui está um resumo das mudanças:
Esta configuração não é adequada para uso em produção, mas é importante para nossos testes de benchmark, pois reduz os efeitos de fatores irrelevantes.
Na DoubleCloud, no momento em que este artigo foi escrito, oferecemos suporte a estas principais gerações de recursos de computação:
Para processadores Graviton, oferecemos suporte:
Além disso, testei instâncias t2a no GCP como alternativa ao Graviton no Ampere Altra. Não oferecemos isso aos nossos clientes devido ao suporte regional limitado da AWS, mas incluí-os nos benchmarks para comparar o desempenho. Esta pode ser uma boa opção se você estiver em uma das regiões “certas”.
Para benchmarking, desenvolvi uma ferramenta leve baseada na biblioteca franz-go e no exemplo . Esta ferramenta satura Kafka com eficiência sem se tornar um gargalo.
Embora o librdkafka seja conhecido por sua confiabilidade e popularidade, evitei-o devido a possíveis problemas com o cgo.
Kafka é conhecido por sua escalabilidade, permitindo que os tópicos sejam divididos em várias partições para distribuir eficientemente as cargas de trabalho horizontalmente entre os corretores. No entanto, concentrei-me na avaliação do desempenho de núcleo único para nosso foco específico na relação desempenho/preço.
Portanto, os testes utilizaram tópicos com partições únicas para utilizar plenamente os recursos principais individuais.
Cada caso de teste incluiu dois tipos:
Usei mensagens de 8 KB, maiores que o caso médio de um cliente, para saturar totalmente os threads de partição de tópico.
Apresento uma série de gráficos comparando diferentes casos de teste usando uma métrica de eficiência sintética para avaliar diferentes arquiteturas. Essa métrica quantifica milhões de linhas que podemos ingerir no corretor Kafka por cento , fornecendo uma avaliação direta da relação custo-benefício da arquitetura.
É importante reconhecer que os resultados reais podem variar devido aos descontos adicionais dos fornecedores de nuvem. Sempre que possível, os testes foram realizados em Frankfurt para ambos os fornecedores de cloud (ou nos Países Baixos, nos casos em que as opções de tipo de instância eram restritas).
Em todos os gráficos, uso nomes convencionais para instâncias, os mesmos que seus provedores usam. As instâncias são classificadas primeiro por provedores de nuvem (AWS e depois GCP) e depois por geração: da mais antiga para a mais recente.
Os resultados completos, embora em formato bruto, estão disponíveis em minha abrangente planilha de benchmarking . Lá você pode encontrar mais dados do que apresento neste artigo, incluindo números de latência e largura de banda e desempenho comparativo de diferentes JVMs.
As instâncias s1 de “1ª geração” baseadas na geração m5a com AMD EPYC 7571, que datam do terceiro trimestre de 2019, são nossa opção legada. Eles são os menos eficientes e mais lentos entre nossas opções em Frankfurt, custando aproximadamente ~0,2080 €/hora sob demanda. A transição para a família s2 mais recente, que custa aproximadamente 0,2070 €/hora, produz o dobro da eficiência por basicamente o mesmo preço. Incentivamos os clientes a migrar para essas opções mais econômicas e de melhor desempenho para melhorar os tempos de consulta e a velocidade de ingestão para aplicativos analíticos.
A família g1 é baseada no Graviton 2 e historicamente oferece um bom valor, mas a família s2 mais recente com processadores AMD agora corresponde ao seu nível de eficiência para Apache Kafka. Apesar de oferecer largura de banda um pouco menor e uma vantagem marginal de preço, a família g1 agora é considerada desatualizada em comparação com as opções mais recentes.
A família g2, alimentada por Graviton 3, destaca-se como nossa principal recomendação devido à sua eficiência superior. Ele supera as famílias s2 e i2 em até 39% em determinados cenários, oferecendo uma solução econômica em quase todas as regiões, tornando-o ideal para a maioria dos casos de uso do Apache Kafka. Dada a natureza típica de IO de Kafka, a otimização da eficiência computacional é crucial para a economia de custos. Tenho observado uma tendência crescente de adoção da arquitetura arm64, com quase metade dos nossos clusters já aproveitando esta tecnologia mais recente.
Os testes mostram que cada novo processador AMD ou Intel melhora em termos de rendimento e latência geral. Apesar disso, os ganhos de eficiência das novas gerações m6 e m7 estagnaram. Mesmo a geração m7, embora ofereça potencialmente menor latência em algumas regiões, fica aquém da eficiência em comparação com a família g2, de acordo com nossos testes.
A família m7a se destaca em aplicativos de baixa latência, superando as gerações Intel e AMD anteriores em termos de rendimento e latência. Embora não esteja disponível universalmente, esta arquitetura reflete o progresso da AMD na melhoria do desempenho. Se estiver disponível em sua região, considere o m7a para resultados superiores.
As instâncias do GCP geralmente têm eficiência menor do que as alternativas da AWS. Esse foi um ótimo insight para mim, já que os clientes normalmente preferem o GCP por sua economia em aplicações analíticas, resultando em contas mais baixas. Nossa família sg1 utiliza a geração padrão n2, comparável à família AWS s2. No entanto, a minha tentativa de estender esta comparação a outros tipos de instância foi limitada pela disponibilidade regional, especialmente para as gerações c3 e n2.
As instâncias Arm que usam os processadores Tau do GCP oferecem uma melhoria de eficiência de 5 a 7% em relação ao Graviton 2, tornando-as uma opção razoável de economia de custos, se disponível em sua região . Embora o suporte do GCP para instâncias arm seja limitado a quatro regiões, ele oferece desempenho e eficiência comparáveis à família g1.
Como os clusters Apache Kafka têm uso constante de VM, aproveitar os descontos por uso prolongado permite descontos de até 20%. Isso torna o poder computacional ainda mais antigo, como o Ampere Altra, competitivo com o Graviton 3 em termos de eficiência. No entanto, as comparações diretas são complicadas aqui devido aos descontos adicionais da AWS que também podem ser aplicados.
Achei que veria uma melhoria significativa com as versões mais recentes da JVM na arquitetura ARM. No entanto, parece que o openjdk-11 e o corretto-11 já estão bastante otimizados para ARM. Como as versões mais recentes do Kafka exigem Java 17 e superior, mudei para o Java 17, o que resultou em um ganho de desempenho de aproximadamente 4 a 8% em nossos benchmarks.
Além disso, o 21.0.2-amzn parece promissor, oferecendo um aumento extra de desempenho de 10 a 20% em tipos de instância mais recentes.
De tempos em tempos, realizo pesquisas internas para encontrar soluções ideais para nossos clusters de produção e coletar insights úteis. A mudança para a arquitetura ARM é vantajosa para serviços gerenciados, pois economiza dinheiro e reduz o uso de energia.
Depender de ARMs já se mostrou benéfico, melhorando o desempenho e a eficiência de custos tanto do Serviço Gerenciado para Apache Kafka quanto do Serviço Gerenciado para ClickHouse. Esta pesquisa ajudou a refinar nossa matriz de testes, identificando os ambientes e áreas mais eficientes para otimização adicional. Estamos sempre nisso: ajustando e refinando os bastidores, e estou feliz em compartilhar nosso conhecimento com a comunidade. Fique atento!