確定 Kubernetes 中 Kafka 集群的適當大小

筆記。 翻譯。:在本文中,Banzai Cloud 分享了一個範例,說明如何使用其自訂工具使 Kafka 在 Kubernetes 中更容易使用。 以下說明說明如何確定基礎架構的最佳規模並配置 Kafka 本身以實現所需的吞吐量。

確定 Kubernetes 中 Kafka 集群的適當大小

Apache Kafka 是一個分散式串流平台,用於創建可靠、可擴展且高效能的即時串流系統。 其令人印象深刻的功能可以使用 Kubernetes 進行擴充。 為此我們開發了 開源 Kafka 算子 和一個名為 超級管。 它們允許您在 Kubernetes 上運行 Kafka 並使用其各種功能,例如微調代理配置、基於指標的重新平衡擴展、機架感知、“軟” (優美) 推出更新等

在您的叢集中嘗試 Supertubes:

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

或聯繫 文件。 您還可以了解 Kafka 的一些功能,它的工作是使用 Supertubes 和 Kafka 運算符實現自動化的。 我們已經在部落格上寫過它們:

當您決定在 Kubernetes 上部署 Kafka 叢集時,您可能會面臨確定底層基礎架構的最佳大小以及需要微調 Kafka 配置以滿足吞吐量要求的挑戰。 每個代理程式的最大效能由底層基礎設施元件的效能決定,例如記憶體、處理器、磁碟速度、網路頻寬等。

理想情況下,代理配置應使所有基礎設施元素都能發揮其最大功能。 然而,在現實生活中,這種設定相當複雜。 使用者更有可能配置代理程式以最大限度地利用一兩個元件(磁碟、記憶體或處理器)。 一般來說,當代理的配置允許最慢的元件得到最大程度的使用時,代理就會顯示出最大的效能。 這樣我們就可以粗略地了解一個代理可以處理的負載。

理論上,我們還可以估計處理給定負載所需的代理數量。 然而,實際上,不同級別的配置選項如此之多,以至於評估特定配置的潛在性能非常困難(如果不是不可能的話)。 換句話說,根據某些給定的效能來規劃配置是非常困難的。

對於Supertubes用戶,我們通常採取以下方法:我們從一些配置(基礎設施+設定)開始,然後測量其效能,調整經紀商設定並再次重複該過程。 這種情況會一直發生,直到基礎設施中最慢的元件被充分利用為止。

這樣,我們就可以更清楚地了解一個叢集需要多少個broker來處理一定的負載(broker的數量還取決於其他因素,例如保證彈性的最小訊息副本數、分區數量等)領導等)。 此外,我們也深入了解哪些基礎設施組件需要垂直擴展。

本文將討論我們為充分利用初始配置中最慢的元件並測量 Kafka 群集的吞吐量而採取的步驟。 高彈性配置需要至少三個正在運行的代理(min.insync.replicas=3),分佈在三個不同的可訪問區域。 為了配置、擴展和監控 Kubernetes 基礎設施,我們使用自己的混合雲容器管理平台 - 管道。 它支援本地部署(裸機、VMware)和五種類型的雲端(阿里巴巴、AWS、Azure、Google、Oracle)以及它們的任意組合。

關於Kafka叢集基礎設施和配置的思考

對於下面的範例,我們選擇 AWS 作為雲端供應商,選擇 EKS 作為 Kubernetes 發行版。 可以使用類似的配置來實現 P.K.E. - Banzai Cloud 的 Kubernetes 發行版,經 CNCF 認證。

磁盤

亞馬遜提供各種 EBS 磁碟區型。 核心 gp2 и io1 不過,有 SSD 硬碟來確保高吞吐量 gp2 消耗累積積分 (I/O 積分),所以我們更喜歡這種類型 io1,提供一致的高吞吐量。

實例類型

Kafka 的效能高度依賴作業系統的頁面緩存,因此我們需要為代理(JVM)和頁面快取提供足夠記憶體的實例。 實例 c5.2xlarge - 一個好的開始,因為它有 16 GB 內存 優化以與 EBS 搭配使用。 它的缺點是每30小時只能提供不超過24分鐘的最大性能。 如果您的工作負載需要在較長時間內達到尖峰效能,您可能需要考慮其他執行個體類型。 這正是我們所做的,停在 c5.4xlarge。 它提供最大吞吐量 593,75兆位元/秒。 EBS磁碟區的最大吞吐量 io1 高於實例 c5.4xlarge,因此基礎設施中最慢的元素可能是該實例類型的 I/O 吞吐量(我們的負載測試也應該確認這一點)。

Сеть

與虛擬機器實例和磁碟的效能相比,網路吞吐量必須足夠大,否則網路將成為瓶頸。 在我們的例子中,網路接口 c5.4xlarge 支援高達 10 Gb/s 的速度,明顯高於 VM 實例的 I/O 吞吐量。

代理部署

Brokers 應部署(在 Kubernetes 中調度)到專用節點,以避免與其他進程競爭 CPU、記憶體、網路和磁碟資源。

Java版本

合理的選擇是 Java 11,因為它與 Docker 相容,因為 JVM 可以正確確定運行代理程式的容器可用的處理器和記憶體。 知道 CPU 限制很重要,JVM 在內部透明地設定 GC 執行緒和 JIT 執行緒的數量。 我們使用了 Kafka 圖像 banzaicloud/kafka:2.13-2.4.0,其中包括 Java 2.4.0 上的 Kafka 版本 2.13 (Scala 11)。

如果您想了解有關 Kubernetes 上的 Java/JVM 的更多信息,請查看我們的以下帖子:

經紀商內存設置

配置代理記憶體有兩個關鍵面向:JVM 和 Kubernetes Pod 的設定。 為 pod 設定的記憶體限制必須大於最大堆大小,以便 JVM 為駐留在其自己記憶體中的 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 群集吞吐量所需的水平。 同時,它必須具有一致的可重複性,並且表現出最小的吞吐量變化。

下一節介紹測試叢集基準測試過程中執行的步驟。

工具

以下工具用於快速部署基線配置、產生負載和測量效能:

  • 萬歲雲端管道 用於從 Amazon c 組織 EKS 叢集 普羅米修斯 (收集 Kafka 和基礎設施指標)和 格拉法納 (可視化這些指標)。 我們利用了 融合的 в 管道 提供聯合監控、集中日誌收集、漏洞掃描、災難復原、企業級安全等的服務。
  • 桑格勒內爾 — 用於對 Kafka 叢集進行負載測試的工具。
  • 用於視覺化 Kafka 指標和基礎設施的 Grafana 儀表板: 庫伯內特卡夫卡, 節點導出器.
  • Supertubes CLI 是在 Kubernetes 上設定 Kafka 叢集最簡單的方法。 Zookeeper、Kafka Operator、Envoy 和許多其他元件均已安裝並正確配置,以便在 Kubernetes 上運行生產就緒的 Kafka 叢集。
    • 安裝用 超級管 CLI 使用提供的說明 這裡.

確定 Kubernetes 中 Kafka 集群的適當大小

EKS叢集

準備具有專用工作節點的 EKS 集群 c5.4xlarge 具有 Kafka 代理程式的 Pod 位於不同的可用區域,以及負載產生器和監控基礎設施的專用節點。

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

EKS 叢集啟動並運行後,啟用其集成 監控服務 — 她將把 Prometheus 和 Grafana 部署到一個集群中。

卡夫卡系統組件

使用 supertubes CLI 在 EKS 中安裝 Kafka 系統元件(Zookeeper、kafka-operator):

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

卡夫卡集群

預設情況下,EKS 使用 EBS 磁碟區類型 gp2,所以需要根據磁碟區建立單獨的儲存類 io1 對於卡夫卡集群:

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 並在三個不同可用區的節點上部署 Broker Pod:

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

話題

我們並行運行三個負載生成器實例。 他們每個人都寫自己的主題,也就是說,我們總共需要三個主題:

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

對於每個主題,複製因子為 3 — 高可用生產系統的最小建議值。

負載產生工具

我們啟動了負載產生器的三個副本(每個副本都在單獨的主題中編寫)。 對於負載產生器 Pod,您需要設定節點關聯性,以便僅在為其指派的節點上調度它們:

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 位元組的訊息,並以 500 個訊息為批次發佈到 Kafka。
  • 使用參數 -required-acks=all 當 Kafka 代理收到並確認訊息的所有同步副本時,發布被視為成功。 這意味著在基準測試中,我們不僅測量了領導者接收訊息的速度,還測量了他們的追隨者複製訊息的速度。 此測驗的目的不是要評估消費者的閱讀速度 (消費者) 最近收到的仍保留在作業系統頁面快取中的消息,及其與儲存在磁碟上的消息的讀取速度的比較。
  • 負載產生器並行運行 20 個工作執行緒(-workers=20)。 每個worker包含5個生產者,它們共享worker與Kafka叢集的連結。 因此,每個生成器有 100 個生產者,它們都會向 Kafka 叢集發送訊息。

監控叢集的健康狀況

在 Kafka 叢集的負載測試期間,我們還監控其運行狀況,以確保沒有 pod 重新啟動、沒有不同步的副本以及最大吞吐量和最小波動:

  • 負載產生器寫入有關已發布訊息數量和錯誤率的標準統計資料。 錯誤率應該保持不變 0,00%.
  • 巡航控制由 kafka-operator 部署,提供了一個儀表板,我們也可以在其中監視叢集的狀態。 若要查看此面板,請執行以下操作:
    supertubes cluster cruisecontrol show -n kafka --kubeconfig <path-to-eks-cluster-kubeconfig-file>
  • 情監偵級別 (「同步」副本的數量) 收縮和膨脹等於 0。

測量結果

3 個代理,訊息大小 - 512 位元組

透過將分區均勻分佈在三個代理上,我們能夠實現效能 ~500 Mb/s(每秒約 990 萬則訊息):

確定 Kubernetes 中 Kafka 集群的適當大小

確定 Kubernetes 中 Kafka 集群的適當大小

確定 Kubernetes 中 Kafka 集群的適當大小

JVM虛擬機器的記憶體消耗不超過2GB:

確定 Kubernetes 中 Kafka 集群的適當大小

確定 Kubernetes 中 Kafka 集群的適當大小

確定 Kubernetes 中 Kafka 集群的適當大小

在執行代理程式的所有三個實例上,磁碟吞吐量均達到最大 I/O 節點吞吐量:

確定 Kubernetes 中 Kafka 集群的適當大小

確定 Kubernetes 中 Kafka 集群的適當大小

確定 Kubernetes 中 Kafka 集群的適當大小

從節點記憶體使用資料來看,系統緩衝和快取佔用了約 10-15 GB:

確定 Kubernetes 中 Kafka 集群的適當大小

確定 Kubernetes 中 Kafka 集群的適當大小

確定 Kubernetes 中 Kafka 集群的適當大小

3 個代理,訊息大小 - 100 位元組

隨著訊息大小的減小,吞吐量會下降約 15-20%:處理每個訊息所花費的時間會對其產生影響。 此外,處理器負載幾乎增加了一倍。

確定 Kubernetes 中 Kafka 集群的適當大小

確定 Kubernetes 中 Kafka 集群的適當大小

確定 Kubernetes 中 Kafka 集群的適當大小

由於代理節點仍然有未使用的核心,因此可以透過更改 Kafka 配置來提高效能。 這不是一件容易的任務,因此為了提高吞吐量,最好使用更大的消息。

4 個代理,訊息大小 - 512 位元組

只需新增新的代理並保持分區平衡(這可確保負載在代理之間均勻分配),您就可以輕鬆提高 Kafka 叢集的效能。 在我們的例子中,新增代理後,叢集吞吐量增加到 約 580 Mb/s(約每秒 1,1 萬則訊息)。 成長結果低於預期:這主要是由於分區不平衡造成的(並非所有經紀商都在其能力的巔峰狀態下工作)。

確定 Kubernetes 中 Kafka 集群的適當大小

確定 Kubernetes 中 Kafka 集群的適當大小

確定 Kubernetes 中 Kafka 集群的適當大小

確定 Kubernetes 中 Kafka 集群的適當大小

JVM 機器的記憶體消耗保持在 2 GB 以下:

確定 Kubernetes 中 Kafka 集群的適當大小

確定 Kubernetes 中 Kafka 集群的適當大小

確定 Kubernetes 中 Kafka 集群的適當大小

確定 Kubernetes 中 Kafka 集群的適當大小

具有驅動器的代理程式的工作受到分區不平衡的影響:

確定 Kubernetes 中 Kafka 集群的適當大小

確定 Kubernetes 中 Kafka 集群的適當大小

確定 Kubernetes 中 Kafka 集群的適當大小

確定 Kubernetes 中 Kafka 集群的適當大小

發現

上面提出的迭代方法可以擴展到涵蓋涉及數百個消費者、重新分區、滾動更新、pod 重新啟動等的更複雜的場景。 所有這些使我們能夠評估 Kafka 叢集在各種條件下的能力限制,識別其運行中的瓶頸並找到解決它們的方法。

我們設計 Supertubes 是為了快速輕鬆地部署叢集、配置叢集、新增/刪除代理程式和主題、回應警報並確保 Kafka 在 Kubernetes 上正常運作。 我們的目標是幫助您專注於主要任務(「產生」和「消費」Kafka 訊息),並將所有艱苦的工作留給 Supertubes 和 Kafka 操作員。

如果您對 Banzai Cloud 技術和開源專案感興趣,請訂閱該公司: GitHub上, LinkedInTwitter.

譯者PS

另請閱讀我們的博客:

來源: www.habr.com

添加評論