笔记。 翻译。:在本文中,Banzai Cloud 分享了一个示例,说明如何使用其自定义工具使 Kafka 在 Kubernetes 中更易于使用。 以下说明说明了如何确定基础设施的最佳规模并配置 Kafka 本身以实现所需的吞吐量。
Apache Kafka 是一个分布式流平台,用于创建可靠、可扩展和高性能的实时流系统。 其令人印象深刻的功能可以使用 Kubernetes 进行扩展。 为此我们开发了
在您的集群中尝试 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 基础设施,我们使用自己的混合云容器管理平台 -
关于Kafka集群基础设施和配置的思考
对于下面的示例,我们选择 AWS 作为云提供商,选择 EKS 作为 Kubernetes 发行版。 可以使用类似的配置来实现
磁盘
亚马逊提供各种
实例类型
Kafka 的性能高度依赖于操作系统的页面缓存,因此我们需要为代理(JVM)和页面缓存提供足够内存的实例。 实例 c5.2xlarge - 一个好的开始,因为它有 16 GB 内存
Сеть
与虚拟机实例和磁盘的性能相比,网络吞吐量必须足够大,否则网络将成为瓶颈。 在我们的例子中,网络接口 c5.4xlarge 支持高达 10 Gb/s 的速度,明显高于 VM 实例的 I/O 吞吐量。
代理部署
Brokers 应部署(在 Kubernetes 中调度)到专用节点,以避免与其他进程竞争 CPU、内存、网络和磁盘资源。
爪哇版
合理的选择是 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 使用提供的说明
这里 .
- 用于安装 超级管 CLI 使用提供的说明
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 集群启动并运行后,启用其集成
卡夫卡系统组件
使用 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 万条消息):
JVM虚拟机的内存消耗不超过2GB:
在运行代理的所有三个实例上,磁盘吞吐量均达到最大 I/O 节点吞吐量:
从节点内存使用数据来看,系统缓冲和缓存占用了约 10-15 GB:
3 个代理,消息大小 - 100 字节
随着消息大小的减小,吞吐量会下降大约 15-20%:处理每条消息所花费的时间会对其产生影响。 此外,处理器负载几乎增加了一倍。
由于代理节点仍然有未使用的核心,因此可以通过更改 Kafka 配置来提高性能。 这不是一件容易的任务,因此为了提高吞吐量,最好使用更大的消息。
4 个代理,消息大小 - 512 字节
只需添加新的代理并保持分区平衡(这可确保负载在代理之间均匀分配),您就可以轻松提高 Kafka 集群的性能。 在我们的例子中,添加代理后,集群吞吐量增加到 约 580 Mb/s(约每秒 1,1 万条消息)。 增长结果低于预期:这主要是由于分区不平衡造成的(并非所有经纪商都在其能力的巅峰状态下工作)。
JVM 机器的内存消耗保持在 2 GB 以下:
具有驱动器的代理的工作受到分区不平衡的影响:
发现
上面提出的迭代方法可以扩展到涵盖涉及数百个消费者、重新分区、滚动更新、pod 重新启动等的更复杂的场景。 所有这些使我们能够评估 Kafka 集群在各种条件下的能力限制,识别其运行中的瓶颈并找到解决它们的方法。
我们设计 Supertubes 是为了快速轻松地部署集群、配置集群、添加/删除代理和主题、响应警报并确保 Kafka 在 Kubernetes 上正常运行。 我们的目标是帮助您专注于主要任务(“生成”和“消费”Kafka 消息),并将所有艰苦的工作留给 Supertubes 和 Kafka 操作员。
如果您对 Banzai Cloud 技术和开源项目感兴趣,请订阅该公司:
译者PS
另请阅读我们的博客:
- «
关于 K8s 中的 Redis 操作员的一个故事以及用于分析该数据库中的数据的实用程序的简短回顾 “; - «
RabbitMQ 无缝迁移到 Kubernetes “; - «
CoreOS 中的 zetcd:用 etcd 存储替换 ZooKeeper “。
来源: habr.com