BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

Obs. övers.: I denna artikel delar Banzai Cloud med sig av ett exempel pÄ hur deras specialverktyg kan underlÀtta driften av Kafka inom Kubernetes. Instruktionerna visar hur man kan bestÀmma den optimala storleken pÄ infrastrukturen och konfigurera Kafka för att uppnÄ önskad kapacitet.

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

Apache Kafka Àr en distribuerad strömmande plattform för skapande av pÄlitliga, skalbara och högpresterande realtids-system. Dess imponerande funktioner kan förstÀrkas med hjÀlp av Kubernetes. För detta har vi utvecklat Open Source Kafka-operatorn och ett verktyg som kallas Supertubes. De möjliggör driftsÀttning av Kafka i Kubernetes och utnyttja dess olika funktioner, sÄsom finjustering av broker-konfiguration, skalning baserad pÄ metrics med ombalansering, rack awareness, "mjuk" (graceful) uppgradering av versioner m.m.

Testa Supertubes i din kluster:

curl https://getsupertubes.sh | sh och supertubes install -a --no-democluster --kubeconfig

Eller kontakta dokumentationen. Det gÄr ocksÄ att lÀsa om vissa funktioner av Kafka, vars hantering Àr automatiserad med hjÀlp av Supertubes och Kafka-operatorn. Vi har redan skrivit om dem i bloggen:

NÀr du beslutar att sÀtta upp en Kafka-kluster i Kubernetes kommer du sÀkert att stöta pÄ problemet att bestÀmma den optimala storleken pÄ den grundlÀggande infrastrukturen och behovet av att finjustera Kafka-konfigurationen för att möta kapacitetskraven. Den maximala prestandan för varje broker bestÀms av prestandan hos infrastrukturens komponenter, sÄsom minne, processor, diskens hastighet, nÀtverkskapacitet osv.

I idealfallet bör brokerkonfigurationen vara sÄdan att alla infrastrukturella element anvÀnds maximalt. Men i verkliga livet Àr en sÄdan instÀllning ganska svÄr. Det Àr mer sannolikt att anvÀndare konfigurerar brokerinstÀllningar för att maximera anvÀndningen av en eller tvÄ komponenter (disk, minne eller processor). Generellt visar en broker maximal prestanda nÀr dess konfiguration tillÄter den lÄngsammaste komponenten att utnyttjas fullt ut. PÄ sÄ sÀtt kan vi fÄ en ungefÀrlig uppfattning om den belastning som en broker kan hantera.

Teoretiskt kan vi Àven uppskatta antalet brokers som behövs för att hantera en viss belastning. Men i praktiken Àr det sÄ mÄnga konfigurationsalternativ pÄ olika nivÄer att det Àr ganska svÄrt (om inte omöjligt) att bedöma den potentiella prestandan hos en viss konfiguration. Med andra ord Àr det mycket utmanande att planera en konfiguration med utgÄngspunkt frÄn en viss förvÀntad prestanda.

För anvÀndare av Supertubes tillÀmpar vi vanligtvis följande metod: vi börjar med en viss konfiguration (infrastruktur + instÀllningar), mÀter dess prestanda, justerar brokerinstÀllningarna och upprepar processen. Detta pÄgÄr tills potentialen hos den lÄngsammaste infrastrukturella komponenten Àr helt utnyttjad.

Genom denna metod fÄr vi en klarare uppfattning om hur mÄnga brokers som krÀvs för klustret för att hantera en viss belastning (antalet brokers beror ocksÄ pÄ andra faktorer, sÄsom minimalt antal meddelandekopior för att sÀkerstÀlla redundans, antalet partitionledare osv.). Dessutom fÄr vi en uppfattning om vilken infrastrukturell komponent som bör skalas vertikalt.

I den hĂ€r artikeln kommer vi att diskutera de steg vi tar för att "fĂ„ ut allt" frĂ„n de lĂ„ngsammaste komponenterna i initiala konfigurationer och mĂ€ta klustrets genomströmning i Kafka. En högt tillförlitlig konfiguration krĂ€ver minst tre aktiva brokers (min.insync.replicas=3), spridda över tre olika tillgĂ€nglighetszoner. För att konfigurera, skala och övervaka Kubernetes-infrastrukturen anvĂ€nder vi vĂ„r egen containerhanteringsplattform för hybridmoln — Pipeline. Den stöder on-premise (bare metal, VMware) och fem typer av moln (Alibaba, AWS, Azure, Google, Oracle), samt alla tĂ€nkbara kombinationer av dem.

Tankar kring infrastruktur och konfiguration av Kafka-klustret

För exemplen nedan har vi valt AWS som molnleverantör och EKS som Kubernetes-distribution. En liknande konfiguration kan realiseras med PKE — en Kubernetes-distribution frĂ„n Banzai Cloud, certifierad av CNCF.

Enhet

Amazon erbjuder olika typer av EBS-volymer. I grunden gp2 och io1 baseras pÄ SSD-enheter, men för att sÀkerstÀlla hög genomströmning gp2 förbrukar ackumulerade krediter (I/O credits), dÀrför föredrog vi en typ io1, som erbjuder stabil hög genomströmning.

Typer av instanser

Kafkas prestanda beror starkt pÄ operativsystemets sid-cache, sÄ vi behöver instanser med tillrÀckligt med minne för mÀklare (JVM) och sid-cache. Instansen c5.2xlarge Àr en bra början, eftersom den har 16 GB minne och Àr optimerad för arbete med EBS. Nackdelen Àr att den kan leverera maximal prestanda under högst 30 minuter om dygnet. Om arbetsbelastningen krÀver maximal prestanda under lÀngre perioder bör vi övervÀga andra typer av instanser. Och sÄ gjorde vi, nÀr vi stannade vid c5.4xlarge. Den erbjuder maximal genomströmning pÄ 593,75 MB/s. Den maximala genomströmningen för EBS-volymen io1 Àr högre Àn för instansen c5.4xlarge, sÄ den lÄngsammaste delen av infrastrukturen Àr uppenbarligen I/O-genomströmningen för den hÀr instansen (vilket ocksÄ bör bekrÀftas av resultaten av vÄra belastningstester).

NĂ€tverk

NÀtverksbandbredden mÄste vara tillrÀckligt stor jÀmfört med instansens VM-prestanda och disken, annars blir nÀtverk den svaga lÀnken. I vÄrt fall stöder nÀtverksgrÀnssnittet c5.4xlarge hastigheter upp till 10 Gb/s, vilket Àr betydligt mer Àn I/O-genomströmningen för VM-instansen.

Distribuering av mÀklare

MÀklarna bör distribueras (planeras i Kubernetes) pÄ dedikerade noder för att undvika konkurrens med andra processer om CPU-, minnes-, nÀtverks- och diskresurser.

Java-version

Ett rimligt val Àr Java 11, eftersom det Àr kompatibelt med Docker pÄ sÄ sÀtt att JVM korrekt identifierar de processorer och det minne som Àr tillgÀngligt för den container dÀr mÀklaren körs. Med vetskap om att CPU-grÀnser Àr viktiga, stÀller JVM internt och transparent in antalet GC-trÄdar och JIT-kompilatortrÄdar. Vi anvÀnde bilden Kafka banzaicloud/kafka:2.13-2.4.0, som inkluderar version 2.4.0 av Kafka (Scala 2.13) pÄ Java 11.

Om du vill veta mer om Java/JVM pÄ Kubernetes, kolla gÀrna pÄ vÄra följande publikationer:

MÀklarnas minnesinstÀllningar

Det finns tvÄ viktiga aspekter av att konfigurera mÀklarens minne: instÀllningar för JVM och för Kubernetes-poden. GrÀnsen för minnet som sÀtts för podden bör vara större Àn det maximala heap-storleken, sÄ att JVM har utrymme för Java-metaplatsen, som ligger i sin egen minne, och för operativsystemets sid cache, som Kafka aktivt anvÀnder. I vÄra tester körde vi Kafka-mÀklare med parametrarna -Xmx4G -Xms2G, medan minnesgrÀnsen för podden var 10 Gi. Observera att minnesinstÀllningar för JVM automatiskt kan fÄs med -XX:MaxRAMPercentage och -X:MinRAMPercentage, baserat pÄ minnesgrÀnsen för podden.

MÀklarnas processorinstÀllningar

Generellt sett kan prestandan ökas genom att öka parallellismen genom att öka antalet trÄdar som Kafka anvÀnder. Ju fler processorer som Àr tillgÀngliga för Kafka, desto bÀttre. I vÄrt test började vi med en begrÀnsning pÄ 6 processorer och ökade successivt (i iterationer) antalet till 15. Dessutom stÀllde vi in num.network.threads=12 i mÀklarens instÀllningar för att öka antalet trÄdar som tar emot data frÄn nÀtverket och skickar dem. Vi upptÀckte omedelbart att följarna inte kunde ta emot repliker tillrÀckligt snabbt, sÄ vi ökade num.replica.fetchers till 4 för att öka hastigheten med vilken följarna replikerade meddelanden frÄn ledarna.

Belastningstestverktyg

Det Àr viktigt att sÀkerstÀlla att potentialen hos den valda belastningsgeneratorn inte tar slut innan Kafka-klustret (vars prestanda mÀts) nÄr sin maximala belastning. Med andra ord Àr det nödvÀndigt att göra en förhandsutvÀrdering av belastningsgeneratorns kapabiliteter samt vÀlja instanser med tillrÀckligt med processorer och minne. Under dessa förhÄllanden kommer vÄrt verktyg att generera mer belastning Àn vad Kafka-klustret kan hantera. Efter flera tester har vi valt att anvÀnda tre instanser c5.4xlarge, dÀr varje instans körde en generator.

Benchmarking

PrestandamÀtning Àr en iterativ process som involverar följande steg:

  • konfigurering av infrastrukturen (EKS-kluster, Kafka-kluster, belastningsgenerator och Ă€ven Prometheus och Grafana);
  • generering av belastning under en viss tidsperiod för att filtrera bort slumpmĂ€ssiga avvikelser i de insamlade prestandamĂ„tten;
  • justering av infrastrukturen och brokerkonfigurationen baserat pĂ„ observerade prestandaindikatorer;
  • upprepning av processen tills den önskade genomströmningen i Kafka-klustret uppnĂ„s. Det ska ocksĂ„ vara stabilt reproducerbart och visa minimala variationer i genomströmning.

I nÀsta avsnitt beskrivs stegen som utfördes under benchmarking-processen av testklustret.

Verktyg

För snabb distribution av en grundkonfiguration, belastningsgenerering och prestandamÀtning anvÀndes följande verktyg:

  • Banzai Cloud Pipeline för att organisera EKS-klustret frĂ„n Amazon med Prometheus (för insamling av Kafka och infrastrukturmetrik) och Grafana (för visualisering av dessa metrik). Vi anvĂ€nde integrerade pĂ„ Pipeline tjĂ€nster som erbjuder federativ övervakning, centraliserad logginsamlning, sĂ„rbarhetsskanning, Ă„terstĂ€llning efter driftstopp, företagsklassens sĂ€kerhet och mycket mer.
  • Sangrenel — ett verktyg för belastningstestning av Kafka-klustret.
  • Grafana-paneler för visualisering av Kafka- och infrastrukturmetrik: Kubernetes Kafka, Node Exporter.
  • Supertubes CLI för den enklaste konfigurationen av ett Kafka-kluster i Kubernetes. Zookeeper, Kafka-operator, Envoy och mĂ„nga andra komponenter installeras och konfigureras korrekt för att köra ett produktionsklart Kafka-kluster i Kubernetes.
    • För installation supertubes CLI anvĂ€nd instruktionerna som anges hĂ€r.

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

EKS-kluster

Förbered EKS-klustret med dedikerade noder c5.4xlarge i olika tillgÀnglighetszoner för poddar med Kafka-brokers samt dedikerade noder för lastgenerering och övervakningsinfrastruktur.

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

NĂ€r EKS-klustret Ă€r igĂ„ng, aktivera dess integrerade övervakningstjĂ€nst — den kommer att installera Prometheus och Grafana i klustret.

Systemkomponenter för Kafka

Installera systemkomponenter för Kafka (Zookeeper, kafka-operator) i EKS med hjÀlp av supertubes CLI:

supertubes install -a --no-democluster --kubeconfig

Kafka-kluster

Som standard anvÀnds EBS-volymer av typen gp2, sÄ det Àr nödvÀndigt att skapa en sÀrskild lagringsklass baserad pÄ volymer io1 för Kafka-klustret:

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

StÀll in parametern för brokerns min.insync.replicas=3 och distribuera poddar för brokers pÄ noder i tre olika tillgÀnglighetszoner:

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

Ämnen

Vi körde samtidigt tre instanser av lastgeneratorn. Var och en skriver till sitt eget Àmne, totalt behöver vi alltsÄ tre Àmnen:

supertubes cluster topic create -n kafka --kubeconfig  -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  -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  -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

För varje Ă€mne Ă€r faktorn för replikering 3 — det minimi rekommenderade vĂ€rdet för hög tillgĂ€nglighet i produktionssystem.

Belastningstestverktyg

Vi startade tre instanser av belastningstestgeneratorn (varje instans skrev till en separat topic). För belastningstestgeneratorns poddar mÄste node affinity anges sÄ att de endast schemalÀggs pÄ de reserverade noderna:

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

NÄgra punkter att tÀnka pÄ:

  • Belastningstestgeneratorn genererar meddelanden pĂ„ 512 byte och publicerar dem i Kafka i batcher om 500 meddelanden.
  • Med hjĂ€lp av argumentet -required-acks=all anses publiceringen vara lyckad nĂ€r alla synkroniserade repliker av meddelandet har mottagits och bekrĂ€ftats av Kafka-brokers. Det innebĂ€r att vi i benchmarket mĂ€tte inte bara hastigheten hos ledarna som tar emot meddelanden, utan ocksĂ„ deras efterföljare som replikerar meddelanden. MĂ„let med detta test Ă€r inte att utvĂ€rdera hastigheten hos konsumenterna (consumers) för nyligen mottagna meddelanden, som fortfarande ligger i operativsystemets sidcache, och dess jĂ€mförelse med hastigheten för att lĂ€sa meddelanden som lagras pĂ„ disk.
  • Belastningstestgeneratorn kör parallellt 20 arbetare (-workers=20). Varje arbetare innehĂ„ller 5 producenter som gemensamt anvĂ€nder arbetarnas anslutning till Kafka-klustret. Totalt har varje generator 100 producenter och alla skickar meddelanden till Kafka-klustret.

Övervakning av klustrets tillstĂ„nd

Under load testing of the Kafka cluster, we also monitored its health to ensure there were no pod restarts, unsynchronized replicas, and maximum throughput with minimal fluctuations:

  • The load generator writes standard statistics on the number of published messages and the error rate. The error percentage should remain at 0,00%.
  • Cruise Control, deployed by kafka-operator, provides a monitoring dashboard where we can also observe the state of the cluster. To view this dashboard, execute:
    supertubes cluster cruisecontrol show -n kafka --kubeconfig
  • The ISR level (number of 'in-sync' replicas) is equal to 0 for shrink and expansion.

Measurement results

3 brokers, message size — 512 bytes

With partitions evenly distributed across three brokers, we managed to achieve a performance of ~500 MB/s (approximately 990 thousand messages per second):

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

The memory consumption by the JVM virtual machine did not exceed 2 GB:

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

Disk throughput reached the maximum I/O throughput of the node across all three instances where the brokers were running:

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

From the data on memory usage by the nodes, it can be seen that system buffering and caching took ~10-15 GB:

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

3 brokers, message size — 100 bytes

With the reduction in message size, the throughput decreases by approximately 15-20%: this is affected by the time spent processing each message. Additionally, the CPU load nearly doubled.

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

Since there are still unused cores on the broker nodes, performance can be improved by modifying the Kafka configuration. This is a complex task, so to increase throughput, it is better to work with larger messages.

4 brokers, message size — 512 bytes

It is easy to increase the performance of the Kafka cluster simply by adding new brokers and maintaining partition balance (this ensures an even distribution of load among brokers). In our case, after adding a broker, the cluster throughput increased to ~580 MB/s (~1.1 million messages per second). The increase was less than expected: this is mainly explained by the imbalance of partitions (not all brokers are operating at peak capacity).

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

JVM-maskinens minnesanvÀndning har hÄllits under 2 GB:

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

Brokers arbete med lagringsenheter har pÄverkats av en obalans i partitioner:

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

BestÀm rÀtt storlek för en Kafka-kluster i Kubernetes

Slutsatser

Den iterativa metoden som presenteras ovan kan utvidgas för att inkludera mer komplexa scenarier med hundratals konsumenter, ompartitionering, rullande uppdateringar, omstarter av poddar etc. Detta gör att vi kan bedöma grÀnserna för Kafkas klusterkapacitet under olika förhÄllanden, identifiera flaskhalsar i dess prestanda och hitta sÀtt att ÄtgÀrda dem.

Vi har utvecklat Supertubes för snabb och enkel distribution av klustret, dess konfiguration, tillÀgg/borttagning av brokers och teman, reagere pÄ aviseringar och sÀkerstÀlla en korrekt funktion av Kafka i Kubernetes i stort. VÄrt mÄl Àr att hjÀlpa till att koncentrera sig pÄ huvuduppgiften ("generera" och "konsumera" Kafka-meddelanden), medan allt det tunga arbetet överlÄts till Supertubes och Kafka-operatören.

Om du Àr intresserad av Banzai Clouds teknik och Open Source-projekt, följ företaget pÄ GitHub, LinkedIn eller Twitter.

P.S. frÄn översÀttaren

LÀs Àven i vÄr blogg:

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster