Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Notera. transl.: I den här artikeln delar Banzai Cloud ett exempel på hur dess anpassade verktyg kan användas för att göra Kafka enklare att använda inom Kubernetes. Följande instruktioner illustrerar hur du kan bestämma den optimala storleken på din infrastruktur och konfigurera Kafka själv för att uppnå önskad genomströmning.

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Apache Kafka är en distribuerad streamingplattform för att skapa pålitliga, skalbara och högpresterande realtidsstreamingsystem. Dess imponerande kapacitet kan utökas med Kubernetes. För detta har vi utvecklat Kafka-operatör med öppen källkod och ett verktyg som heter Supertubes. De låter dig köra Kafka på Kubernetes och använda dess olika funktioner, som att finjustera mäklarkonfigurationen, metrisk baserad skalning med ombalansering, rackmedvetenhet, "mjuk" (graciös) rulla ut uppdateringar osv.

Prova Supertubes i ditt kluster:

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

Eller kontakta dokumentation. Du kan också läsa om några av Kafkas funktioner, vars arbete är automatiserat med Supertubes och Kafka-operatören. Vi har redan skrivit om dem på bloggen:

När du bestämmer dig för att distribuera ett Kafka-kluster på Kubernetes kommer du sannolikt att ställas inför utmaningen att bestämma den optimala storleken på den underliggande infrastrukturen och behovet av att finjustera din Kafka-konfiguration för att möta genomströmningskraven. Den maximala prestandan för varje mäklare bestäms av prestandan för de underliggande infrastrukturkomponenterna, såsom minne, processor, diskhastighet, nätverksbandbredd, etc.

Helst bör mäklarkonfigurationen vara sådan att alla infrastrukturelement används till maximal kapacitet. Men i verkligheten är denna inställning ganska komplex. Det är mer troligt att användare kommer att konfigurera mäklare för att maximera användningen av en eller två komponenter (disk, minne eller processor). Generellt sett visar en mäklare maximal prestanda när dess konfiguration tillåter att den långsammaste komponenten används i sin fulla utsträckning. På så sätt kan vi få en ungefärlig uppfattning om belastningen som en mäklare kan hantera.

Teoretiskt kan vi också uppskatta antalet mäklare som krävs för att hantera en given belastning. Men i praktiken finns det så många konfigurationsalternativ på olika nivåer att det är mycket svårt (om inte omöjligt) att utvärdera den potentiella prestandan för en viss konfiguration. Det är med andra ord väldigt svårt att planera en konfiguration utifrån en viss prestanda.

För Supertubes användare använder vi vanligtvis följande tillvägagångssätt: vi börjar med en viss konfiguration (infrastruktur + inställningar), mäter sedan dess prestanda, justerar mäklarinställningarna och upprepar processen igen. Detta sker tills den långsammaste komponenten av infrastrukturen är fullt utnyttjad.

På så sätt får vi en tydligare uppfattning om hur många mäklare ett kluster behöver för att hantera en viss belastning (antalet mäklare beror också på andra faktorer, såsom minsta antal meddelanderepliker för att säkerställa motståndskraft, antalet partitioner ledare etc.). Dessutom får vi insikt i vilka infrastrukturkomponenter som kräver vertikal skalning.

Den här artikeln kommer att prata om de steg vi tar för att få ut det mesta av de långsammaste komponenterna i initiala konfigurationer och mäta genomströmningen av ett Kafka-kluster. En mycket motståndskraftig konfiguration kräver minst tre löpande mäklare (min.insync.replicas=3), fördelade på tre olika tillgänglighetszoner. För att konfigurera, skala och övervaka Kubernetes infrastruktur använder vi vår egen containerhanteringsplattform för hybridmoln - Pipeline. Den stöder on-premise (bar metal, VMware) och fem typer av moln (Alibaba, AWS, Azure, Google, Oracle), såväl som valfri kombination av dem.

Tankar om Kafka-klusterinfrastruktur och konfiguration

För exemplen nedan valde vi AWS som molnleverantör och EKS som Kubernetes-distribution. En liknande konfiguration kan implementeras med hjälp av PKE - Kubernetes distribution från Banzai Cloud, certifierad av CNCF.

skiva

Amazon erbjuder olika EBS volymtyper. I kärnan gp2 и io1 Det finns dock SSD-enheter för att säkerställa hög genomströmning gp2 förbrukar ackumulerade krediter (I/O-poäng), så vi föredrog typen io1, som erbjuder konsekvent hög genomströmning.

Instanstyper

Kafkas prestanda är starkt beroende av operativsystemets sidcache, så vi behöver instanser med tillräckligt med minne för mäklarna (JVM) och sidcachen. Exempel c5.2xlarge - en bra början, eftersom den har 16 GB minne och optimerad för att arbeta med EBS. Dess nackdel är att den bara kan ge maximal prestanda i högst 30 minuter var 24:e timme. Om din arbetsbelastning kräver toppprestanda över en längre tidsperiod, kanske du vill överväga andra instanstyper. Det var precis vad vi gjorde, stannade vid c5.4xlarge. Det ger maximal genomströmning in 593,75 Mb/s. Maximal genomströmning av en EBS-volym io1 högre än instansen c5.4xlarge, så det långsammaste elementet i infrastrukturen är sannolikt I/O-genomströmningen av den här instanstypen (vilket våra belastningstester också bör bekräfta).

Сеть

Nätverksgenomströmningen måste vara tillräckligt stor jämfört med prestandan för VM-instansen och disken, annars blir nätverket en flaskhals. I vårt fall nätverksgränssnittet c5.4xlarge stöder hastigheter på upp till 10 Gb/s, vilket är betydligt högre än I/O-genomströmningen för en VM-instans.

Distribution av mäklare

Mäklare bör distribueras (schemalagda i Kubernetes) till dedikerade noder för att undvika att konkurrera med andra processer för CPU, minne, nätverk och diskresurser.

Java version

Det logiska valet är Java 11 eftersom det är kompatibelt med Docker i den meningen att JVM korrekt bestämmer vilka processorer och minne som är tillgängligt för behållaren där mäklaren körs. Genom att veta att CPU-gränser är viktiga ställer JVM internt och transparent in antalet GC-trådar och JIT-trådar. Vi använde Kafka-bilden banzaicloud/kafka:2.13-2.4.0, som inkluderar Kafka version 2.4.0 (Scala 2.13) på Java 11.

Om du vill lära dig mer om Java/JVM på Kubernetes, kolla in våra följande inlägg:

Mäklarens minnesinställningar

Det finns två nyckelaspekter för att konfigurera mäklarminne: inställningar för JVM och för Kubernetes pod. Minnesgränsen som är inställd för en pod måste vara större än den maximala heapstorleken så att JVM har plats för Java-metautrymmet, som finns i dess eget minne, och för operativsystemets sidcache, som Kafka aktivt använder. I våra tester lanserade vi Kafka-mäklare med parametrar -Xmx4G -Xms2G, och minnesgränsen för podden var 10 Gi. Observera att minnesinställningar för JVM kan erhållas automatiskt med -XX:MaxRAMPercentage и -X:MinRAMPercentage, baserat på minnesgränsen för podden.

Mäklarens processorinställningar

Generellt sett kan du förbättra prestandan genom att öka parallelliteten genom att öka antalet trådar som används av Kafka. Ju fler processorer tillgängliga för Kafka, desto bättre. I vårt test började vi med en gräns på 6 processorer och höjde gradvis (genom iterationer) deras antal till 15. Dessutom satte vi num.network.threads=12 i mäklarinställningarna för att öka antalet trådar som tar emot data från nätverket och skickar det. När de omedelbart upptäckte att följarmäklarna inte kunde ta emot repliker snabbt nog, höjde de num.replica.fetchers till 4 för att öka hastigheten med vilken följarmäklare replikerade meddelanden från ledare.

Lastgenereringsverktyg

Du bör se till att den valda lastgeneratorn inte tar slut innan Kafka-klustret (som benchmarkas) når sin maximala belastning. Med andra ord är det nödvändigt att göra en preliminär bedömning av kapaciteten hos lastgenereringsverktyget och även välja instanstyper för det med ett tillräckligt antal processorer och minne. I det här fallet kommer vårt verktyg att producera mer belastning än Kafka-klustret kan hantera. Efter många experiment bestämde vi oss för tre exemplar c5.4xlarge, som var och en hade en generator igång.

Benchmarking

Prestationsmätning är en iterativ process som inkluderar följande steg:

  • sätta upp infrastruktur (EKS-kluster, Kafka-kluster, lastgenereringsverktyg, samt Prometheus och Grafana);
  • generera en belastning under en viss period för att filtrera slumpmässiga avvikelser i de insamlade prestationsindikatorerna;
  • justering av mäklarens infrastruktur och konfiguration baserat på observerade prestationsindikatorer;
  • upprepa processen tills den erforderliga nivån av Kafka-klustergenomströmning uppnås. Samtidigt måste den vara konsekvent reproducerbar och uppvisa minimala variationer i genomströmning.

Nästa avsnitt beskriver de steg som utfördes under benchmarkingprocessen för testkluster.

Verktyg

Följande verktyg användes för att snabbt distribuera en baslinjekonfiguration, generera belastningar och mäta prestanda:

  • Banzai Cloud Pipeline för att organisera ett EKS-kluster från Amazon c Prometheus (för att samla Kafka och infrastrukturmått) och grafana (för att visualisera dessa mätvärden). Vi utnyttjade integrerad в Pipeline tjänster som tillhandahåller federerad övervakning, centraliserad logginsamling, sårbarhetsskanning, katastrofåterställning, säkerhet i företagsklass och mycket mer.
  • Sangrenel — ett verktyg för lasttestning av ett Kafka-kluster.
  • Grafana-instrumentpaneler för att visualisera Kafka-mått och infrastruktur: Kubernetes Kafka, Nodexportör.
  • Supertubes CLI för det enklaste sättet att sätta upp ett Kafka-kluster på Kubernetes. Zookeeper, Kafka-operatör, Envoy och många andra komponenter är installerade och korrekt konfigurerade för att köra ett produktionsfärdigt Kafka-kluster på Kubernetes.
    • För installation supertubes CLI använd instruktionerna som tillhandahålls här.

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

EKS-kluster

Förbered ett EKS-kluster med dedikerade arbetarnoder c5.4xlarge i olika tillgänglighetszoner för poddar med Kafka-mäklare, samt dedikerade noder för lastgeneratorn och övervakningsinfrastrukturen.

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 det integrerade övervakningstjänst — hon kommer att distribuera Prometheus och Grafana i ett kluster.

Kafka systemkomponenter

Installera Kafka-systemkomponenter (Zookeeper, kafka-operatör) i EKS med supertubes CLI:

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

Kafka-kluster

Som standard använder EKS EBS-volymer av typen gp2, så du måste skapa en separat lagringsklass baserat på volymer io1 för Kafka-kluster:

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 mäklare min.insync.replicas=3 och distribuera mäklarpods på noder i tre olika tillgänglighetszoner:

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

Ämnen

Vi körde tre lastgeneratorinstanser parallellt. Var och en av dem skriver till sitt eget ämne, det vill säga vi behöver tre ämnen totalt:

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

För varje ämne är replikeringsfaktorn 3 – det lägsta rekommenderade värdet för högt tillgängliga produktionssystem.

Lastgenereringsverktyg

Vi lanserade tre exemplar av lastgeneratorn (var och en skrev i ett separat ämne). För belastningsgeneratorpods måste du ställa in nodaffinitet så att de bara schemaläggs på de noder som tilldelats dem:

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 notera:

  • Lastgeneratorn genererar meddelanden på 512 byte långa och publicerar dem till Kafka i grupper om 500 meddelanden.
  • Använder ett argument -required-acks=all Publiceringen anses vara framgångsrik när alla synkroniserade repliker av meddelandet tas emot och bekräftas av Kafka-mäklare. Det betyder att vi i riktmärket mätte inte bara hastigheten för ledare som tar emot meddelanden, utan också hur deras följare replikerar meddelanden. Syftet med detta test är inte att utvärdera konsumenternas läshastighet (konsumenter) nyligen mottagna meddelanden som fortfarande finns kvar i OS-sidans cache, och dess jämförelse med läshastigheten för meddelanden lagrade på disken.
  • Lastgeneratorn driver 20 arbetare parallellt (-workers=20). Varje arbetare innehåller 5 producenter som delar arbetarens koppling till Kafka-klustret. Som ett resultat har varje generator 100 producenter, och de skickar alla meddelanden till Kafka-klustret.

Övervakning av klustrets hälsa

Under belastningstestning av Kafka-klustret övervakade vi också dess tillstånd för att säkerställa att det inte fanns några omstarter av pod, inga osynkroniserade repliker och maximal genomströmning med minimala fluktuationer:

  • Lastgeneratorn skriver standardstatistik om antalet publicerade meddelanden och felfrekvensen. Felfrekvensen bör förbli densamma 0,00%.
  • Farthållare, utplacerad av kafka-operatören, tillhandahåller en instrumentpanel där vi också kan övervaka klustrets tillstånd. Gör så här för att se den här panelen:
    supertubes cluster cruisecontrol show -n kafka --kubeconfig <path-to-eks-cluster-kubeconfig-file>
  • ISR-nivå (antal "synkroniserade" repliker) krympning och expansion är lika med 0.

Mätresultat

3 mäklare, meddelandestorlek - 512 byte

Med partitioner jämnt fördelade över tre mäklare kunde vi uppnå prestanda ~500 Mb/s (ungefär 990 tusen meddelanden per sekund):

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Minnesförbrukningen för den virtuella JVM-maskinen översteg inte 2 GB:

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Diskgenomströmningen nådde den maximala I/O-nodgenomströmningen på alla tre instanser som mäklarna körde på:

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Från data om minnesanvändning av noder, följer det att systembuffring och cachning tog ~10-15 GB:

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

3 mäklare, meddelandestorlek - 100 byte

När meddelandestorleken minskar, sjunker genomströmningen med cirka 15-20 %: tiden som ägnas åt att bearbeta varje meddelande påverkar det. Dessutom har processorbelastningen nästan fördubblats.

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Eftersom mäklarnoder fortfarande har oanvända kärnor, kan prestanda förbättras genom att ändra Kafka-konfigurationen. Detta är ingen lätt uppgift, så för att öka genomströmningen är det bättre att arbeta med större meddelanden.

4 mäklare, meddelandestorlek - 512 byte

Du kan enkelt öka prestandan för ett Kafka-kluster genom att helt enkelt lägga till nya mäklare och upprätthålla en balans av partitioner (detta säkerställer att belastningen är jämnt fördelad mellan mäklare). I vårt fall, efter att ha lagt till en mäklare, ökade klustrets genomströmning till ~580 Mb/s (~1,1 miljoner meddelanden per sekund). Tillväxten visade sig vara mindre än väntat: detta förklaras främst av obalansen mellan partitioner (inte alla mäklare arbetar på toppen av sina möjligheter).

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Minnesförbrukningen för JVM-maskinen förblev under 2 GB:

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Mäklares arbete med enheter påverkades av obalansen mellan partitioner:

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Bestäm lämplig storlek för ett Kafka-kluster i Kubernetes

Resultat

Det iterativa tillvägagångssättet som presenteras ovan kan utökas för att täcka mer komplexa scenarier som involverar hundratals konsumenter, ompartitionering, rullande uppdateringar, pod-omstarter, etc. Allt detta tillåter oss att bedöma gränserna för Kafka-klustrets kapacitet under olika förhållanden, identifiera flaskhalsar i dess drift och hitta sätt att bekämpa dem.

Vi designade Supertubes för att snabbt och enkelt distribuera ett kluster, konfigurera det, lägga till/ta bort mäklare och ämnen, svara på varningar och säkerställa att Kafka i allmänhet fungerar korrekt på Kubernetes. Vårt mål är att hjälpa dig att koncentrera dig på huvuduppgiften (”generera” och ”konsumera” Kafka-meddelanden), och överlåta allt det hårda arbetet till Supertubes och Kafka-operatören.

Om du är intresserad av Banzai Cloud-teknik och Open Source-projekt, prenumerera på företaget på GitHub, LinkedIn eller Twitter.

PS från översättaren

Läs även på vår blogg:

Källa: will.com

Lägg en kommentar