kafka服务端之控制器

文章目录

  • 概述
  • 控制器的选举与故障恢复
    • 控制器的选举
    • 故障恢复
  • 优雅关闭
  • 分区leader的选举

概述

在Kafka集群中会有一个或多个broker,其中有一个broker会被选举为控制器(Kafka Controler),它负责管理整个集群中所有分区和副本的状态。当某个分区的leader副本出现故障时,由控制器负责为该分区选举新的leader副本。当检测到某个分区的ISR集合发生变化时,由控制器负责通知所有broker更新其元数据信息。当使用kafka-topics.sh脚本为某个topic增加分区数量时,同样还是由控制器负责分区的重新分配

这里主要讲控制器的功能与实现,优雅关闭部分会简单概括。

控制器的选举与故障恢复

控制器的选举

Kafka中的控制器选举工作依赖于ZooKeeper,成功竞选为控制器的broker会在ZooKeeper中创建/controller这个临时(EPHEMERAL)节点,此临时节点的内容参考如下:
(version":1,brokerid":0,“timestamp":”1529210278988”)
其中version在目前版本中固定为1,brokeria表示成为控制器的broker的ia编号,timestamp 表示竞选成为控制器时的时间戳。

在任意时刻,集群中有且仅有一个控制器。每个broker启动的时候会去尝试读取/controller节点的brokeria的值,如果读取到brokerid的值不为-1,则表示已经有其他broker节点成功竞选为控制器,所以当前broker就会放弃竞选:如果ZooKeeper中不存在/controller,或者这个节点中的数据异常,那么就会尝试去创建/controller节点。当前broker去创建节点的时候,也有可能其他broker同时去尝试创建这个节点,只有创建成功的那个broker才会成为控制器,而创建失败的broker竞选失败。每个broker都会在内存中保存当前控制器的brokerid值,这个值可以标识为activeControllerid。

ZooKeeper中还有一个与控制器有关的/controller_epoch节点,这个节点是持久(PERSISTENT)节点,节点中存放的是一个整型的controller_epoch值。controller_epoch用于记录控制器发生变更的次数,即记录当前的控制器是第几代控制器,我们也可以称之为“控制器的纪元”

controller_epch的初始值为1,即集群中第一个控制器的纪元为1,当控制器发生变更时,每选出一个新的控制器就将该字段值加1。每个和控制器交互的请求都会携带controller_epoch这个字段,如果请求的controller_epoch值小于内存中的controller_epoch值,则认为这个请求是向已经过期的控制器所发送的请求,那么这个请求会被认定为无效的请求。如果请求的controller_epoch值大于内存中的controller_epoch值,那么说明已经有新的控制器当选了。由此可见,Kafka通过controller_epoch来保证控制器的唯性,进而保证相关操作的一致性。

具备控制器身份的broker需要比其他普通的broker多一份职责,具体细节如下:

  • 监听分区相关的变化。为ZooKeeper中的/admin/reassign partitions节点注 册
    PartitionReassignmentHandler,用来处理分区重分配的动作。为ZooKeeper中的/isr change notification节点注册IsrChangeNotificetionHandler,用来处理ISR集合变更的动作。为ZooKeeper中中的/admin/preferred-replica-election节点添加
    PreferredReplicaElectionHandler,用来处理优先副本的选举动作

  • 监听主题相关的变化。为ZooKeeper中的/brokers/topics节点添加
    TopicChangeHandler,用来处理主题增减的变化;为ZooKeeper中的/admin/ delete
    topics节点添加TopicDeletionHandler,月用来处理删除主题的动作。

  • 监听broker相关的变化。为ZooKeeper中的/brokers/ids节点添加BrokerChangeHandler,用来处理broker增减的变化。

  • 从ZooKeeper中读取获取当前所有与主题、分区及broker有关的信息并进行相应的管理。对所有主题对应的ZooKeeper中的/brokers/topics/节点添加PartitionModificationsHandler,用来监听主题中的分区分配变化

  • 启动并管理分区状态机和副本状态机

  • 更新集群的元数据信息

  • 如果参数auto.leader.rebalance.enable设置为true,贝则还会开启一个名为
    “auto-leader-rebalance-task”的定时任务来负责维护分区的优先副本的均衡

控制器在选举成功之后会读取ZooKeeper中各个节点的数据来初始化上下文信息(ControllerContext),并且需要管理这些上下文信息。比如为某个主题增加了若干分区,控制器在负责创建这些分区的同时要更新上下文信息,并且需要将这些变更信息同步到其他普通的broker节点中。不管是监听器触发的事件,还是定时任务触发的事件,或者是其他事件都会读取或更新控制器中的上下文信息,那么这样就会涉及多线程间的同步。如果单纯使用锁机制来实现,那么整体的性能会大打折扣。针对这一现象,Kafka的控制器使用单线程基于事件队列的模型,将每个事件都做一层封装,然后按照事件发生的先后顺序暂存到LinkedBlockingQueue中,最后使用一个专用的线程(ControllerEventThread)按照FIFO(FirstInputFirstOutput,先入先出)的原则顺序处理各个事件,这样不需要锁机制就可以在多线程间维护线程安全,具体可以参考下图。
在这里插入图片描述

在Kafka的早期版本中,并没有采用KafkaController这样一个概念来对分区和副本的状态进行管理,而是依赖于ZooKeeper,每个broker都会在ZooKeeper上为分区和副本注册大量的监听器(Watcher)。当分区或副本状态变化时,会唤醒很多不必要的监听器,这种严重依赖

ZooKeeper的设计会有脑裂羊群效应,以及造成ZooKeeper过载的隐患(旧版的消费者客户端存在同样的问题)。在目前的新版本的设计中,只有KafkaController在ZooKeeper上注册相应的监听器,其他的broker极少需要再监听ZooKeeper中的数据变化,这样省去了很多不必要的麻烦。不过每个broker还是会对/controller节点添加监听器,以此来监听此节点的数据变化(ControllerChangeHandler)

故障恢复

当/controller节点的数据发生变化时,每个broker都会更新自身内存中保存的activeControllerlds如果broker在数据变更前是控制器,在数据变更后自身的brokerid值与新的 activeControllerId值不一致,那么就需要“退位”,关闭相应的资源,比如关闭状态机、注销相应的监听器等。有可能控制器由于异常而下线,造成/controller这个临时节点被自动删除;也有可能是其他原因将此节点删除了。

当/controller节点被删除时,每个broker都会进行选举,如果broker在节点被删除前是控制器,那么在选举前还需要有一个“退位”的动作。如果有特殊需要,则可以手动删除/controller节点来触发新一轮的选举。当然关闭控制器所对应的broker,以及手动向/controller节点写入新的brokerid的所对应的数据,同样可以触发新一轮的选举。

优雅关闭

Kafka自身提供了一个脚本工具,就是存放在其bin目录下的kafka-server-stop.sh,这个脚本的内容非常简单,具体内容如下:

PIDS=S (ps ax I grep -i kafkal.Kafka’ Igrep java l grep -v grep 1 awk print S1)') if[-Z”SPIDS”】;then echo rNokafkaserver to stop' exit 1 else kill -S TERM SPIDS fi

以上脚本直接执行会存在执行不成功,这是因为与Kafka进程有关的输出信息太长,所以kafka-server-stop.sh脚本在很多情况下并不会奏效。

可以通过修改计算机PAGE_SIZE的大小或者修改脚本内容,这里我们可以直接修改kafka-server-storsh脚本的内容,将其中的第一行命令修改如下:
PIDS=S(ps axIgrep -i 'kafka’i grep javalgrep-v greplawkitprint Si}'
即把“.Kafka”去掉,这样在绝大多数情况下是可以奏效的。如果有极端情况,即使这样也不能关闭,那么只需要按照以下两个步骤就可以优雅地关闭Kafka的服务进程:
(1)获取Kafka的服务进程号PIDS。可以使用Java中的jps命令或使用Linux系统中的ps命令来查看。
(2)使用kill-STERMSPIDS或kill-15 $PIDS的方式来关闭进程,注意千万不要使用kill-9的方式。

为什么这样关闭的方式会是优雅的?Kafka服务入口程序中有一个名为“kafka-shutdown-hock”的关闭钩子,待Kafka进程捕获终止信号的时候会执行这个关闭钩子中的内容,其中除了正常关闭一些必要的资源,还会执行一个控制关闭C ControlledShutdown )的动作。使用ControlledShutdown的方式关闭Kafka有两个优点:一是可以让消息完全同步到磁盘上,在服务下次重新上线时不需要进行日志的恢复操作;二是ControllerShutdown在关闭服务之前,会对其上的leader副本进行证移,这样就可以减少分区的不可用时间。这里更加详细的分析可以查下其他人的博客。

当然这里是通过脚本进行优雅关闭,你也可以自己通过KafkaAdminClient自己写一个优雅关闭的接口去执行。这里详细的设计与实现可以查下其他博客。

分区leader的选举

分区leader副本的选举由控制器负责具体实施。当创建分区(创建主题或增加分区都有创建分区的动作)或分区上线(比如分区中原先的leader副本下线,此时分区需要选举一个新的leader上线来对外提供服务)的时候都需要执行leader的选举动作,对应的选举策略为OfflinePartitionLeaderElectionStrategy。这种策略的基本思路是按照AR集合中副本的顺序查找第一个存活的副本,并且这个副本在ISR集合中。一个分区的AR集合在分配的时候就被指定并且只要不发生重分配的情况,集合内部副本的顺序是保持不变的,而分区的ISR集合中副本的顺序可能会改变。注意这里是根据AR的顺序而不是ISR的顺序进行选举的

如果ISR集合中没有可用的副本,那么此时还要再检查一下所配置的unclean.leader.election.enable参数(默认值为false)。如果这个参数配置为true那么表示允许从非ISR列表中的选举leader,从AR列表中找到第一个存活的副本即为leader。

那么哪些情况下会出现leader选举呢?

  • 当分区进行重分配的时候也需要执行leader的选举动作,对应的选举策略为ReassignPartitionLeaderElectionStrategy。这个选举策略的思路比较简单:从重分配的AR列表中找到第一个存活的副本,且这个副本在日前的ISR列表中。

  • 当发生优先副本的选举时,直接将优先副本设置为leader即可,AR集合中的第一个副本即为优先副本(PreferredReplicaPartitionLeaderElectionStrategy)

  • 还有一种情况会发生leader的选举,当某节点被优雅地关闭(也就是执行 ControlledShutdown)时,位于这个节点上的leader副本都会下线,所以与此对应的分区需要执行leader的选举。与此对应的选举策略(ControlledShutdownPartitionLeaderElectionStrategy)为:从AR列表中找到第一个存活的副本,且这个副本在日前的ISR列表中,与此同时还要确保这个副本不处于正在被关闭的节点上。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/966041.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

03/29 使用 海康SDK 对接时使用的 MysqlUtils

前言 最近朋友的需求, 是需要使用 海康sdk 连接海康设备, 进行数据的获取, 比如 进出车辆, 进出人员 这一部分是 资源比较贫瘠时的一个 Mysql 工具类 测试用例 public class MysqlUtils {public static String MYSQL_HOST "192.168.31.9";public static int MY…

【蓝桥杯—单片机】第十一届省赛真题代码题解题笔记 | 省赛 | 真题 | 代码题 | 刷题 | 笔记

第十一届省赛真题代码部分 前言赛题代码思路笔记竞赛板配置内部振荡器频率设定键盘工作模式跳线扩展方式跳线 建立模板明确设计要求和初始状态显示功能部分数据界面第一部分第二部分第三部分调试时发现的问题 参数设置界面第一部分第二部分和第四部分第三部分和第五部分 按键功…

【C语言】数 组与指针:深度剖析与等价表达

博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C语言 文章目录 💯前言💯数组与指针的基本关系💯数组与指针的互换使用数组下标与指针的等价性 💯六个表达式的等价性💯指针运算的注意事项💯数组…

Explain 是 SQL 查询优化中非常重要的工具,它用于分析 SQL 查询的执行计划

Explain 是 SQL 查询优化中非常重要的工具,它用于分析 SQL 查询的执行计划https://mp.weixin.qq.com/s/QKra-Sp5JoaEPSCqfffOtA

Leetcode—487. 最大连续1的个数 II【中等】Plus

2025每日刷题&#xff08;210&#xff09; Leetcode—487. 最大连续1的个数 II 实现代码 class Solution { public:int findMaxConsecutiveOnes(vector<int>& nums) {int zeros 0;int ans 0;for(int l 0, r 0; r < nums.size(); r) {if(nums[r] 0) {zeros;…

C32.【C++ Cont】静态实现双向链表及STL库的list

目录 1.知识回顾 2.静态实现演示图 3.静态实现代码 1.初始双向链表 2.头插 3.遍历链表 4.查找某个值 4.任意位置之后插入元素 5.任意位置之前插入元素 6.删除任意位置的元素 4.STL库的list 1.知识回顾 96.【C语言】数据结构之双向链表的初始化,尾插,打印和尾删 97.【C…

Docker的镜像

Docker的镜像 一&#xff0e;Docker镜像的概念 镜像是Docker&#xff08;镜像&#xff0c;容器&#xff0c;仓库&#xff09;三大核心概念之一。镜像本质上是一个只读文件&#xff0c;它包含了文件系统、源码、库文件、依赖、工具等运行应用程序所必须的文件。 镜像是由文件…

如何在Windows上使用Docker

引言 WSL2&#xff08;Windows Subsystem for Linux2&#xff09;是微软开发的一种技术&#xff0c;允许在 Windows 操作系统上运行 Linux 环境。它提供了一个兼容层&#xff0c;使得用户可以在 Windows 系统中直接运行 Linux 命令行工具、应用程序和开发工具&#xff0c;而无需…

赛博算命之 ”梅花易数“ 的 “JAVA“ 实现 ——从玄学到科学的探索

hello~朋友们&#xff01;好久不见&#xff01; 今天给大家带来赛博算命第三期——梅花易数的java实现 赛博算命系列文章&#xff1a; 周易六十四卦 掐指一算——小六壬 更多优质文章&#xff1a;个人主页 JAVA系列&#xff1a;JAVA 大佬们互三哦~互三必回&#xff01;&#xf…

Spring Web MVC项目的创建及使用

一、什么是Spring Web MVC&#xff1f; Spring Web MVC 是基于 Servlet API 构建的原始 Web 框架&#xff0c;从⼀开始就包含在 Spring 框架中&#xff0c;通常被称为Spring MVC。 1.1 MVC的定义 MVC 是 Model View Controller 的缩写&#xff0c;它是软件工程中的一种软件架构…

Websocket从原理到实战

引言 WebSocket 是一种在单个 TCP 连接上进行全双工通信的网络协议&#xff0c;它使得客户端和服务器之间能够进行实时、双向的通信&#xff0c;既然是通信协议一定要从发展历史到协议内容到应用场景最后到实战全方位了解 发展历史 WebSocket 最初是为了解决 HTTP 协议在实时…

IDEA+DeepSeek让Java开发起飞

1.获取DeepSeek秘钥 登录DeepSeek官网 : https://www.deepseek.com/ 进入API开放平台&#xff0c;第一次需要注册一个账号 进去之后需要创建一个API KEY&#xff0c;然后把APIkey记录保存下来 接着我们获取DeepSeek的API对话接口地址&#xff0c;点击左边的&#xff1a;接口…

深度解读 Docker Swarm

一、引言 随着业务规模的不断扩大和应用复杂度的增加,容器集群管理的需求应运而生。如何有效地管理和调度大量的容器,确保应用的高可用性、弹性伸缩和资源的合理分配,成为了亟待解决的问题。Docker Swarm 作为 Docker 官方推出的容器集群管理工具,正是在这样的背景下崭露头…

嵌入式面试题 C/C++常见面试题整理_7

一.什么函数不能声明为虚函数? 常见的不能声明为虚函数的有:普通函数(非成员函数):静态成员函数;内联成员函数;构造函数;友元函数。 1.为什么C不支持普通函数为虚函数?普通函数(非成员函数)只能被overload&#xff0c;不能被override&#xff0c;声明为虚函数也没有什么意思…

Ubuntu MKL(Intel Math Kernel Library)

Get Intel oneAPI Math Kernel Library wget https://registrationcenter-download.intel.com/akdlm/IRC_NAS/79153e0f-74d7-45af-b8c2-258941adf58a/intel-onemkl-2025.0.0.940_offline.sh sudo sh ./intel-onemkl-2025.0.0.940_offline.sh MKL库的配置和使用-CSDN博客 CMak…

如何在Vscode中接入Deepseek

一、获取Deepseek APIKEY 首先&#xff0c;登录Deepseek官网的开放平台&#xff1a;DeepSeek 选择API开放平台&#xff0c;然后登录Deepseek后台。 点击左侧菜单栏“API keys”&#xff0c;并创建API key。 需要注意的是&#xff0c;生成API key复制保存到本地&#xff0c;丢失…

go-zero学习笔记(三)

利用goctl生成rpc服务 编写proto文件 // 声明 proto 使用的语法版本 syntax "proto3";// proto 包名 package demoRpc;// golang 包名(可选) option go_package "./demo";// 如需为 .proto 文件添加注释&#xff0c;请使用 C/C 样式的 // 和 /* ... */…

将Deepseek接入pycharm 进行AI编程

目录 专栏导读1、进入Deepseek开放平台创建 API key 2、调用 API代码 3、成功4、补充说明多轮对话 总结 专栏导读 &#x1f338; 欢迎来到Python办公自动化专栏—Python处理办公问题&#xff0c;解放您的双手 &#x1f3f3;️‍&#x1f308; 博客主页&#xff1a;请点击——…

yolov8 opencv模型部署(C++版)

TensorRT系列之 Windows10下yolov8 tensorrt模型加速部署 TensorRT系列之 Linux下 yolov8 tensorrt模型加速部署 TensorRT系列之 Linux下 yolov7 tensorrt模型加速部署 TensorRT系列之 Linux下 yolov6 tensorrt模型加速部署 TensorRT系列之 Linux下 yolov5 tensorrt模型加速…

Android 常用命令和工具解析之Battery Historian

Batterystats是包含在 Android 框架中的一种工具&#xff0c;用于收集设备上的电池数据。您可以使用adb bugreport命令抓取日志&#xff0c;将收集的电池数据转储到开发机器&#xff0c;并生成可使用 Battery Historian 分析的报告。Battery Historian 会将报告从 Batterystats…