Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Observação. trad.: Neste artigo, Banzai Cloud compartilha um exemplo de como seus utilitários personalizados podem ser usados ​​para tornar o Kafka mais fácil de usar no Kubernetes. As instruções a seguir ilustram como você pode determinar o tamanho ideal da sua infraestrutura e configurar o próprio Kafka para atingir o rendimento necessário.

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Apache Kafka é uma plataforma de streaming distribuída para a criação de sistemas de streaming em tempo real confiáveis, escaláveis ​​e de alto desempenho. Seus recursos impressionantes podem ser estendidos usando o Kubernetes. Para isso desenvolvemos Operador Kafka de código aberto e uma ferramenta chamada Supertubos. Eles permitem que você execute Kafka no Kubernetes e use seus vários recursos, como ajuste fino da configuração do corretor, escalonamento baseado em métrica com rebalanceamento, reconhecimento de rack, “soft” (gracioso) lançando atualizações, etc.

Experimente Supertubes em seu cluster:

curl https://getsupertubes.sh | sh и supertubes install -a --no-democluster --kubeconfig <path-to-eks-cluster-kubeconfig-file>

Ou entre em contato documentação. Você também pode ler sobre alguns dos recursos do Kafka, cujo trabalho é automatizado usando Supertubes e o operador Kafka. Já escrevemos sobre eles no blog:

Ao decidir implantar um cluster Kafka no Kubernetes, você provavelmente enfrentará o desafio de determinar o tamanho ideal da infraestrutura subjacente e a necessidade de ajustar sua configuração Kafka para atender aos requisitos de rendimento. O desempenho máximo de cada corretor é determinado pelo desempenho dos componentes da infraestrutura subjacente, como memória, processador, velocidade do disco, largura de banda da rede, etc.

Idealmente, a configuração do corretor deve ser tal que todos os elementos da infraestrutura sejam usados ​​em suas capacidades máximas. No entanto, na vida real esta configuração é bastante complexa. É mais provável que os usuários configurem os intermediários para maximizar o uso de um ou dois componentes (disco, memória ou processador). De modo geral, um corretor apresenta desempenho máximo quando sua configuração permite que o componente mais lento seja utilizado em toda a sua extensão. Dessa forma, podemos ter uma ideia aproximada da carga que uma corretora pode suportar.

Teoricamente, também podemos estimar o número de corretores necessários para lidar com uma determinada carga. Contudo, na prática existem tantas opções de configuração em diferentes níveis que é muito difícil (se não impossível) avaliar o desempenho potencial de uma configuração específica. Em outras palavras, é muito difícil planejar uma configuração baseada em um determinado desempenho.

Para usuários do Supertubes, normalmente adotamos a seguinte abordagem: começamos com alguma configuração (infraestrutura + configurações), depois medimos seu desempenho, ajustamos as configurações da corretora e repetimos o processo novamente. Isto acontece até que o componente mais lento da infraestrutura seja totalmente utilizado.

Desta forma, temos uma ideia mais clara de quantos brokers um cluster precisa para lidar com uma determinada carga (o número de brokers também depende de outros fatores, como o número mínimo de réplicas de mensagens para garantir resiliência, o número de partições líderes, etc.). Além disso, obtemos insights sobre quais componentes da infraestrutura exigem escalabilidade vertical.

Este artigo falará sobre as etapas que executamos para aproveitar ao máximo os componentes mais lentos nas configurações iniciais e medir o rendimento de um cluster Kafka. Uma configuração altamente resiliente requer pelo menos três agentes em execução (min.insync.replicas=3), distribuídos por três zonas de acessibilidade distintas. Para configurar, dimensionar e monitorar a infraestrutura Kubernetes, utilizamos nossa própria plataforma de gerenciamento de contêineres para nuvens híbridas - Pipeline. Suporta on-premise (bare metal, VMware) e cinco tipos de nuvens (Alibaba, AWS, Azure, Google, Oracle), bem como qualquer combinação deles.

Reflexões sobre a infraestrutura e configuração do cluster Kafka

Para os exemplos abaixo, escolhemos AWS como provedor de nuvem e EKS como distribuição Kubernetes. Uma configuração semelhante pode ser implementada usando P.K.E. - Distribuição Kubernetes da Banzai Cloud, certificada pela CNCF.

disco

Amazon oferece vários Tipos de volume EBS. No centro gp2 и io1 existem unidades SSD, no entanto, para garantir alto rendimento gp2 consome créditos acumulados (créditos de E/S), então preferimos o tipo io1, que oferece alto rendimento consistente.

Tipos de instância

O desempenho do Kafka é altamente dependente do cache de páginas do sistema operacional, portanto, precisamos de instâncias com memória suficiente para os brokers (JVM) e cache de páginas. Instância c5.2xgrande - um bom começo, pois possui 16 GB de memória e otimizado para trabalhar com EBS. Sua desvantagem é que ele só é capaz de fornecer desempenho máximo por no máximo 30 minutos a cada 24 horas. Se sua carga de trabalho exigir desempenho máximo durante um longo período de tempo, você poderá considerar outros tipos de instância. Foi exatamente isso que fizemos, parando em c5.4xgrande. Ele fornece rendimento máximo em 593,75 Mb/s. Taxa de transferência máxima de um volume EBS io1 maior que a instância c5.4xgrande, portanto, o elemento mais lento da infraestrutura provavelmente será a taxa de transferência de E/S desse tipo de instância (que nossos testes de carga também devem confirmar).

Сеть

A taxa de transferência da rede deve ser grande o suficiente em comparação com o desempenho da instância de VM e do disco, caso contrário a rede se tornará um gargalo. No nosso caso, a interface de rede c5.4xgrande oferece suporte a velocidades de até 10 Gb/s, o que é significativamente maior que a taxa de transferência de E/S de uma instância de VM.

Implantação do corretor

Os corretores devem ser implantados (agendados no Kubernetes) em nós dedicados para evitar competir com outros processos por recursos de CPU, memória, rede e disco.

Versão Java

A escolha lógica é Java 11 porque é compatível com Docker no sentido de que a JVM determina corretamente os processadores e a memória disponível para o contêiner no qual o broker está sendo executado. Sabendo que os limites da CPU são importantes, a JVM define interna e transparentemente o número de threads GC e threads JIT. Usamos a imagem Kafka banzaicloud/kafka:2.13-2.4.0, que inclui Kafka versão 2.4.0 (Scala 2.13) em Java 11.

Se você quiser saber mais sobre Java/JVM no Kubernetes, confira nossos seguintes posts:

Configurações de memória do corretor

Existem dois aspectos principais na configuração da memória do broker: configurações para a JVM e para o pod Kubernetes. O limite de memória definido para um pod deve ser maior que o tamanho máximo de heap para que a JVM tenha espaço para o metaespaço Java que reside em sua própria memória e para o cache de páginas do sistema operacional que o Kafka usa ativamente. Em nossos testes lançamos corretoras Kafka com parâmetros -Xmx4G -Xms2G, e o limite de memória do pod era 10 Gi. Observe que as configurações de memória para a JVM podem ser obtidas automaticamente usando -XX:MaxRAMPercentage и -X:MinRAMPercentage, com base no limite de memória do pod.

Configurações do processador do corretor

De modo geral, você pode melhorar o desempenho aumentando o paralelismo aumentando o número de threads usados ​​pelo Kafka. Quanto mais processadores disponíveis para Kafka, melhor. Em nosso teste, começamos com um limite de 6 processadores e gradualmente (por meio de iterações) aumentamos seu número para 15. Além disso, definimos num.network.threads=12 nas configurações do corretor para aumentar o número de threads que recebem dados da rede e os enviam. Descobrindo imediatamente que os corretores seguidores não poderiam receber réplicas com rapidez suficiente, eles levantaram num.replica.fetchers para 4 para aumentar a velocidade com que os corretores seguidores replicaram mensagens dos líderes.

Ferramenta de geração de carga

Você deve garantir que o gerador de carga selecionado não fique sem capacidade antes que o cluster Kafka (que está sendo avaliado) atinja sua carga máxima. Em outras palavras, é necessário realizar uma avaliação preliminar das capacidades da ferramenta de geração de carga, e também selecionar tipos de instâncias com número suficiente de processadores e memória. Nesse caso, nossa ferramenta produzirá mais carga do que o cluster Kafka pode suportar. Depois de muitos experimentos, decidimos por três cópias c5.4xgrande, cada um dos quais tinha um gerador funcionando.

avaliação comparativa

A medição de desempenho é um processo iterativo que inclui as seguintes etapas:

  • configuração de infraestrutura (cluster EKS, cluster Kafka, ferramenta de geração de carga, além de Prometheus e Grafana);
  • gerar uma carga por determinado período para filtrar desvios aleatórios nos indicadores de desempenho coletados;
  • ajustar a infraestrutura e configuração da corretora com base nos indicadores de desempenho observados;
  • repetir o processo até que o nível necessário de taxa de transferência do cluster Kafka seja alcançado. Ao mesmo tempo, deve ser reproduzível de forma consistente e demonstrar variações mínimas no rendimento.

A próxima seção descreve as etapas executadas durante o processo de benchmarking do cluster de teste.

Ferramentas

As ferramentas a seguir foram usadas para implantar rapidamente uma configuração de linha de base, gerar cargas e medir o desempenho:

  • Pipeline de nuvem Banzai para organizar um cluster EKS da Amazon c Prometeu (para coletar métricas de Kafka e de infraestrutura) e grafana (para visualizar essas métricas). Nós aproveitamos integrado в Pipeline serviços que fornecem monitoramento federado, coleta centralizada de logs, verificação de vulnerabilidades, recuperação de desastres, segurança de nível empresarial e muito mais.
  • Sanguenel — uma ferramenta para testar a carga de um cluster Kafka.
  • Painéis Grafana para visualizar métricas e infraestrutura Kafka: Kubernetes Kafka, Exportador de nós.
  • Supertubes CLI para a maneira mais fácil de configurar um cluster Kafka no Kubernetes. Zookeeper, operador Kafka, Envoy e muitos outros componentes estão instalados e configurados corretamente para executar um cluster Kafka pronto para produção no Kubernetes.
    • Para instalar supertubos CLI use as instruções fornecidas aqui.

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Cluster EKS

Prepare um cluster EKS com nós de trabalho dedicados c5.4xgrande em diferentes zonas de disponibilidade para pods com corretores Kafka, bem como nós dedicados para o gerador de carga e infraestrutura de monitoramento.

banzai cluster create -f https://raw.githubusercontent.com/banzaicloud/kafka-operator/master/docs/benchmarks/infrastructure/cluster_eks_202001.json

Assim que o cluster EKS estiver instalado e funcionando, ative seu integrado serviço de monitoramento – ela implantará Prometheus e Grafana em um cluster.

Componentes do sistema Kafka

Instale os componentes do sistema Kafka (Zookeeper, operador kafka) no EKS usando supertubes CLI:

supertubes install -a --no-democluster --kubeconfig <path-to-eks-cluster-kubeconfig-file>

Aglomerado Kafka

Por padrão, o EKS usa volumes EBS do tipo gp2, então você precisa criar uma classe de armazenamento separada com base em volumes io1 para cluster Kafka:

kubectl create -f - <<EOF
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: fast-ssd
provisioner: kubernetes.io/aws-ebs
parameters:
  type: io1
  iopsPerGB: "50"
  fsType: ext4
volumeBindingMode: WaitForFirstConsumer
EOF

Defina o parâmetro para corretores min.insync.replicas=3 e implantar pods de agente em nós em três zonas de disponibilidade diferentes:

supertubes cluster create -n kafka --kubeconfig <path-to-eks-cluster-kubeconfig-file> -f https://raw.githubusercontent.com/banzaicloud/kafka-operator/master/docs/benchmarks/infrastructure/kafka_202001_3brokers.yaml --wait --timeout 600

Tópicos

Executamos três instâncias do gerador de carga em paralelo. Cada um escreve sobre seu tema, ou seja, precisamos de três temas no total:

supertubes cluster topic create -n kafka --kubeconfig <path-to-eks-cluster-kubeconfig-file> -f -<<EOF
apiVersion: kafka.banzaicloud.io/v1alpha1
kind: KafkaTopic
metadata:
  name: perftest1
spec:
  name: perftest1
  partitions: 12
  replicationFactor: 3
  retention.ms: '28800000'
  cleanup.policy: delete
EOF

supertubes cluster topic create -n kafka --kubeconfig <path-to-eks-cluster-kubeconfig-file> -f -<<EOF
apiVersion: kafka.banzaicloud.io/v1alpha1
kind: KafkaTopic
metadata:
    name: perftest2
spec:
  name: perftest2
  partitions: 12
  replicationFactor: 3
  retention.ms: '28800000'
  cleanup.policy: delete
EOF

supertubes cluster topic create -n kafka --kubeconfig <path-to-eks-cluster-kubeconfig-file> -f -<<EOF
apiVersion: kafka.banzaicloud.io/v1alpha1
kind: KafkaTopic
metadata:
  name: perftest3
spec:
  name: perftest3
  partitions: 12
  replicationFactor: 3
  retention.ms: '28800000'
  cleanup.policy: delete
EOF

Para cada tópico, o fator de replicação é 3 – o valor mínimo recomendado para sistemas de produção altamente disponíveis.

Ferramenta de geração de carga

Lançamos três exemplares do gerador de carga (cada um escrito em um tópico separado). Para pods geradores de carga, é necessário configurar a afinidade do nó para que eles sejam planejados apenas nos nós alocados para eles:

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  labels:
    app: loadtest
  name: perf-load1
  namespace: kafka
spec:
  progressDeadlineSeconds: 600
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: loadtest
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: loadtest
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: nodepool.banzaicloud.io/name
                operator: In
                values:
                - loadgen
      containers:
      - args:
        - -brokers=kafka-0:29092,kafka-1:29092,kafka-2:29092,kafka-3:29092
        - -topic=perftest1
        - -required-acks=all
        - -message-size=512
        - -workers=20
        image: banzaicloud/perfload:0.1.0-blog
        imagePullPolicy: Always
        name: sangrenel
        resources:
          limits:
            cpu: 2
            memory: 1Gi
          requests:
            cpu: 2
            memory: 1Gi
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30

Alguns pontos a serem observados:

  • O gerador de carga gera mensagens de 512 bytes de comprimento e as publica no Kafka em lotes de 500 mensagens.
  • Usando um argumento -required-acks=all A publicação é considerada bem-sucedida quando todas as réplicas sincronizadas da mensagem são recebidas e confirmadas pelos corretores Kafka. Isto significa que no benchmark medimos não apenas a velocidade com que os líderes recebem mensagens, mas também a velocidade com que os seus seguidores replicam mensagens. O objetivo deste teste não é avaliar a velocidade de leitura do consumidor (consumidores) mensagens recebidas recentemente que ainda permanecem no cache de páginas do SO e sua comparação com a velocidade de leitura das mensagens armazenadas em disco.
  • O gerador de carga executa 20 trabalhadores em paralelo (-workers=20). Cada trabalhador contém 5 produtores que compartilham a conexão do trabalhador com o cluster Kafka. Como resultado, cada gerador possui 100 produtores e todos enviam mensagens para o cluster Kafka.

Monitorando a integridade do cluster

Durante o teste de carga do cluster Kafka, também monitoramos sua integridade para garantir que não houvesse reinicializações de pod, réplicas fora de sincronia e rendimento máximo com flutuações mínimas:

  • O gerador de carga grava estatísticas padrão sobre o número de mensagens publicadas e a taxa de erro. A taxa de erro deve permanecer a mesma 0,00%.
  • Controlador Velocidade, implantado pelo operador kafka, fornece um painel onde também podemos monitorar o estado do cluster. Para visualizar este painel faça:
    supertubes cluster cruisecontrol show -n kafka --kubeconfig <path-to-eks-cluster-kubeconfig-file>
  • Nível de ISR (número de réplicas “sincronizadas”) encolhimento e expansão são iguais a 0.

Resultados de medição

3 corretores, tamanho da mensagem - 512 bytes

Com partições distribuídas uniformemente entre três corretores, conseguimos alcançar desempenho ~500 Mb/s (aproximadamente 990 mil mensagens por segundo):

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

O consumo de memória da máquina virtual JVM não excedeu 2 GB:

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

O rendimento do disco atingiu o rendimento máximo do nó de E/S em todas as três instâncias nas quais os intermediários estavam em execução:

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

A partir dos dados sobre o uso de memória pelos nós, conclui-se que o buffer e o cache do sistema levaram cerca de 10 a 15 GB:

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

3 corretores, tamanho da mensagem - 100 bytes

À medida que o tamanho da mensagem diminui, o rendimento cai aproximadamente 15-20%: o tempo gasto no processamento de cada mensagem o afeta. Além disso, a carga do processador quase dobrou.

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Como os nós do corretor ainda possuem núcleos não utilizados, o desempenho pode ser melhorado alterando a configuração do Kafka. Esta não é uma tarefa fácil, portanto para aumentar o rendimento é melhor trabalhar com mensagens maiores.

4 corretores, tamanho da mensagem - 512 bytes

Você pode aumentar facilmente o desempenho de um cluster Kafka simplesmente adicionando novos agentes e mantendo um equilíbrio de partições (isso garante que a carga seja distribuída uniformemente entre os agentes). No nosso caso, após adicionar um corretor, o rendimento do cluster aumentou para ~580 Mb/s (~1,1 milhão de mensagens por segundo). O crescimento acabou por ser menor do que o esperado: isto é explicado principalmente pelo desequilíbrio das partições (nem todos os corretores trabalham no auge das suas capacidades).

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

O consumo de memória da máquina JVM permaneceu abaixo de 2 GB:

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

O trabalho dos corretores com drives foi afetado pelo desequilíbrio das partições:

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Determine o tamanho apropriado para um cluster Kafka no Kubernetes

Descobertas

A abordagem iterativa apresentada acima pode ser expandida para cobrir cenários mais complexos envolvendo centenas de consumidores, reparticionamento, atualizações contínuas, reinicializações de pods, etc. Tudo isto permite-nos avaliar os limites das capacidades do cluster Kafka em diversas condições, identificar gargalos no seu funcionamento e encontrar formas de os combater.

Projetamos Supertubes para implantar um cluster de forma rápida e fácil, configurá-lo, adicionar/remover brokers e tópicos, responder a alertas e garantir que o Kafka em geral funcione corretamente no Kubernetes. Nosso objetivo é ajudá-lo a se concentrar na tarefa principal (“gerar” e “consumir” mensagens Kafka) e deixar todo o trabalho duro para os Supertubes e o operador Kafka.

Se você está interessado nas tecnologias Banzai Cloud e projetos Open Source, inscreva-se na empresa em GitHub, LinkedIn ou Twitter.

PS do tradutor

Leia também em nosso blog:

Fonte: habr.com

Adicionar um comentário