关于kafka:Kafka-负载均衡在-vivo-的落地实践

71次阅读

共计 9561 个字符,预计需要花费 24 分钟才能阅读完成。

​vivo 互联网服务器团队 -You Shuo

正本迁徙是 Kafka 最高频的操作,对于一个领有几十万个正本的集群,通过人工去实现正本迁徙是一件很艰难的事件。Cruise Control 作为 Kafka 的运维工具,它蕴含了 Kafka 服务高低线、集群内负载平衡、正本扩缩容、正本缺失修复以及节点降级等性能。显然,Cruise Control 的呈现,使得咱们可能更容易的运维大规模 Kafka 集群。
备注:本文基于 Kafka 2.1.1 发展。

一、Kafka 负载平衡

1.1 生产者负载平衡

Kafka 客户端能够应用分区器根据音讯的 key 计算分区,如果在发送音讯时未指定 key,则默认分区器会基于 round robin 算法为每条音讯调配分区;

否则会基于 murmur2 哈希算法计算 key 的哈希值,并与分区数取模的到最初的分区编号。

很显然,这并不是咱们要探讨的 Kafka 负载平衡,因为生产者负载平衡看起来并不是那么的简单。

1.2 消费者负载平衡

思考到消费者高低线、topic 分区数变更等状况,KafkaConsumer 还须要负责与服务端交互执行分区再调配操作,以保障消费者可能更加平衡的生产 topic 分区,从而晋升生产的性能;

Kafka 目前支流的分区调配策略有 2 种(默认是 range,能够通过 partition.assignment.strategy 参数指定):

  • range: 在保障平衡的前提下,将间断的分区调配给消费者,对应的实现是 RangeAssignor;
  • round-robin:在保障平衡的前提下,轮询调配,对应的实现是 RoundRobinAssignor;
  • 0.11.0.0 版本引入了一种新的分区调配策略 StickyAssignor,其劣势在于可能保障分区平衡的前提下尽量放弃原有的分区调配后果,从而防止许多冗余的分区调配操作,缩小分区再调配的执行工夫。

无论是生产者还是消费者,Kafka 客户端外部曾经帮咱们做了负载平衡了,那咱们还有探讨负载平衡的必要吗?答案是必定的,因为Kafka 负载不均的次要问题存在于服务端而不是客户端。

二、Kafka 服务端为什么要做负载平衡

咱们先来看一下 Kafka 集群的流量散布(图 1)以及新上线机器后集群的流量散布(图 2):

从图 1 能够看出资源组内各 broker 的流量散布并不是很平衡,而且因为局部 topic 分区集中散布在某几个 broker 上,当 topic 流量突增的时候,会呈现只有局部 broker 流量突增。

这种状况下,咱们就须要扩容 topic 分区或手动执行迁挪动操作。

图 2 是咱们 Kafka 集群的一个资源组扩容后的流量散布状况,流量无奈主动的摊派到新扩容的节点上。此时,就须要咱们手动的触发数据迁徙,从而能力把流量引到新扩容的节点上。

2.1 Kafka 存储构造

为什么会呈现上述的问题呢?这个就须要从 Kafka 的存储机制说起。

下图是 Kafka topic 的存储构造,其具体层级构造形容如下:

  1. 每个 broker 节点能够通过 logDirs 配置项指定多个 log 目录,咱们线上机器共有 12 块盘,每块盘都对应一个 log 目录。
  2. 每个 log 目录下会有若干个 [topic]-[x] 字样的目录,该目录用于存储指定 topic 指定分区的数据,对应的如果该 topic 是 3 正本,那在集群的其余 broker 节点上会有两个和该目录同名的目录。
  3. 客户端写入 kafka 的数据最终会依照工夫程序成对的生成.index、.timeindex、.snapshot 以及.log 文件,这些文件保留在对应的 topic 分区目录下。
  4. 为了实现高可用目标,咱们线上的 topic 个别都是 2 正本 / 3 正本,topic 分区的每个正本都散布在不同的 broker 节点上,有时为了升高机架故障带来的危险,topic 分区的不同正本也会被要求调配在不同机架的 broker 节点上。

理解完 Kafka 存储机制之后,咱们能够清晰的理解到,客户端写入 Kafka 的数据会依照 topic 分区被路由到 broker 的不同 log 目录下,只有咱们不人工干预,那每次路由的后果都不会扭转。因为每次路由后果都不会扭转,那么 问题来了

随着 topic 数量一直增多,每个 topic 的分区数量又不统一,最终就会呈现topic 分区在 Kafka 集群内调配不均 的状况。

比方:topic1 是 10 个分区、topic2 是 15 个分区、topic3 是 3 个分区,咱们集群有 6 台机器。那 6 台 broker 上总会有 4 台 broker 有两个 topic1 的分区,有 3 台 broke 上有 3 个 topic3 分区等等。

这样的问题就会导致分区多的 broker 上的出入流量可能要比其余 broker 上要高,如果要思考同一 topic 不同分区流量不统一、不同 topic 流量又不统一,再加上咱们线上有 7000 个 topic、13 万个分区、27 万个正本等等这些。

这么简单的状况下,集群内总会有 broker 负载特地高,有的 broker 负载特地低,当 broker 负载高到肯定的时候,此时就须要咱们的运维同学染指进来了,咱们须要帮这些 broker 减减压,从而间接的晋升集群总体的负载能力。

集群整体负载都很高,业务流量会持续增长的时候,咱们会往集群内扩机器。有些同学想扩机器是坏事呀,这会有什么问题呢?问题和下面是一样的,因为发往 topic 分区的数据,其路由后果不会扭转,如果没有人工干预的话,那新扩进来机器的流量就始终是 0,集群内原来的 broker 负载仍然得不到加重。

三、如何对 Kafka 做负载平衡

3.1 人工生成迁徙打算和迁徙

如下图所示,咱们模仿一个简略的场景,其中的 T0-P0-R0 示意 topic- 分区 - 正本,假如 topic 各分区流量雷同,假如每个分区 R0 正本是 leader。

咱们能够看到,有两个 topic T0 和 T1,T0 是 5 分区 2 正本(出入流量为 10 和 5),T1 是 3 分区 2 正本(出入流量为 5 和 1),如果严格思考机架的话,那 topic 正本的散布可能如下:

假如咱们当初新扩入一台 broker3(Rack2),如下图所示:因为之前思考了 topic 在机架上的散布,所以从整体上看,broker2 的负载要高一些。

咱们当初想把 broker2 上的一些分区迁徙到新扩进来的 broker3 上,综合思考机架、流量、正本个数等因素,咱们将 T0-P2-R0、T0-P3-R1、T0-P4-R0、T1-P0-R1 四个分区迁徙到 broker3 上。

看起来还不是很平衡,咱们再将 T1-P2 分区切换一下 leader:

经验一番折腾后,整个集群就平衡许多了,对于下面迁徙正本和 leader 切换的命令参考如下:

Kafka 正本迁徙脚本

# 正本迁徙脚本:kafka-reassign-partitions.sh
# 1. 配置迁徙文件
$ vi topic-reassignment.json
{"version":1,"partitions":[{"topic":"T0","partition":2,"replicas":[broker3,broker1]},
{"topic":"T0","partition":3,"replicas":[broker0,broker3]},
{"topic":"T0","partition":4,"replicas":[broker3,broker1]},
{"topic":"T1","partition":0,"replicas":[broker2,broker3]},
{"topic":"T1","partition":2,"replicas":[broker2,broker0]}
]}
# 2. 执行迁徙命令
bin/kafka-reassign-partitions.sh --throttle 73400320 --zookeeper zkurl --execute --reassignment-json-file topic-reassignment.json
# 3. 查看迁徙状态 / 革除限速配置
bin/kafka-reassign-partitions.sh --zookeeper zkurl --verify --reassignment-json-file topic-reassignment.json

3.2 应用负载平衡工具 -cruise control

通过对 Kafka 存储构造、人工干预 topic 分区散布等的理解后,咱们能够看到 Kafka 运维起来是十分繁琐的,那有没有一些工具能够帮忙咱们解决这些问题呢?

答案是必定的。

cruise control 是 LinkedIn 针对 Kafka 集群运维艰难问题而开发的一个我的项目,cruise control 可能对 Kafka 集群各种资源进行动静负载平衡,这些资源包含:CPU、磁盘使用率、入流量、出流量、正本散布等,同时 cruise control 也具备首选 leader 切换和 topic 配置变更等性能。

3.2.1 cruise cotnrol 架构

咱们先简略介绍下 cruise control 的架构。

如下图所示,其次要由Monitor、Analyzer、Executor 和 Anomaly Detector 四局部组成:

(1)Monitor

Monitor 分为客户端 Metrics Reporter 和服务端 Metrics Sampler:

  • Metrics Reporter实现了 Kafka 的指标上报接口 MetricsReporter,以特定的格局将原生的 Kafka 指标上报到 topic \_\_CruiseControlMetrics 中。
  • Metrics Sampler从 \_\_CruiseControlMetrics 中获取原生指标后依照 broker 和分区级指标别离进行聚合,聚合后的指标蕴含了 broker、分区负载的均值、最大值等统计值,这些两头后果将被发送 topic \_\_KafkaCruiseControlModelTrainingSamples 和 \_\_KafkaCruiseControlPartitionMetricSamples 中;

(2)Analyzer

Analyzer 作为 cruise control 的外围局部,它依据用户提供的优化指标和基于 Monitor 生成的集群负载模型生成迁徙打算。

在 cruise control 中,“用户提供的优化指标”包含硬性指标和软性指标两大类,硬性指标是 Analyzer 在做预迁徙的时候必须满足的一类指标(例如:正本在迁徙后必须满足机架分散性准则),软性指标则是尽可能要达到的指标,如果某一副本在迁徙后只能同时满足硬性指标和软性指标中的一类,则以硬性指标为主,如果存在硬性指标无奈满足的状况则本次剖析失败。

Analyzer 可能须要改良的中央:

  1. 因为 Monitor 生成的是整个集群的负载模型,咱们的 Kafka 平台将 Kafka 集群划分为多个资源组,不同资源组的资源利用率存在很大差异,所以原生的集群负载模型不再实用于咱们的利用场景。
  2. 大多数业务没有指定 key 进行生产,所以各分区的负载偏差不大。如果 topic 分区正本均匀分布在资源组内,则资源组也随之变得平衡。
  3. 原生的 cruise control 会从集群维度来开展平衡工作,指定资源组后能够从资源组维度开展平衡工作,但无奈满足跨资源组迁徙的场景。

(3)Executor

Executor 作为一个执行者,它执行 Analyzer 剖析失去的迁徙打算。它会将迁徙打算以接口的模式分批提交到 Kafka 集群上,后续 Kafka 会依照提交上来的迁徙脚本执行正本迁徙。

Executor 可能须要改良的中央:

cruise control 在执行正本迁徙类的性能时,不能触发集群首选 leader 切换:有时在集群平衡过程中呈现了宕机重启,以问题机器作为首选 leader 的分区,其 leader 不能主动切换回来,造成集群内其余节点压力陡增,此时往往会产生连锁反应。

(4)Anomaly Detector

Anomaly Detector 是一个定时工作,它会定期检测 Kafka 集群是否不平衡或者是否有正本缺失这些异常情况,当 Kafka 集群呈现这些状况后,Anomaly Detector 会主动触发一次集群内的负载平衡。

在前面的次要性能形容中,我会次要介绍 MonitorAnalyzer的解决逻辑。

3.2.2 平衡 broker 出入流量 / 机器高低线平衡

对于 Kafka 集群内各 broker 之间流量负载不均的起因、示意图以及解决方案,咱们在下面曾经介绍过了,那么cruise control 是如何解决这个问题的

其实 cruise control 平衡集群的思路和咱们手动去平衡集群的思路大体一致,只不过它须要 Kafka 集群具体的指标数据,以这些指标为根底,去计算各 broker 之间的负载差距,并依据咱们关注的资源去做剖析,从而得出最终的迁徙打算。

以 topic 分区 leader 正本这类资源为例:

服务端在接管到平衡申请后,Monitor会先依据缓存的集群指标数据构建一个可能形容整个集群负载散布的模型。

下图简略形容了整个集群负载信息的生成过程,smaple fetcher线程会将获取到的原生指标加载成可读性更好的 Metric Sample,并对其进行进一步的加工,失去带有 brokerid、partition 分区等信息的统计指标,这些指标保留在对应 broker、replica 的 load 属性中,所以 broker 和 repilca 会蕴含流量负载、存储大小、以后正本是否是 leader 等信息。

Analyzer 会遍历咱们指定的 broker(默认是集群所有的 broker),因为每台 broker 及其上面的 topic 分区正本都有具体的指标信息,剖析算法间接依据这些指标和指定资源对 broker 进行排序。

本例子的资源就是 topic 分区 leader 正本数量,接着 Analyzer 会依据咱们提前设置的最大 / 最小阈值、离散因子等来判断以后 broker 上某 topic 的 leader 正本数量是否须要减少或缩减,如果是减少,则变更 clustermodel 将负载比拟高的 broker 上对应的 topic leader 正本迁徙到以后 broker 上,反之亦然,在前面的革新点中,咱们会对 Analyzer 的工作过程做简略的形容。

遍历过所有 broker,并且针对咱们指定的所有资源都进行剖析之后,就得出了最终版的 clustermodel,再与咱们最后生成的 clustermodel 比照,就生成了 topic 迁徙打算。

cruise control 会依据咱们指定的迁徙策略分批次的将 topic 迁徙打算提交给 kafka 集群执行。

迁徙打算示意图如下:

3.2.3 首选 leader 切换

切换非首选 leader 正本,迁徙打算示意图如下:

3.2.4 topic 配置变更

扭转 topic 正本个数,迁徙打算示意图如下:

3.3 革新 cruise control

3.3.1 指定资源组进行平衡

当集群规模十分宏大的时候,咱们想要平衡整个集群就变得十分艰难,往往平衡一次就须要半个月甚至更长时间,这在无形之中也加大了咱们运维同学的压力。

针对这个场景,咱们对 cruise control 也进行了革新,咱们从逻辑上将 Kafka 集群划分成多个资源组,使得业务领有本人的资源组,当某个业务呈现流量稳定的时候,不会影响到其余的业务。

通过指定资源组,咱们每次只须要对集群的一小部分或多个局部进行平衡即可,大大缩短了平衡的工夫,使得平衡的过程更加可控。

革新后的 cruise control 能够做到如下几点:

  1. 通过平衡参数,咱们能够只平衡某个或多个资源组的 broker。
  2. 更改 topic 配置,比方减少 topic 正本时,新扩的正本须要和 topic 原先的正本在同一个资源组内。
  3. 在资源组内剖析 broker 上的资源是迁入还是迁出。对于每一类资源指标,cruise control 是计算资源组范畴内的统计指标,而后联合阈值和离散因子来剖析 broker 是迁出资源还是迁入资源。

如下图所示,咱们将集群、资源组、以及资源组下的 topic 这些元数据保留在数据库中,Analyzer 得以在指定的资源组范畴内,对每个 broker 依照资源散布指标做平衡剖析。

例如:当对 broker- 0 做平衡剖析的时候,Analyzer 会遍历 goals 列表,每个 goals 负责一类资源负载指标(cpu、入流量等),当平衡剖析达到 goal- 0 的时候,goal- 0 会判断 broker- 0 的负载是否超出下限阈值,如果超出,则须要将 broker- 0 的一些 topic 正本迁徙到负载较低的 broker 上;反之,则须要将其余 broker 上的正本迁徙到 broker- 0 上。

其中,上面的 recheck goals 是排在前面的 goal 在做平衡剖析的时候,在更新 cluster model 之前会判断本次迁徙会不会与之前的 goal 抵触,如果抵触,那就不更新 cluster model,以后的 goal 会持续尝试往其余 broker 上迁徙,直到找到适宜的迁徙指标,而后更新 cluster model。

3.3.2 topic/topic 分区往指定 broker 上迁徙

思考这些场景:

  1. 一个我的项目下会有几个资源组,因为业务变更,业务想要把 A 资源组下的 topic 迁徙到 B 资源组。
  2. 业务想要把公共资源组的 topic 迁徙到 C 资源组。
  3. 平衡实现之后,发现总有几个 topic/ 分区散布不是很平均。

面对这些场景,咱们下面指定资源组进行平衡的性能就满足不了咱们的需要了。所以,咱们针对上述场景革新后的 cruise control 能够做到如下几点:

  1. 只平衡指定的 topic 或 topic 分区;
  2. 平衡的 topic 或 topic 分区只往指定的 broker 上迁徙。

3.3.3 新增指标剖析——topic 分区 leader 正本分散性

业务方大多都是没有指定 key 进行发送数据的,所以同一 topic 每个分区的流量、存储都是靠近的,即每一个 topic 的各个分区的 leader 正本尽可能平均的散布在集群的 broker 上时,那集群的负载就会很平均。

有同学会问了,topic 分区数并不总是可能整除 broker 数量,那最初各 broker 的负载不还是不统一嘛?

答案是必定的,只通过分区的 leader 正本还不能做到最终的平衡。

针对上述场景革新后的 cruise control 能够做到如下几点:

  1. 新增一类资源剖析:topic 分区 leader 正本分散性。
  2. 首先保障每个 topic 的 leader 正本和 follower 正本尽可能的均匀分布在资源组的 broker 上。
  3. 在 2 的根底上,正本会尽可能的往负载较低的 broker 上散布。

如下图所示,针对每一个 topic 的正本,Analyzer会顺次计算以后 broker 的 topic leader 数是否超过阈值下限,如果超过,则 Analyzer 会依照 topic 的 leader 正本数量、topic 的 follower 正本数量、broker 的出流量负载等来选出 AR 中的 follower 正本作为新的 leader 进行切换,如果 AR 正本中也没有符合要求的 broker,则会抉择 AR 列表以外的 broker。

3.3.4 最终平衡成果

下图是某个资源组平衡后的流量散布,各节点间流量偏差十分小,这种状况下,既能够加强集群扛住流量异样突增的能力又能够晋升集群整体资源利用率和服务稳定性,降低成本。

3.4 装置 / 部署 cruise control

3.4.1 客户端部署:指标采集

【步骤 1】:创立 Kafka 账号,用于前面生产和生产指标数据

【步骤 2】:创立 3 个 Kafka 外部 topic:a 是用来存储 Kafka 服务原生 jmx 指标;b 和 c 别离是用来存储 cruise control 解决过后的分区和模型指标;

【步骤 3】:给步骤 1 创立的账号授予读 / 写以及集群的操作权限,用于读 / 写步骤 2 创立的 topic;

【步骤 4】:批改 kafka 的 server.properties,减少如下配置:

在 Kafka 服务上配置采集程序

# 批改 kafka 的 server.properties
metric.reporters=com.linkedin.kafka.cruisecontrol.metricsreporter.CruiseControlMetricsReporter
cruise.control.metrics.reporter.bootstrap.servers= 域名:9092
 
cruise.control.metrics.reporter.security.protocol=SASL_PLAINTEXT
cruise.control.metrics.reporter.sasl.mechanism=SCRAM-SHA-256
cruise.control.metrics.reporter.sasl.jaas.config=org.apache.kafka.common.security.scram.ScramLoginModule required username=\"ys\" password=\"ys\";

【步骤 5】:增加 cruise-control-metrics-reporter 的 jar 包到 Kafka 的 lib 目录下:mv cruise-control-metrics-reporter-2.0.104-SNAPSHOT.jar kafka\_dir/lib/;

【步骤 6】:重启 Kafka 服务。

3.4.2 服务端部署:指标聚合 / 平衡剖析

(1)到 https://github.com/linkedin/cruise-control 下载 zip 文件并解压;

(2)将本人本地 cruise control 子模块下生成的 jar 包替换 cruise control 的:mv cruise-control-2.0.xxx-SNAPSHOT.jar cruise-control/build/libs;

(3)批改 cruise control 配置文件,次要关注如下配置:

# 批改 cruise control 配置文件
security.protocol=SASL_PLAINTEXT
sasl.mechanism=SCRAM-SHA-256
sasl.jaas.config=org.apache.kafka.common.security.scram.ScramLoginModule required username=\"ys\" password=\"ys\";
bootstrap.servers= 域名:9092
zookeeper.connect=zkURL

(4)批改数据库连贯配置:

# 集群 id
cluster_id=xxx  
db_url=jdbc:mysql://hostxxxx:3306/databasexxx
db_user=xxx
db_pwd=xxx

四、总结

通过以上的介绍,咱们能够看出 Kafka 存在比拟显著的两个缺点:

  1. Kafka 每个 partition replica 与机器的磁盘绑定,partition replica 由一系列的 Segment 组成,所以往往单分区存储会占用比拟大的磁盘空间,对于磁盘会有很大压力。
  2. 在集群扩容 broker 时必须做 Rebalance,须要 broker 有良好的执行流程,保障没有任何故障的状况下使得各 broker 负载平衡。

cruise control 就是针对 Kafka 集群运维艰难问题而诞生的,它可能很好的解决 kafka 运维艰难的问题。

参考文章:

  1. linkedIn/cruise-control
  2. Introduction to Kafka Cruise Control
  3. Cloudera Cruise Control REST API Reference
  4. http://dockone.io/article/2434664
  5. . https://www.zhenchao.org/2019/06/22/kafka/kafka-log-manage/

正文完
 0