摘要:因为在我们实际的运维过程中,需要指定某个副本为ISR,但是Kafka中的Leader选举策略并不支持这个功能,所以需要我们自己来实现它。

本文分享自华为云社区《Kafka的指定副本作为Leader的三种实现方式》,作者:石臻臻的杂货铺。

前几天有个群友问到: kafka如何修改优先副本? 他们有个需求是, 想指定某个分区中的其中一个副本为Leader。

需求分析

对于这么一个问题,在我们生产环境还是挺常见的,经常有需要修改某个Topic中某分区的Leader

比如 topic1-0这个分区有3个副本[0,1,2], 按照「优先副本」的规则那么 0 号副本肯定就是Leader了 我们都知道分区中的只有Leader副本才会提供读写副本其他副本作为备份 假如在某些情况下,「0」 号副本性能资源不够,或者网络不太好,或者IO压力比较大那么肯定对Topic的整体读写性能有很大影响, 这个时候切换一台压力较小副本作为Leader就显得很重要;优先副本: 分区中的AR(所有副本)信息, 优先选择排在第一位的副本作为Leader Leader机制: 分区中只有一个Leader来承担读写,其他副本只是作为备份

那么如何实现这样一个需求呢?

解决方案

知道了原理之后,我们就能想到对应的解决方案了 只要将 分区的 AR 中的第一个位置,替换成你指定副本就行了;AR = { 0,1,2 } ==> AR = {2,1,0}

一般能够达到这个目的有两种方案,下面我们来分析一下

方案一: 分区副本重分配 (低成本方案)

一般分区副本重分配主要有三个流程

  1. 生成推荐的迁移Json文件
  2. 执行迁移Json文件
  3. 验证迁移流程是否完成

这里我们主要看第2步骤, 来看看迁移文件一般是什么样子的

{
"version": 1,
"partitions": [{
"topic": "topic1",
"partition": 0,
"replicas": [0,1,2]
}]
}

这个迁移Json意思是, 把topic1的「0」号分区的副本分配成[0,1,2] ,也就是说 topic1-0号分区最终有3个副本分别在 {brokerId-0,brokerId-1,brokerId-2} ;

又根据Leader的选举策略得知,不管是什么策略的选择,都是按照AR的顺序来选的

修改AR顺序

AR: 副本的分配顺序

那么我们想要实现我们的需求
是不是把这个Json文件 中的 “replicas”: [0,1,2] 改一下就行了
比如改成 “replicas”: [2,1,0] ,
改完Json后执行,执行execute, 正式开始重分配流程!
迁移完成之后, 就会发现,Leader已经变成上面的第一个位置的副本「2」 了

执行Leader选举

修改完AR顺序就结束了吗?

可以说是结束了,也可以说没有结束。

上面只是修改了AR的顺序, 但是没有执行Leader选举呀,这个时候Leader还是原来的,所以我们需要主动触发一下Leader选举

## 石臻臻的杂货铺
## 微信: szzdzhp001 sh bin/kafka-leader-election.sh --bootstrap-server xxxx:9090 --topic Topic1 --election-type PREFERRED --partition 0

这样就会立马切换成我们想要的Leader了。

也可以不主动触发,等Controller自动均衡。

如果你觉得主动触发这个很麻烦,那么没有关系,那就不执行,如果你开启了自动均衡策略的话,默认是开启的。

延伸: 自动均机制

当一个broker停止或崩溃时,这个broker中所有分区的leader将转移给其他副本。这意味着在默认情况下,当这个broker重新启动之后,它的所有分区都将仅作为follower,不再用于客户端的读写操作。

为了避免这种不平衡,Kafka有一个优先副本的概念。如果一个分区的副本列表是1,5,9,节点1将优先作为其他两个副本5和9的leader。

Controller会有一个定时任务,定期执行优先副本选举,这样就不会导致负载不均衡和资源浪费,这就是leader的自动均衡机制

优缺点

优点: 实现了需求, 不需要改源码,也没有额外的开发工作。

缺点: 操作比较复杂容易出错,需要先获取原先的分区分配数据,然后手动修改Json文件,这里比较容易出错,影响会比较大,当然这些都可以通过校验接口来做好限制, 最重要的一点是 副本重分配当前只能有一个任务 !
假如你当前有一个「副本重分配」的任务在,那么这里就不能够执行了。

方案二: 手动修改AR顺序(高成本方案)

  1. 从zk中获取/brokers/topics/{topic名称}节点数据。
  2. 手动调整一下里面的顺序
  3. 将调整后的数据,重新覆盖掉之前的节点。
  4. 删除zk中的/Controller节点,让它触发重新加载,并且同时触发Leader选举。

例如:

修改的时候请先用get获取数据,在那个基础上改,因为不同版本,里面的数据结构是不一样的,我们只需要改分区AR顺序就行了 “partitions”:{“0”:[0,1,2]}

## get zk 节点数据。

get /szz1/brokers/topics/Topic2

## zk中的修改命令
set /szz1/brokers/topics/Topic2 {"version":2,"partitions":{"0":[0,1,2]},"adding_replicas":{},"removing_replicas":{}}

为什么要删除Controller的zk节点?

之所以删除Controller节点,是因为我们手动修改了zk节点数据之后,因为没有副本的新增,是不会触发Controller去更新AR内存的,就算你主动触发Leader选举,AR还是以前的,并不会达到想要的效果。

删除zk中的/Controller节点,会触发Controller重新选举,重新选举会重新加载所有元数据,所以我们刚刚加载的数据就会生效, 同时Controller重新加载也会触发Leader选举。

简单代码

当然上面功能,手动改起来麻烦,那么饿肯定是要集成到LogiKM 3.0中的咯;

优缺点

优点: 实现了目标需求, 简单, 操作方便

缺点: 频繁的Controller重选举对生产环境来说会有一些影响;

方案三:修改源码(高级方案推荐)

我们方案二中的问题就是需要删除/Controller节点发送重新选举,我们能不能不重新选举Controller也能生效呢?

如何让修改后的AR立即生效 ?

Controller会监听每一个topic的节点/brokers/topics/{topic名称}

KafkaController#processPartitionModifications

/**
* 石臻臻的杂货铺
* 微信:szzdzhp001
* 省略部分代码
**/
private def processPartitionModifications(topic: String): Unit = {
def restorePartitionReplicaAssignment(
topic: String,
newPartitionReplicaAssignment: Map[TopicPartition, ReplicaAssignment]
): Unit = { val partitionReplicaAssignment = zkClient.getFullReplicaAssignmentForTopics(immutable.Set(topic))
val partitionsToBeAdded = partitionReplicaAssignment.filter { case (topicPartition, _) =>
controllerContext.partitionReplicaAssignment(topicPartition).isEmpty
} if (topicDeletionManager.isTopicQueuedUpForDeletion(topic)) { } else if (partitionsToBeAdded.nonEmpty) {
info(s"New partitions to be added $partitionsToBeAdded")
partitionsToBeAdded.foreach { case (topicPartition, assignedReplicas) =>
controllerContext.updatePartitionFullReplicaAssignment(topicPartition, assignedReplicas)
}
onNewPartitionCreation(partitionsToBeAdded.keySet)
}
}
}

这段代码省略了很多,我想让你看到的是:

只有新增了副本,才会执行更新Controller的内存操作。

那么我们在这里面新增一段逻辑

新增逻辑:如果只是变更了AR的顺序,那么我们也更新一下内存。

来我们改一下源码

   // 1. 找到 AR 顺序有变更的 所有TopicPartition
val partitionsOrderChange = partitionReplicaAssignment.filter { case (topicPartition, _) =>
//这里自己写下过滤逻辑 把只是顺序变更的分区找出
true
} if (topicDeletionManager.isTopicQueuedUpForDeletion(topic)) {
if (partitionsToBeAdded.nonEmpty) { } else { }
} else if (partitionsToBeAdded.nonEmpty) {
info(s"New partitions to be added $partitionsToBeAdded")
partitionsToBeAdded.foreach { case (topicPartition, assignedReplicas) =>
controllerContext.updatePartitionFullReplicaAssignment(topicPartition, assignedReplicas)
}
onNewPartitionCreation(partitionsToBeAdded.keySet)
}else if (partitionsOrderChange.nonEmpty) {
// ② .在这里加个逻辑
info(s"OrderChange partitions to be updatecache $partitionsToBeAdded")
partitionsOrderChange.foreach { case (topicPartition, assignedReplicas) =>
controllerContext.updatePartitionFullReplicaAssignment(topicPartition, assignedReplicas)
}
}

改成这样之后,上面的流程就变成了

  1. 从zk中获取/brokers/topics/{topic名称}节点数据。
  2. 手动调整一下里面的顺序
  3. 将调整后的数据,重新覆盖掉之前的节点。
  4. 手动执行一次,优先副本选举。

思考

方案三改了之后会对其他的流程有影响吗?

上面更改的方法,一般是在分区副本重分配或者新增分区的时候会触发。

上面新增的逻辑并不会对现有流程有影响,因为假设都是上面的场景的情况下,他们都是会主动更新内存的。

在我看来,这里的改动,完全可以向kafka社区提一个Pr. 来“修复”这个问题。

因为提了这个PR,对我们有收益,没有额外的开销!

点击关注,第一时间了解华为云新鲜技术~

教你3种Kafka的指定副本作为Leader的实现方式的更多相关文章

  1. 教你三种jQuery框架实现元素显示及隐藏动画方式

    摘要:在jQuery框架中对元素对象进行显示和隐藏有三种方式,分别是"默认方式显示和隐藏"."滑动方式显示和隐藏"."淡入淡出显示和隐藏". ...

  2. kafka 分区和副本以及kafaka 执行流程,以及消息的高可用

    1.Kafka概览 Apache下的项目Kafka(卡夫卡)是一个分布式流处理平台,它的流行是因为卡夫卡系统的设计和操作简单,能充分利用磁盘的顺序读写特性.kafka每秒钟能有百万条消息的吞吐量,因此 ...

  3. 详细解析kafka之kafka分区和副本

    本篇主要介绍kafka的分区和副本,因为这两者是有些关联的,所以就放在一起来讲了,后面顺便会给出一些对应的配置以及具体的实现代码,以供参考~ 1.kafka分区机制 分区机制是kafka实现高吞吐的秘 ...

  4. kafka分区及副本在broker的分配

    kafka分区及副本在broker的分配 部分内容參考自:http://blog.csdn.net/lizhitao/article/details/41778193 以下以一个Kafka集群中4个B ...

  5. Kafka 0.8 副本同步机制理解

    Kafka的普及在很大程度上归功于它的设计和操作简单,如何自动调优Kafka副本的工作,挑战之一:如何避免follower进入和退出同步副本列表(即ISR).如果某些topic的部分partition ...

  6. 4种Kafka网络中断和网络分区场景分析

    摘要:本文主要带来4种Kafka网络中断和网络分区场景分析. 本文分享自华为云社区<Kafka网络中断和网络分区场景分析>,作者: 中间件小哥. 以Kafka 2.7.1版本为例,依赖zk ...

  7. 5种kafka消费端性能优化方法

    摘要:带你了解基于FusionInsight HD&MRS的5种kafka消费端性能优化方法. 本文分享自华为云社区<FusionInsight HD&MRSkafka消费端性能 ...

  8. CAD转DXF怎么转换?教你三种转换方法

    CAD图纸在我们日常生活中都是可见到的,因为CAD图纸文件的格式是多样的,在工作中就需要经常将CAD的格式进行转换.那CAD转DXF怎么转换呢?这个问题很多的小伙伴们都遇到过,下面小编就来教大家三种转 ...

  9. Kafka水位(high watermark)与leader epoch的讨论

    ~~~这是一篇有点长的文章,希望不会令你昏昏欲睡~~~ 本文主要讨论0.11版本之前Kafka的副本备份机制的设计问题以及0.11是如何解决的.简单来说,0.11之前副本备份机制主要依赖水位(或水印) ...

  10. Kafka设计解析(二十一)Kafka水位(high watermark)与leader epoch的讨论

    转载自 huxihx,原文链接 Kafka水位(high watermark)与leader epoch的讨论 本文主要讨论0.11版本之前Kafka的副本备份机制的设计问题以及0.11是如何解决的. ...

随机推荐

  1. Kubernetes---修改证书可用年限

    kubeadm---修改apiserver证书有效期 源码编译自签证书: 需要有go环境,从github源码仓库拉取k8s对应版本的源码进行修改/编译.覆盖原来的kubeadm即可. 1.查询证书可用 ...

  2. 2023江苏省领航杯(部分CRYPTO题目复现)

    决赛 回文 1.题目信息 =QfzEDO4YDNlBzN4gzN0YGM1QzYyUGZ3QDZzgDM7V2Sn52bI52Q= 2.解题方法 base64解码,两种思路: 要么是去掉前面=号解码 ...

  3. FreeSWITCH添加自定义endpoint之api及app开发

    操作系统 :CentOS 7.6_x64 FreeSWITCH版本 :1.10.9 之前写过FreeSWITCH添加自定义endpoint的文章,今天整理下api及app开发的笔记.历史文章可参考如下 ...

  4. P1144 最短路计数 题解

    Problem 考察算法:拓扑排序 + \(DP\) + \(Dijkstra\). 题目简述 给出一个无向无权图,问从顶点 \(1\) 开始,到其他每个点的最短路有几条. 思路 先求出 \(1\) ...

  5. 如何通过Python代码旋转PDF页面

    前言 日常处理 PDF 文档时,我们时常会遇到页面颠倒.很难正常阅读或打印的情况. 在这种情况下,我们可以通过旋转页面来调整文档的方向.旋转时,也可以根据具体情况,选择顺时针或逆时针旋转特定的角度,以 ...

  6. 记录一下我的ctf比赛的web题目

    Web之getshell: 具体代码如下 <?php highlight_file(__FILE__); error_reporting(0); echo "<h1>WEL ...

  7. Java 基础学习第二弹

    1. HashMap和HashT able的区别 HashMap和Hashtable是两种常见的哈希表数据结构,它们在实现上有一些区别. 线程安全性:Hashtable是线程安全的,而HashMap不 ...

  8. 文心一言 VS 讯飞星火 VS chatgpt (146)-- 算法导论12.2 1题

    一.用go语言,假设一棵二叉搜索树中的结点在1到 1000 之间,现在想要查找数值为 363 的结点.下面序列中哪个不是查找过的序列? a.2,252,401,398,330,344,397,363. ...

  9. 构建满足流批数据质量监控用火山引擎DataLeap

    更多技术交流.求职机会,欢迎关注字节跳动数据平台微信公众号,回复[1]进入官方交流群 面对今日头条.抖音等不同产品线的复杂数据质量场景,火山引擎 DataLeap 数据质量平台如何满足多样的需求?本文 ...

  10. 使用 PyTorch 完全分片数据并行技术加速大模型训练

    本文,我们将了解如何基于 PyTorch 最新的 完全分片数据并行 (Fully Sharded Data Parallel,FSDP) 功能用 Accelerate 库来训练大模型. 动机 随着机器 ...