快速实现leader选举之Spring Cloud Kubernetes Leader Election
Posted 水中加点糖
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了快速实现leader选举之Spring Cloud Kubernetes Leader Election相关的知识,希望对你有一定的参考价值。
说起节点选举,一般最先想到的就是使用zookeeper或redis来进行实现。
但有时因为项目的原因,如果不方便引入其它的中间件,又正好使用了spring cloud kubernetes框架,那么就可以直接使用spring cloud kubernetes leader election来实现节点选举了。
The Spring Cloud Kubernetes leader election mechanism implements the leader election API of Spring Integration using a Kubernetes ConfigMap.
接入方法
接入方法可直接看官方描述,其地址为:https://docs.spring.io/spring-cloud-kubernetes/docs/current/reference/html/#leader-election
从官方说明中可以看出,实现节点选举功能只需要引入如下的依赖即可:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-kubernetes-fabric8-leader</artifactId>
</dependency>
但在引入时需要注意,目前只有是采用的fabric8作为服务发现的项目才可以引入它,也就是一般需要这样引入依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-fabric8</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-kubernetes-fabric8-leader</artifactId>
</dependency>
对于服务注册和发现的依赖不能使用spring-cloud-starter-kubernetes-client,也就是不能使用这个依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-client</artifactId>
</dependency>
如果引用错了,项目可能会报错启动失败。
另外从官方的说明文档中我们可以看出,节点选举是使用ConfigMap实现的。
The Spring Cloud Kubernetes leader election mechanism implements the leader election API of Spring Integration using a Kubernetes ConfigMap.
默认用的名为leader的configmap存储的主节点数据,如果想换个configmap的名字,修改如下配置即可:
spring.cloud.kubernetes.leader.config-map-name=leader
当前面依赖引入之后,接下来的就是实现监听的方法就可以了。
通过官方文档可以看出,当某个节点被成功选为主节点时,会收到一个OnGrantedEvent的事件
When granted leadership, a leader application receives an OnGrantedEvent application event with leadership Context
当主节点释放leader权限时,会手收到一个OnRevokedEvent事件
When leadership removal occurs, the previous leader receives OnRevokedEvent application event.
所以代码里添加添加对应事件的代码即可,如测试时这样添加一下监听类:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.integration.leader.event.OnGrantedEvent;
import org.springframework.integration.leader.event.OnRevokedEvent;
import org.springframework.stereotype.Component;
import java.net.InetAddress;
import java.net.UnknownHostException;
@Component
public class LeaderElectionEventListener implements ApplicationListener
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public void onApplicationEvent(ApplicationEvent applicationEvent)
String localIp = getLocalIp();
if (applicationEvent instanceof OnGrantedEvent)
OnGrantedEvent onGrantedEvent = (OnGrantedEvent) applicationEvent;
logger.error("[onApplicationEvent] onGrantedEvent: source: role: ip:", onGrantedEvent.toString(), onGrantedEvent.getSource(), onGrantedEvent.getRole(), localIp);
else if (applicationEvent instanceof OnRevokedEvent)
OnRevokedEvent onRevokedEvent = (OnRevokedEvent) applicationEvent;
logger.error("[onApplicationEvent] onRevokedEvent: source: role: ip:", onRevokedEvent.toString(), onRevokedEvent.getSource(), onRevokedEvent.getRole(), localIp);
else
logger.error("[onApplicationEvent] otherEvent: source: timestamp: ip:", applicationEvent.toString(), applicationEvent.getSource(), applicationEvent.getTimestamp(), localIp);
private String getLocalIp()
try
InetAddress addr = InetAddress.getLocalHost();
return addr.getHostAddress();
catch (UnknownHostException e)
e.printStackTrace();
return "unkown ip";
示例效果
仅一个节点
只有一个活动节点时,会触发一个OnGrantedEvent事件。
再看下configmap中的内容为:
从上面我们可以看出,当k8s集群中leader选举成功后,会创建一个存储leader的configmap。默认用的是leader名称。
多个节点
之后再将节点数设为3个副本数,再观察configmap,
kubectl describe configmap/leader
Name: leader
Namespace: default
Labels: kind=leaders
provider=spring-cloud-kubernetes
Annotations: <none>
Data
====
leader.id.leader:
----
svca-service-8fbb78cb7-gdx2j
Events: <none>
从观察节点可以看出,只要原来的leader是存活的,即便启了新的节点,还会是以原来的节点为准。如上面的,leader仍然为:svca-service-8fbb78cb7-gdx2j
原leader故障转移
再测试一下将原来的leader进行手动删掉,观察下情况。
由前面的configmap数据可知,当前的leader节点为:svca-service-8fbb78cb7-gdx2j
所以直接删除主节点
kubectl delete pod/svca-service-8fbb78cb7-gdx2j
再查看configmap情况
kubectl describe configmap/leader
其值如下:
Name: leader
Namespace: default
Labels: kind=leaders
provider=spring-cloud-kubernetes
Annotations: <none>
Data
====
leader.id.leader:
----
svca-service-8fbb78cb7-m9ncl
Events: <none>
leader变成了节点:svca-service-8fbb78cb7-m9ncl
看下它的日志:
kubectl logs pod/svca-service-8fbb78cb7-m9ncl
其中有如下日志:
2021-10-23 17:20:21.631 ERROR 1 --- [//10.43.0.1/...] c.z.s.event.LeaderElectionEventListener : [onApplicationEvent] onGrantedEvent:OnGrantedEvent [role=leader, context=org.springframework.cloud.kubernetes.commons.leader.LeaderContext@2734b465, source=org.springframework.cloud.kubernetes.fabric8.leader.Fabric8LeadershipController@663d90b7] source:org.springframework.cloud.kubernetes.fabric8.leader.Fabric8LeadershipController@663d90b7 role:leader ip:10.42.1.203
2021-10-23 17:20:21.636 INFO 1 --- [//10.43.0.1/...] o.s.integration.leader.DefaultCandidate : DefaultCandidaterole=leader, id=svca-service-8fbb78cb7-m9ncl has been granted leadership; context: org.springframework.cloud.kubernetes.commons.leader.LeaderContext@2734b465
说明这个节点选举成功后,也触发了OnGrantedEvent事件
以上是关于快速实现leader选举之Spring Cloud Kubernetes Leader Election的主要内容,如果未能解决你的问题,请参考以下文章
快速实现leader选举之Spring Cloud Kubernetes Leader Election