Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Nota. trad.: In questo articolo, Banzai Cloud condivide un esempio di come è possibile utilizzare i suoi strumenti personalizzati per semplificare l'utilizzo di Kafka all'interno di Kubernetes. Le seguenti istruzioni illustrano come determinare la dimensione ottimale della propria infrastruttura e configurare Kafka stesso per ottenere il throughput richiesto.

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Apache Kafka è una piattaforma di streaming distribuita per la creazione di sistemi di streaming in tempo reale affidabili, scalabili e ad alte prestazioni. Le sue straordinarie capacità possono essere estese utilizzando Kubernetes. Per questo abbiamo sviluppato Operatore Kafka open source e uno strumento chiamato Supertubi. Ti consentono di eseguire Kafka su Kubernetes e di utilizzare le sue varie funzionalità, come la messa a punto della configurazione del broker, il ridimensionamento basato su metriche con ribilanciamento, la consapevolezza del rack, il "soft" (grazioso) lancio di aggiornamenti, ecc.

Prova Supertubes nel tuo cluster:

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

Oppure contatta documentazione. Puoi anche leggere alcune delle funzionalità di Kafka, il cui lavoro è automatizzato utilizzando Supertubes e l'operatore Kafka. Ne abbiamo già scritto sul blog:

Quando decidi di distribuire un cluster Kafka su Kubernetes, probabilmente dovrai affrontare la sfida di determinare la dimensione ottimale dell'infrastruttura sottostante e la necessità di ottimizzare la configurazione Kafka per soddisfare i requisiti di throughput. La prestazione massima di ciascun broker è determinata dalle prestazioni dei componenti dell'infrastruttura sottostante, come memoria, processore, velocità del disco, larghezza di banda della rete, ecc.

Idealmente, la configurazione del broker dovrebbe essere tale che tutti gli elementi dell'infrastruttura vengano utilizzati al massimo delle loro capacità. Tuttavia, nella vita reale questa configurazione è piuttosto complessa. È più probabile che gli utenti configurino i broker per massimizzare l'utilizzo di uno o due componenti (disco, memoria o processore). In generale, un broker mostra le massime prestazioni quando la sua configurazione consente di sfruttare al meglio la componente più lenta. In questo modo possiamo avere un’idea approssimativa del carico che un broker può gestire.

In teoria, possiamo anche stimare il numero di broker necessari per gestire un dato carico. Tuttavia, in pratica ci sono così tante opzioni di configurazione a diversi livelli che è molto difficile (se non impossibile) valutare le prestazioni potenziali di una particolare configurazione. In altre parole, è molto difficile pianificare una configurazione basata su determinate prestazioni.

Per gli utenti di Supertubes, di solito adottiamo il seguente approccio: iniziamo con alcune configurazioni (infrastruttura + impostazioni), quindi misuriamo le sue prestazioni, regoliamo le impostazioni del broker e ripetiamo nuovamente il processo. Ciò accade fino a quando il componente più lento dell'infrastruttura non viene completamente utilizzato.

In questo modo abbiamo un'idea più chiara di quanti broker ha bisogno un cluster per gestire un certo carico (il numero di broker dipende anche da altri fattori, come il numero minimo di repliche dei messaggi per garantire la resilienza, il numero di partizioni leader, ecc.). Inoltre, otteniamo informazioni su quali componenti dell'infrastruttura richiedono un ridimensionamento verticale.

Questo articolo parlerà dei passaggi da eseguire per ottenere il massimo dai componenti più lenti nelle configurazioni iniziali e misurerà il throughput di un cluster Kafka. Una configurazione altamente resiliente richiede almeno tre broker in esecuzione (min.insync.replicas=3), distribuiti in tre diverse zone di accessibilità. Per configurare, scalare e monitorare l'infrastruttura Kubernetes, utilizziamo la nostra piattaforma di gestione dei contenitori per cloud ibridi: Conduttura. Supporta on-premise (bare metal, VMware) e cinque tipi di cloud (Alibaba, AWS, Azure, Google, Oracle), nonché qualsiasi combinazione di essi.

Considerazioni sull'infrastruttura e sulla configurazione del cluster Kafka

Per gli esempi seguenti, abbiamo scelto AWS come fornitore di servizi cloud ed EKS come distribuzione Kubernetes. Una configurazione simile può essere implementata utilizzando P.K.E. - Distribuzione Kubernetes di Banzai Cloud, certificata da CNCF.

disco

Amazon ne offre diversi Tipi di volume EBS. Al centro gp2 и io1 ci sono unità SSD, tuttavia, per garantire un throughput elevato gp2 consuma i crediti accumulati (Crediti I/O), quindi abbiamo preferito il tipo io1, che offre un throughput elevato e costante.

Tipi di istanza

Le prestazioni di Kafka dipendono fortemente dalla cache della pagina del sistema operativo, quindi abbiamo bisogno di istanze con memoria sufficiente per i broker (JVM) e la cache della pagina. Esempio c5.2xgrande - un buon inizio, poiché ha 16 GB di memoria e ottimizzato per funzionare con EBS. Lo svantaggio è che è in grado di fornire le massime prestazioni solo per non più di 30 minuti ogni 24 ore. Se il tuo carico di lavoro richiede prestazioni di picco per un periodo di tempo più lungo, potresti prendere in considerazione altri tipi di istanze. Questo è esattamente quello che abbiamo fatto, fermandoci a c5.4xgrande. Fornisce il massimo throughput in 593,75 Mbit/s. Throughput massimo di un volume EBS io1 superiore all'istanza c5.4xgrande, quindi è probabile che l'elemento più lento dell'infrastruttura sia il throughput I/O di questo tipo di istanza (cosa che dovrebbero confermare anche i nostri test di carico).

Rete

La velocità effettiva della rete deve essere sufficientemente elevata rispetto alle prestazioni dell'istanza VM e del disco, altrimenti la rete diventa un collo di bottiglia. Nel nostro caso, l'interfaccia di rete c5.4xgrande supporta velocità fino a 10 Gb/s, che è significativamente superiore al throughput I/O di un'istanza VM.

Distribuzione del broker

I broker dovrebbero essere distribuiti (programmati in Kubernetes) su nodi dedicati per evitare di competere con altri processi per risorse di CPU, memoria, rete e disco.

Versione Java

La scelta logica è Java 11 perché è compatibile con Docker, nel senso che la JVM determina correttamente i processori e la memoria disponibile per il contenitore in cui è in esecuzione il broker. Sapendo che i limiti della CPU sono importanti, la JVM imposta internamente e in modo trasparente il numero di thread GC e thread JIT. Abbiamo usato l'immagine di Kafka banzaicloud/kafka:2.13-2.4.0, che include la versione 2.4.0 di Kafka (Scala 2.13) su Java 11.

Se desideri saperne di più su Java/JVM su Kubernetes, consulta i nostri post seguenti:

Impostazioni della memoria del broker

Esistono due aspetti chiave nella configurazione della memoria del broker: le impostazioni per la JVM e per il pod Kubernetes. Il limite di memoria impostato per un pod deve essere maggiore della dimensione massima dell'heap in modo che la JVM abbia spazio per il metaspazio Java, che risiede nella propria memoria, e per la cache delle pagine del sistema operativo, che Kafka utilizza attivamente. Nei nostri test abbiamo lanciato i broker Kafka con parametri -Xmx4G -Xms2Ge il limite di memoria per il pod era 10 Gi. Tieni presente che le impostazioni della memoria per la JVM possono essere ottenute automaticamente utilizzando -XX:MaxRAMPercentage и -X:MinRAMPercentage, in base al limite di memoria del pod.

Impostazioni del processore del broker

In generale, è possibile migliorare le prestazioni aumentando il parallelismo aumentando il numero di thread utilizzati da Kafka. Più processori sono disponibili per Kafka, meglio è. Nel nostro test, abbiamo iniziato con un limite di 6 processori e gradualmente (attraverso iterazioni) abbiamo aumentato il loro numero fino a 15. Inoltre, abbiamo impostato num.network.threads=12 nelle impostazioni del broker per aumentare il numero di thread che ricevono dati dalla rete e li inviano. Scoprendo immediatamente che i broker follower non potevano ricevere le repliche abbastanza velocemente, hanno rilanciato num.replica.fetchers a 4 per aumentare la velocità con cui i broker follower replicano i messaggi dei leader.

Strumento di generazione del caricamento

È necessario assicurarsi che il generatore di carico selezionato non esaurisca la capacità prima che il cluster Kafka (di cui viene eseguito il benchmark) raggiunga il carico massimo. In altre parole, è necessario condurre una valutazione preliminare delle capacità dello strumento di generazione del carico e anche selezionare i tipi di istanza con un numero sufficiente di processori e memoria. In questo caso, il nostro strumento produrrà più carico di quanto il cluster Kafka possa gestire. Dopo molti esperimenti, abbiamo optato per tre copie c5.4xgrande, ognuno dei quali aveva un generatore in funzione.

Analisi comparativa

La misurazione della performance è un processo iterativo che comprende le seguenti fasi:

  • configurazione dell'infrastruttura (cluster EKS, cluster Kafka, strumento di generazione del carico, nonché Prometheus e Grafana);
  • generare un carico per un certo periodo per filtrare le deviazioni casuali negli indicatori di prestazione raccolti;
  • adeguare l'infrastruttura e la configurazione del broker in base agli indicatori di prestazione osservati;
  • ripetendo il processo fino al raggiungimento del livello richiesto di velocità effettiva del cluster Kafka. Allo stesso tempo, deve essere costantemente riproducibile e presentare variazioni minime nella produttività.

La sezione successiva descrive i passaggi eseguiti durante il processo di benchmarking del cluster di test.

Strumenti

Sono stati utilizzati i seguenti strumenti per distribuire rapidamente una configurazione di base, generare carichi e misurare le prestazioni:

  • Banzai Cloud Pipeline per organizzare un cluster EKS da Amazon c Prometeo (per raccogliere Kafka e parametri infrastrutturali) e graminacee (per visualizzare queste metriche). Ne abbiamo approfittato integrato в Conduttura servizi che forniscono monitoraggio federato, raccolta centralizzata dei registri, scansione delle vulnerabilità, ripristino di emergenza, sicurezza di livello aziendale e molto altro ancora.
  • Sangrenel — uno strumento per testare il carico di un cluster Kafka.
  • Dashboard Grafana per la visualizzazione delle metriche e dell'infrastruttura Kafka: Kubernetes Kafka, Esportatore di nodi.
  • CLI di Supertubes per il modo più semplice per configurare un cluster Kafka su Kubernetes. Zookeeper, operatore Kafka, Envoy e molti altri componenti sono installati e configurati correttamente per eseguire un cluster Kafka pronto per la produzione su Kubernetes.
    • Per l'installazione CLI dei supertubi utilizzare le istruzioni fornite qui.

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Gruppo EKS

Preparare un cluster EKS con nodi di lavoro dedicati c5.4xgrande in diverse zone di disponibilità per pod con broker Kafka, nonché nodi dedicati per il generatore di carico e l'infrastruttura di monitoraggio.

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

Una volta che il cluster EKS è attivo e funzionante, abilitarne l'integrazione servizio di monitoraggio - schiererà Prometheus e Grafana in un ammasso.

Componenti del sistema Kafka

Installa i componenti del sistema Kafka (Zookeeper, kafka-operator) in EKS utilizzando la CLI di supertubes:

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

Gruppo Kafka

Per impostazione predefinita, EKS utilizza volumi EBS di tipo gp2, quindi è necessario creare una classe di archiviazione separata in base ai volumi io1 per il 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

Imposta il parametro per i broker min.insync.replicas=3 e distribuisci i pod broker sui nodi in tre diverse zone di disponibilità:

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

Temi

Abbiamo eseguito tre istanze del generatore di carico in parallelo. Ognuno di loro scrive sul proprio argomento, ovvero abbiamo bisogno di tre argomenti in totale:

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

Per ogni argomento, il fattore di replica è 3: il valore minimo consigliato per i sistemi di produzione ad alta disponibilità.

Strumento di generazione del caricamento

Abbiamo lanciato tre copie del generatore di carico (ognuna ha scritto in un argomento separato). Per i pod del generatore di carico, devi impostare l'affinità dei nodi in modo che vengano pianificati solo sui nodi ad essi assegnati:

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

Alcuni punti da notare:

  • Il generatore di carico genera messaggi di 512 byte di lunghezza e li pubblica in Kafka in batch di 500 messaggi.
  • Utilizzando un argomento -required-acks=all La pubblicazione viene considerata riuscita quando tutte le repliche sincronizzate del messaggio vengono ricevute e confermate dai broker Kafka. Ciò significa che nel benchmark abbiamo misurato non solo la velocità con cui i leader ricevono i messaggi, ma anche i loro follower che li replicano. Lo scopo di questo test non è valutare la velocità di lettura del consumatore (consumatori) messaggi ricevuti di recente che rimangono ancora nella cache della pagina del sistema operativo e confronto con la velocità di lettura dei messaggi archiviati su disco.
  • Il generatore di carico fa funzionare 20 lavoratori in parallelo (-workers=20). Ogni lavoratore contiene 5 produttori che condividono la connessione del lavoratore al cluster Kafka. Di conseguenza, ogni generatore ha 100 produttori e tutti inviano messaggi al cluster Kafka.

Monitoraggio dell'integrità del cluster

Durante il test di carico del cluster Kafka, ne abbiamo anche monitorato l'integrità per garantire che non si verificassero riavvii dei pod, repliche non sincronizzate e velocità effettiva massima con fluttuazioni minime:

  • Il generatore di carico scrive statistiche standard sul numero di messaggi pubblicati e sul tasso di errore. Il tasso di errore dovrebbe rimanere lo stesso 0,00%.
  • Cruise Control, distribuito da kafka-operator, fornisce una dashboard in cui possiamo anche monitorare lo stato del cluster. Per visualizzare questo pannello eseguire:
    supertubes cluster cruisecontrol show -n kafka --kubeconfig <path-to-eks-cluster-kubeconfig-file>
  • Livello ISR (numero di repliche “in sincronia”) contrazione ed espansione sono pari a 0.

Risultati della misurazione

3 broker, dimensione del messaggio - 512 byte

Con le partizioni distribuite uniformemente su tre broker, siamo riusciti a ottenere prestazioni elevate ~500 Mb/s (circa 990mila messaggi al secondo):

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Il consumo di memoria della macchina virtuale JVM non ha superato i 2 GB:

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

La velocità effettiva del disco ha raggiunto la velocità effettiva massima del nodo I/O su tutte e tre le istanze su cui erano in esecuzione i broker:

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Dai dati sull'utilizzo della memoria da parte dei nodi, ne consegue che il buffering e il caching del sistema hanno richiesto circa 10-15 GB:

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

3 broker, dimensione del messaggio - 100 byte

Man mano che la dimensione del messaggio diminuisce, il throughput diminuisce di circa il 15-20%: il tempo impiegato nell'elaborazione di ciascun messaggio influisce su di esso. Inoltre, il carico del processore è quasi raddoppiato.

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Poiché i nodi broker hanno ancora core inutilizzati, le prestazioni possono essere migliorate modificando la configurazione di Kafka. Questo non è un compito facile, quindi per aumentare la produttività è meglio lavorare con messaggi più grandi.

4 broker, dimensione del messaggio - 512 byte

Puoi aumentare facilmente le prestazioni di un cluster Kafka semplicemente aggiungendo nuovi broker e mantenendo un equilibrio di partizioni (questo garantisce che il carico sia distribuito uniformemente tra i broker). Nel nostro caso, dopo aver aggiunto un broker, il throughput del cluster è aumentato a ~580 Mb/s (~1,1 milioni di messaggi al secondo). La crescita si è rivelata inferiore alle aspettative: ciò si spiega principalmente con lo squilibrio delle partizioni (non tutti i broker lavorano al massimo delle proprie capacità).

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Il consumo di memoria della macchina JVM è rimasto inferiore a 2 GB:

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Il lavoro dei broker con le unità è stato influenzato dallo squilibrio delle partizioni:

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

Determina la dimensione appropriata per un cluster Kafka in Kubernetes

risultati

L'approccio iterativo presentato sopra può essere ampliato per coprire scenari più complessi che coinvolgono centinaia di consumatori, ripartizionamento, aggiornamenti in sequenza, riavvii dei pod, ecc. Tutto ciò ci consente di valutare i limiti delle capacità del cluster Kafka in varie condizioni, identificare i colli di bottiglia nel suo funzionamento e trovare modi per combatterli.

Abbiamo progettato Supertubes per distribuire rapidamente e facilmente un cluster, configurarlo, aggiungere/rimuovere broker e argomenti, rispondere agli avvisi e garantire che Kafka in generale funzioni correttamente su Kubernetes. Il nostro obiettivo è aiutarti a concentrarti sul compito principale ("generare" e "consumare" messaggi Kafka) e lasciare tutto il duro lavoro a Supertubes e all'operatore Kafka.

Se sei interessato alle tecnologie Banzai Cloud e ai progetti Open Source, iscriviti all'azienda su GitHub, LinkedIn o Twitter.

PS da traduttore

Leggi anche sul nostro blog:

Fonte: habr.com

Aggiungi un commento