选举源码
Ⅰ zookeeper另类
zookeeper是动物管理员的意思。
ZooKeeper是一个分布式的,开放源码租前慎的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
ZooKeeper的基本运转流程:1、选举Leader。2、同步数据。3、选举Leader过程中算法有很多,但要达到的选举标准是一致的。4、Leader要具有最高的执行ID,类似root权限。5、集群中大多数的机器得到响应并接受选出的Leader。
Ⅱ zk源码阅读37:ZooKeeperServer源码分析
前面针对server启动到选举leader进行了一个小结,现在进入leader和follower的启动交互过程,需要先讲ZooKeeperServer,
在之前源码阅读的25节里面带过了一部分,这里详细讲解ZooKeeperServer的源码
继承关系如下
本节主要讲解内容如下
在源码阅读第24节讲解了,这里不赘述
是SessionTracker的内部接口
如下图
除去log,jmx相关部分,源码如下
ChangeRecord是ZooKeeperServer的内部类,衫亩下面会介绍
ServerStats,ZooKeeperServerListener都在25节的源码介绍过
这个类或升森并没有调用,不用管
定义异常
这个数据结构为了促进PrepRequestProcessor以及FinalRequestProcessor的信息共享,讲到调用链的时候再讲。
其中,StatPersisted在源码阅读7中讲DataNode的时候讲过了
描述当前server所处的状态
这里列举处两个底层调用的构造函数
启动涉及到db的数据加载,这里也有集群和单机两种,调用顺序为
主要是集群的时候,server选完了leader,由leader才能调用数据加载loadData
下面按照单机版startdata函数展开
初始化zkDb完成数据加载
恢复session和数据,单机版启动或者集群版leader选举之后调用lead方法时,会调用该方法。
主要完成设置zxid以及把无效的session给kill掉的工作
这里注意,为什么需要干这件事情,在下面思考中会说
里面调用了setZxid(不展开)以及killSession函数
清除db中临时会话记录,会话跟踪器也清除记录
入口是ZooKeeperServer#startup,zkServer都是在上述加载了db的数据之后,调用startup来完成启动
启动的入口函数
调用了createSessionTracker等函数,介绍如下
createSessionTracker 完成会话跟踪器的创建
这里是默认的单机版实现,在集群版不同的角色有不同的实现,主要是参数sid不会传1,而是配置中的sid
startSessionTracker 启动会话跟踪器
设置笑薯服务器运行状态,对于ERROR和SHUTDOWN的state,进行对应的操作
在 源码阅读25:服务器异常报警,关闭机制 讲过,这里不赘述
安装请求处理链路,是PrepRequestProcessor -> SyncRequestProcessor -> FinalRequestProcessor顺序
具体在后面请求处理链路再讲
两个函数getServerId和expire
processConnectRequest用于处理client的连接请求,不展开
值得注意的地方是重连的调用
展开如下
重连的核心函数
验证sessionId和传递来的密码的正确性
根据sessionId生成密码
在会话跟踪器SessionTracker中判断会话是否还有小
完成会话初始化,根据参数valid代表认证通过与否,用来判断server是接收连接请求,还是发出closeConn的请求,不展开,重要部分如下
除去的get,set,jmx,shutdown相关函数,剩下重要函数如下
部分函数列举如下
获取下一个server的zxid,调用方需要确保控制并发顺序
上面ZooKeeperServer#expire调用了close函数,介绍如下
该函数用于提交一个 关闭某个sessionId 的请求
这里有两个函数
之前在源码21节 会话管理中讲解了会话清除,在sessionTracker的记录是马上清除的,而DateTree中临时会话的清除是通过调用链一步步来的,也就是说两个步骤不是同步的,所以如果中间服务器状态改变了,会出现不一致的情况
requestsInProcess代表正在处理的请求个数
就是说发出请求时,requestsInProcess+1,最后完成请求时,requestsInProcess-1.涉及到请求处理链。
ZooKeeperServer#checkPasswd调用
ZooKeeperServer#generatePasswd
就是sessionId要和sessionId^superSecret生成的第一个随机数相匹配即可
密码不是client端设置的,是根据sessionId生成的
ZooKeeperServer#processConnectRequest 里面调用reopenSession中
在上面已经讲了,核心就是
这里还没有深入看,先存疑
比如思考中提到的loadData为什么会出现数据不一致,属于某种异常情况的处理
为什么不放到另外一个类里面去
Ⅲ 教你3种Kafka的指定副本作为Leader的实现方式
在实际的运维过程中,我们有时需要指定某个分区副本为Leader,然而Kafka的Leader选举策略并不支持此功能。本文将介绍三种实现方式,以便满足这一需求。
在生产环境中,常见需求是修改某个Topic中某分区的Leader。例如,对于topic1-0这个分区,有三个副本[0,1,2]。按照优先副本规则,0号副本将是Leader。然而,如果0号副本性能资源不足、网络不佳或IO压力大,我们需要切换到压力较小的副本作为Leader,以提高整体读写性能。这就是优先副本概念,即分区中选择第一位的副本作为Leader,而仅有一个Leader副本提供读写服务,其他副本作为备份。
实现这一需求有以下三种方案:
方案一:分区副本重分配(低成本方案)
通常,分区副本重分配涉及三个步骤,重点在于迁移文件内容。在迁移文件中,可以指定topic1-0号分区的副本分配规则为[0,1,2],最终的副本分布为{brokerId-0,brokerId-1,brokerId-2}。根据Leader选举策略,不论规则如何,都会按照副本分配顺序选择Leader。因此,通过修改副本分配顺序(如将“replicas”:[0,1,2]更改为“replicas”:[2,1,0]),执行重分配流程后,Leader将变为第一个位置的副本(即2号副本)。
方案二:手动修改AR顺序(高成本方案)
此方案涉及直接修改副本分配顺序。在操作前,首先获取分区的原始数据,然后手动修改数据结构(如“partitions”:{“0”:[0,1,2]}),并删除Controller的zk节点以触发重新选举。这将导致Controller重新加载所有元数据,并重新执行Leader选举,以应用修改后的顺序。
方案三:修改源码(高级方案推荐)
此方案通过在源代码中添加逻辑,以在不重新选举Controller的情况下更新副本分配顺序。通常,Controller在新增副本时会更新内存,因此在相关逻辑中添加检测副本顺序变更的代码,使得一旦顺序变更,即可立即更新内存。这样操作不仅实现了目标需求,而且操作简单、方便,不会对现有流程产生负面影响。
这三种方案各有优缺点。方案一操作简便,无需额外开发工作,但需要具备一定技术能力以确保流程正确执行。方案二操作直接,但频繁的Controller重选举可能对生产环境产生一定影响。方案三通过修改源码实现,对系统影响最小,且无额外开销,推荐在具备一定技术基础的场景中使用。