You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
k8s 简化了我们在集群上部署、运维应用的流程。在 k8s 上,我们可以很方便地部署一个分布式应用。以 Deployment 为例,应用就由多个 Pod 组成,基于 Pod 的伸缩能力,应用天然就具备应用的高可用性和可扩展性。但在分布式系统中,通常我们需要指定其中一个 Pod 为 leader,负责协调所有 Pod 或执行特定任务。
一般提到 Leader 选举,我们都会想到利用 ZooKeeper 或 Redis 等软件的分布式锁来实现,所有 Pod 不断争抢锁,抢到锁的 Pod 就成为 Leader,并且 Leader 不断进行 “心跳” 对锁进行续期。其他 Pod 依旧不断强锁,保证 之前 Leader 出现异常后能快速选举出新的 Leader。
然后就根据 LeaderElectionConfig 创建一个 LeaderElector 实例,并调用其 run 方法进行抢锁。调用 run 方法后,Pod 会尝试更新锁资源。示例代码中是 ConfigMapLock,所以 Pod 会尝试创建或更新 ConfigMap,一旦更新成功,就会将当前 Pod 的 IP 写入到 ConfigMap 的 metadata.annotations,写入成功后该 Pod 就成为了 Leader。
概述
k8s 简化了我们在集群上部署、运维应用的流程。在 k8s 上,我们可以很方便地部署一个分布式应用。以 Deployment 为例,应用就由多个 Pod 组成,基于 Pod 的伸缩能力,应用天然就具备应用的高可用性和可扩展性。但在分布式系统中,通常我们需要指定其中一个 Pod 为 leader,负责协调所有 Pod 或执行特定任务。
一般提到 Leader 选举,我们都会想到利用 ZooKeeper 或 Redis 等软件的分布式锁来实现,所有 Pod 不断争抢锁,抢到锁的 Pod 就成为 Leader,并且 Leader 不断进行 “心跳” 对锁进行续期。其他 Pod 依旧不断强锁,保证 之前 Leader 出现异常后能快速选举出新的 Leader。
但使用 ZooKeeper 或 Redis 等,需要我们额外部署一个软件。那在 k8s 中能不能不使用外部软件,实现 Leader 选举呢?
k8s 本身为了保证资源(如 Endpoint、ConfigMap 等)的一致性,在资源的 metadata 中定义了资源版本,并版本信息维护在了分布式存储 etcd 中,通过乐观锁的方式更新资源,保证并发更新资源时,资源只能被更新一次。因此我们也可以利用这个特点,通过在 Pod 内争抢更新某个资源来实现 Leader 选举。
更方便的是,k8s 的 Client 已经封装了 Leader 选举的逻辑,我们直接使用即可。接下来就以 k8s 的 Java Client ( kubernetes-client/java ) 为例,介绍如何实现 Leader 选举。
代码实现
首先需要引入 Java Client ,以 maven 为例,在
pom.xml
中添加相关依赖:
client-java
封装了 k8s 的基础 API,要使用 Leader 选举类,还需要引入client-java-extended
。下面是一段 Leader 选举的代码示例:
首先初始化了 ApiClient。如果是本地开发,则默认会使用本地
${HOME}/.kube/config
中的 kubeconfig 配置来访问集群。
然后创建了一个 ConfigMapLock,该锁就是 Leader 选举时争抢的资源锁,本质上是一个 ConfigMap。在上面代码中,锁的 Identity 是 Pod 的 IP,这样我们就可以根据锁内容判断当前哪个 Pod 是 Leader。除了 ConfigMap,还可以使用 Endpoints 和 Lease 等资源,在 Java Client 中也分别实现了对应的 EndpointsLock 和 LeaseLock。
接下来就是创建一个 LeaderElectionConfig ,该配置主要包含以下属性:
然后就根据 LeaderElectionConfig 创建一个 LeaderElector 实例,并调用其
run
方法进行抢锁。调用run
方法后,Pod 会尝试更新锁资源。示例代码中是 ConfigMapLock,所以 Pod 会尝试创建或更新 ConfigMap,一旦更新成功,就会将当前 Pod 的 IP 写入到 ConfigMap 的metadata.annotations
,写入成功后该 Pod 就成为了 Leader。
下面就是 Leader 选举后的 ConfigMap 示例:
LeaderElector 的
run
方法提供了几个抢锁相关的 hook:在分布式系统中,我们可能只需要 Leader 处理特定任务,这时也可以很方便地判断某个 Pod 是否是 Leader:
整体来看,由于 k8s Client 封装了 Leader 选举的相关逻辑,所以我们使用起来非常简单。关于 LeaderElection 的具体实现,其实也比较简单易懂,就是不断抢锁、续约,感兴趣的可以直接阅读 kubernetes-client/java 的相关源码。
总结
由此可见,基于 k8s 的 Leader 选举是非常简单方便的,并且运用也非常广泛。比如将 Flink 部署到 k8s 上时,Flink 为了实现高可用就使用了基于 k8s 的 Leader 选举机制,保证同时只有一个 jobmanager 负责任务的调度(即作为 Leader),并且 Leader 出现问题时,其他能候补 Pod 够快速晋升为 Leader。
参考
The text was updated successfully, but these errors were encountered: