Определяме подходящия размер за клъстера Kafka в Kubernetes

Прим. прев.: В тази статия компанията Banzai Cloud споделя пример за използване на специализирани инструменти за улесняване на работата с Kafka в контекста на Kubernetes. Инструкциите илюстрират как може да се определи оптималният размер на инфраструктурата и да се настрои самата Kafka за постигане на необходимата пропускна способност.

Определяме подходящия размер за клъстера Kafka в Kubernetes

Apache Kafka е разпределена стрийминг платформа за създаване на надеждни, мащабируеми и високопроизводителни системи за поточно предаване в реално време. Впечатляващите ѝ възможности могат да бъдат разширени с помощта на Kubernetes. За това разработихме Open Source оператор на Kafka и инструмент, наречен Supertubes. Те позволяват стартиране на Kafka в Kubernetes и използване на различните ѝ функции, като фина настройка на конфигурацията на брокера, мащабиране на база метрики с ребалансиране, осведомленост за достъп до хардуерни ресурси (rack awareness), 'меко' (graceful) разгръщане на актуализации и т.н.

Опитайте Supertubes в своя кластер:

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

Или се свържете с документацията. Можете също така да прочетете за някои функции на Kafka, чиято работа е автоматизирана с помощта на Supertubes и Kafka оператора. Писали сме за тях в блога:

Решавайки да разположите кластер Kafka в Kubernetes, вероятно ще се сблъскате с проблема да определите оптималния размер на основната инфраструктура и необходимостта от фина настройка на конфигурацията на Kafka, за да отговори на изискванията за пропускна способност. Максималната производителност на всеки брокер се определя от производителността на компонентите на инфраструктурата в основата му, като памет, процесор, скорост на диска, пропускна способност на мрежата и т.н.

Идеално е конфигурацията на брокера да е такава, че всички елементи на инфраструктурата да се използват на максимум своите възможности. Въпреки това, в реалния живот такава настройка е доста сложна. По-вероятно е потребителите да настройват конфигурацията на брокерите по начин, който максимизира използването на един или два компонента (диск, памет или процесор). По принцип, брокерът показва максимална производителност, когато конфигурацията му позволява да използва най-бавния компонент „на пълна пара“. Така можем да получим приблизителна представа за натоварването, с което е способен да се справи един брокер.

Теоретично можем също да преценим броя на брокерите, необходими за работа с дадено натоварване. Въпреки това, на практика възможностите за настройка на различни нива са толкова много, че оценката на потенциалната производителност на дадена конфигурация е много сложна (ако не и невъзможна). С други думи, много трудно е да се планира конфигурация, основаваща се на предварително зададена производителност.

За потребителите на Supertubes обикновено прилагаме следния подход: започваме с определена конфигурация (инфраструктура + настройки), след това измерваме нейната производителност, коригираме настройките на брокера и повтаряме процеса отново. Това продължава, докато потенциалът на най-бавния компонент на инфраструктурата не бъде напълно включен.

По този начин получаваме по-ясна представа за това колко брокери са необходими на клъстера, за да се справи с определено натоварване (броят на брокерите също зависи от други фактори, като минималния брой реплики на съобщенията за осигуряване на устойчивост, броя на partition-лидерите и т.н.). Освен това получаваме представа за това, за кой инфраструктурен компонент е желателно вертикално мащабиране.

В тази статия ще разгледаме стъпките, които предприемаме, за да „изстискаме всичко“ от най-бавните компоненти в началните конфигурации и да измерим пропускната способност на клъстера Kafka. Конфигурацията с висока устойчивост изисква наличие на поне три работещи брокера (min.insync.replicas=3), разпределени в три различни зони на достъпност. За настройка, мащабиране и мониторинг на инфраструктурата Кubernetes използваме собствена платформа за управление на контейнери за хибридни облаци — Pipeline. Тя поддържа on-premise (bare metal, VMware) и пет типа облаци (Alibaba, AWS, Azure, Google, Oracle), както и всякакви комбинации от тях.

Размисли относно инфраструктурата и конфигурацията на кластера Kafka

За примерите, изброени по-долу, избрахме AWS като доставчик на облачни услуги и EKS като дистрибуция на Kubernetes. Подобна конфигурация може да се реализира с помощта на PKE — дистрибуция на Kubernetes от Banzai Cloud, сертифицирана от CNCF.

Диск

Amazon предлага различни типове EBS томове. В основата на gp2 и io1 лежат SSD дискове, но за осигуряване на висока пропускателна способност gp2 изразходва натрупаните кредити (I/O кредити), затова предпочетохме тип io1, който предлага стабилна висока пропускателна способност.

Типове инстанции

Производителността на Kafka зависи от кеша на страниците на операционната система, затова се нуждаем от инстанции с достатъчно памет за брокерите (JVM) и кеша на страниците. Инстанцията c5.2xlarge е добро начало, тъй като има 16 Гб памет и е оптимизирана за работа с EBS.Недостатъкът е, че може да осигури максимална производителност не повече от 30 минути на всеки 24 часа. Ако работния товар изисква максимална производителност за по-дълъг период, трябва да разгледате и други типове инстанции. Именно така постъпихме, спирайки се на c5.4xlarge.Той осигурява максимална пропускателна способност от 593,75 Мб/с.Максималната пропускателна способност на EBS тома io1 е по-висока от тази на инстанцията c5.4xlarge., затова най-бавният елемент от инфраструктурата, очевидно, е пропускателната способност I/O на този тип инстанция (което също трябва да потвърдят резултатите от нашите тестове на натоварване).

Мрежа

Пропускателната способност на мрежата трябва да бъде достатъчно голяма в сравнение с производителността на инстанцията VM и диска, в противен случай мрежата става тесен врата. В нашия случай мрежовият интерфейс c5.4xlarge. поддържа скорост до 10 Гб/с, което е значително над пропускателната способност I/O на инстанцията VM.

Разгръщане на брокерите

Брокерите трябва да се разгръщат (планират в Kubernetes) на отделни възли, за да се избегне конкуренцията с другите процеси за ресурсите на процесора, паметта, мрежата и диска.

Версия на Java

Логичният избор е Java 11, тъй като тя е съвместима с Docker в смисъл, че JVM правилно определя процесорите и паметта, налична на контейнера, в който работи брокера. Знаейки, че лимитите на процесорите са важни, JVM вътрешно и прозрачно установява броя на потоковете GC и потоковете на JIT компилатора. Ние използвахме образа Kafka banzaicloud/kafka:2.13-2.4.0, включващ версия Kafka 2.4.0 (Scala 2.13) на Java 11.

Ако искате да научите повече за Java/JVM на Kubernetes, обърнете внимание на следните наши публикации:

Настройки на паметта на брокера

Има два ключови аспекта в настройването на паметта на брокера: настройки за JVM и за pod на Kubernetes. Лимитът на паметта, зададен за pod, трябва да бъде по-голям от максималния размер на heap, за да остане място за метапространството на Java, което е в собствената памет, и за кеша на страниците на операционната система, който Kafka активно използва. В нашите тестове стартирахме брокери на Kafka с параметри -Xmx4G -Xms2G, а лимитът на паметта за pod беше 10 Gi. Обърнете внимание, че настройките за паметта на JVM могат да се получават автоматично с помощта на -XX:MaxRAMPercentage и -X:MinRAMPercentage, базирано на лимита на паметта за pod.

Настройки на процесора на брокера

Говорейки общо, може да се повиши производителността, увеличавайки паралелизма чрез нарастване на броя на потоковете, използвани от Kafka. Колкото повече процесори са налични за Kafka, толкова по-добре. В нашия тест започнахме с лимит от 6 процесора и постепенно (чрез итерации) увеличихме броя им до 15. Освен това зададохме num.network.threads=12 в настройките на брокера, за да увеличим броя на потоковете, приемащи данни от мрежата и изпращащи ги. Веднага установихме, че брокерите-последователи не могат да получават реплики достатъчно бързо и увеличихме num.replica.fetchers до 4, за да увеличим скоростта, с която брокерите-последователи репликират съобщения от лидери.

Инструмент за генериране на натоварване

Трябва да се уверим, че потенциалът на избрания генератор на натоварване няма да свърши, преди кластерът Kafka (за който се провежда бенчмарка) да достигне своята максимална натовареност. С други думи, трябва да направим предварителна оценка на възможностите на инструмента за генериране на натоварване и да изберат типове инстанции с достатъчен брой процесори и памет. В този случай нашият инструмент ще генерира повече натоварване, отколкото кластерът Kafka може да обработи. След множество експерименти, спряха на три инстанции c5.4xlarge., във всяка от които беше стартиран генератор.

Бенчмаркинг

Измерването на представянето е итеративен процес, който включва следните етапи:

  • настройка на инфраструктурата (кластера EKS, кластера Kafka, инструмента за генериране на натоварване, както и Prometheus и Grafana);
  • генериране на натоварване в продължение на определен период за филтриране на случайни отклонения в събираните показатели за представяне;
  • настройка на инфраструктурата и конфигурацията на брокера на базата на наблюдаваните показатели за представяне;
  • повторение на процеса, докато не се постигне необходимото ниво на пропускателна способност на кластера Kafka. При това той трябва да бъде стабилно воспроизводим и да показва минимални вариации на пропускателната способност.

В следващия раздел са описани стъпките, които бяха предприети в процеса на бенчмарка на тестовия кластер.

Инструменти

За бързо разгръщане на базовата конфигурация, генериране на натоварване и измерване на представянето бяха използвани следните инструменти:

  • Banzai Cloud Pipeline за организиране на кластера EKS на Amazon с Prometheus (за събиране на метрики от Kafka и инфраструктурата) и Grafana (за визуализиране на тези метрики). Използвахме интегрирани в Pipeline услуги, които осигуряват федеративен мониторинг, централизирано събиране на логове, сканиране за уязвимости, възстановяване след аварии, сигурност на корпоративно ниво и много други.
  • Sangrenel — инструмент за стрес тестиране на кластера Kafka.
  • Панелите на Grafana за визуализиране на метрики от Kafka и инфраструктурата: Kubernetes Kafka, Node Exporter.
  • Supertubes CLI за максимално лесна настройка на Kafka клъстера в Kubernetes. Zookeeper, Kafka оператор, Envoy и много други компоненти са инсталирани и конфигурирани правилно за стартиране на готов за продукция Kafka клъстер в Kubernetes.
    • За инсталация supertubes CLI использвайте инструкциите, приведенные тук.

Определяме подходящия размер за клъстера Kafka в Kubernetes

Клъстер EKS

Подгответе клъстера EKS с отделени работни възли c5.4xlarge. в различни зони на достъпност за подовете с Kafka брокери и отделени възли за генериране на натоварване и мониторингова инфраструктура.

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

Когато клъстерът EKS заработи, активирайте неговата интегрирана услуга за мониторинг — тя ще разверне Prometheus и Grafana в клъстера.

Системни компоненти на Kafka

Инсталирайте системните компоненти на Kafka (Zookeeper, kafka-operator) в EKS с помощта на supertubes CLI:

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

Клъстер Kafka

По подразбиране в EKS се използват EBS томове от тип gp2, затова е необходимо да се създаде отделен клас за съхранение на базата на томове io1 за клъстера 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

Задайте параметъра за брокерите min.insync.replicas=3 и разположете подовете на брокерите на възлите в три различни зони на достъпност:

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

Топици

Същевременно стартирахме три екземпляра на генератора на натоварване. Всеки от тях записва в своя собствен топик, т.е. общо се нуждаем от три топика:

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

За всеки топик факторът на репликация е 3 — минимално препоръчваното значение за високо-достъпни производствени системи.

Инструмент за генериране на натоварване

Стартирахме три инстанции на генератора на натоварването (всяка от които пише в отделна тема). За pod'овете на генератора на натоварването е необходимо да зададете node affinity, за да бъдат планирани само на определените за тях възли:

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

Няколко момента, на които трябва да обърнете внимание:

  • Генераторът на натоварването генерира съобщения с дължина 512 байта и ги публикува в Kafka на партии от 500 съобщения.
  • С помощта на аргумента -required-acks=all публикацията се счита за успешна, когато всички синхронизирани реплики на съобщението са получени и потвърдени от брокерите на Kafka. Това означава, че в теста измервахме не само скоростта на работа на лидерите, които получават съобщения, но и техните последователи, репликиращи съобщения. Задачата на този тест не е да оценява скоростта на четене на потребители (consumers) на наскоро приети съобщения, които все още остават в страницовия кеш на ОС, и нейното сравнение със скоростта на четене на съобщения, съхранявани на диска.
  • Генераторът на натоварването стартира 20 worker'а паралелно (-workers=20). Всеки worker съдържа 5 продюсера, които споделят връзката на worker'а с кластера Kafka. В крайна сметка всеки генератор има 100 продюсера, които всички изпращат съобщения в кластера Kafka.

Наблюдение на състоянието на клъстера

По време на натоварващо тестване на Kafka клъстера, ние също следяхме за неговото здраве, за да се уверим, че няма перезапускане на pod’овете, несинхронизирани реплики и максимална пропускна способност с минимални флуктуации:

  • Генераторът на натоварване извежда стандартна статистика за броя на публикуваните съобщения и нивото на грешките. Процентът на грешките трябва да остане на стойност 0,00%.
  • Cruise Control, внедрен от kafka-operator, предоставя панел за мониторинг, на който можем също да наблюдаваме състоянието на клъстера. За да видите този панел, изпълнете:
    supertubes cluster cruisecontrol show -n kafka --kubeconfig
  • Нивото ISR (броят на репликите "in-sync") shrink и expansion равен на 0.

Резултатите от измерванията

3 брокера, размер на съобщенията — 512 байта

С partition’ите, равномерно разпределени по трите брокера, успяхме да постигнем производителност ~500 Мб/с (приблизително 990 хил. съобщения в секунда):

Определяме подходящия размер за клъстера Kafka в Kubernetes

Определяме подходящия размер за клъстера Kafka в Kubernetes

Определяме подходящия размер за клъстера Kafka в Kubernetes

Консумацията на памет от виртуалната машина JVM не надвиши 2 Гб:

Определяме подходящия размер за клъстера Kafka в Kubernetes

Определяме подходящия размер за клъстера Kafka в Kubernetes

Определяме подходящия размер за клъстера Kafka в Kubernetes

Пропускната способност на диска достигна максималната I/O пропускна способност на възела на всички три инстанции, на които работиха брокерите:

Определяме подходящия размер за клъстера Kafka в Kubernetes

Определяме подходящия размер за клъстера Kafka в Kubernetes

Определяме подходящия размер за клъстера Kafka в Kubernetes

Данните за използването на паметта от възлите показват, че системното буфериране и кеширане заеха около ~10-15 Гб:

Определяме подходящия размер за клъстера Kafka в Kubernetes

Определяме подходящия размер за клъстера Kafka в Kubernetes

Определяме подходящия размер за клъстера Kafka в Kubernetes

3 брокера, размер на съобщенията — 100 байта

С намаляване на размера на съобщенията, пропускната способност намалява с около 15-20%: влияе времето, нужно за обработка на всяко съобщение. Освен това, натоварването на процесора нарасна почти двойно.

Определяме подходящия размер за клъстера Kafka в Kubernetes

Определяме подходящия размер за клъстера Kafka в Kubernetes

Определяме подходящия размер за клъстера Kafka в Kubernetes

Тъй като в брокерските възли все още има неизползвани ядра, производителността може да се увеличи чрез променяне на конфигурацията на Kafka. Това е сложна задача, затова за увеличаване на пропускната способност е по-добре да работите с по-големи съобщения.

4 брокера, размер на съобщенията — 512 байта

Може лесно да увеличите производителността на Kafka клъстера, просто добавяйки нови брокери и запазвайки баланса на partition’ите (това осигурява равномерно разпределение на натоварването между брокерите). В нашия случай, след добавяне на брокер, пропускната способност на клъстера нарасна до ~580 Мб/с (~1,1 млн. съобщения в секунда). Ръстът се оказа по-малък от очакваното: предимно поради дисбаланс на partition’ите (не всички брокери работят на пълен капацитет).

Определяме подходящия размер за клъстера Kafka в Kubernetes

Определяме подходящия размер за клъстера Kafka в Kubernetes

Определяме подходящия размер за клъстера Kafka в Kubernetes

Определяме подходящия размер за клъстера Kafka в Kubernetes

Потреблението на памет от JVM машината остана под 2 Гб:

Определяме подходящия размер за клъстера Kafka в Kubernetes

Определяме подходящия размер за клъстера Kafka в Kubernetes

Определяме подходящия размер за клъстера Kafka в Kubernetes

Определяме подходящия размер за клъстера Kafka в Kubernetes

На работата на брокерите с хранилища повлия дисбалансът на партициите:

Определяме подходящия размер за клъстера Kafka в Kubernetes

Определяме подходящия размер за клъстера Kafka в Kubernetes

Определяме подходящия размер за клъстера Kafka в Kubernetes

Определяме подходящия размер за клъстера Kafka в Kubernetes

Изводи

Представеният по-горе итеративен подход може да бъде разширен, за да обхване по-сложни сценарии, включващи стотици консуматори, преразпределение, актуализации на място, рестартиране на подове и т.н. Всичко това ни позволява да оценим границите на възможностите на кластера Kafka при различни условия, да идентифицираме тесни места в работата му и да намерим начини да се справим с тях.

Разработихме Supertubes за бързо и лесно разгръщане на клъстера, неговата конфигурация, добавяне/изтриване на брокери и теми, реагиране на известия и осигуряване на правилната работа на Kafka в Kubernetes. Нашата цел е да помогнем да се фокусирате върху основната задача („генериране“ и „консумиране“ на съобщения Kafka), а цялата тежка работа да предоставите на Supertubes и Kafka оператора.

Ако се интересувате от технологии и Open Source проекти на Banzai Cloud, абонирайте се за компанията на GitHub, LinkedIn или Twitter.

P.S. от преводача

Прочетете също в нашия блог:

Източник: habr.com

Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри 🔥 Купете надежден хостинг за сайтове с защита от DDoS, VPS VDS сървъри | ProHoster