基于Zookeeper实现调度任务选主及心跳检测
在微服务架构中使用ZooKeeper实现分布式任务调度选主,并确保Follower节点能实时监控Master状态并及时触发重新选举,可以通过以下方案实现:
一、核心设计原理
1. ZooKeeper特性利用
ZK功能 | 在选主中的应用 |
---|---|
临时节点(EPHEMERAL) | Master创建临时节点,会话断开时节点自动删除(相当于心跳检测) |
Watcher机制 | Follower监听Master节点变化 |
顺序节点(SEQUENTIAL) | 实现公平的选举排序 |
2. 状态监控流程
participant Master
participant Follower1
participant Follower2
participant ZK
Master->>ZK: 创建/master_leader临时节点
Follower1->>ZK: 监听/master_leader节点
Follower2->>ZK: 监听/master_leader节点
Note over Master: 正常工作时定期刷新会话
Master--xZK: 会话超时断开
ZK->>Follower1: 触发NodeDeleted事件
ZK->>Follower2: 触发NodeDeleted事件
Follower1->>ZK: 尝试创建新/master_leader节点
ZK-->>Follower1: 创建成功,成为新Master
Follower2->>ZK: 监听新的/master_leader节点
二、完整实现方案
1. 添加依赖
<!-- Curator客户端(推荐) -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>5.5.0</version>
</dependency>
2. 选主服务实现
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.leader.LeaderSelector;
import org.apache.curator.framework.recipes.leader.LeaderSelectorListener;
import org.apache.curator.framework.state.ConnectionState;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component
public class ZkLeaderElection {
private final CuratorFramework zkClient;
private LeaderSelector leaderSelector;
private volatile boolean isLeader = false;
public ZkLeaderElection(CuratorFramework zkClient) {
this.zkClient = zkClient;
}
@PostConstruct
public void init() throws Exception {
leaderSelector = new LeaderSelector(zkClient, "/scheduler/leader",
new LeaderSelectorListener() {
@Override
public void takeLeadership(CuratorFramework client) throws Exception {
// 成为Leader后的逻辑
isLeader = true;
System.out.println("当前节点当选为Leader");
try {
while (true) {
Thread.sleep(1000); // 模拟持续工作
}
} finally {
isLeader = false;
}
}
@Override
public void stateChanged(CuratorFramework client, ConnectionState newState) {
// 连接状态变化处理
if (newState == ConnectionState.LOST) {
isLeader = false;
}
}
});
leaderSelector.autoRequeue(); // 自动重新参与选举
leaderSelector.start();
}
@PreDestroy
public void shutdown() {
if (leaderSelector != null) {
leaderSelector.close();
}
}
public boolean isLeader() {
return isLeader;
}
}
3. 增强型状态监控(生产级)
// 在init()方法中添加以下逻辑
public void init() throws Exception {
// ...原有代码...
// 添加额外的心跳检测
zkClient.getConnectionStateListenable().addListener((client, newState) -> {
if (newState == ConnectionState.RECONNECTED) {
// 重连后强制检查Leader状态
checkLeaderStatus();
}
});
// 启动定时检查任务
Executors.newSingleThreadScheduledExecutor()
.scheduleAtFixedRate(this::checkLeaderStatus, 0, 5, TimeUnit.SECONDS);
}
private void checkLeaderStatus() {
try {
if (zkClient.checkExists().forPath("/scheduler/leader") == null) {
System.out.println("Leader节点不存在,触发重新选举");
}
} catch (Exception e) {
e.printStackTrace();
}
}
三、关键优化点
1. 双Watch机制
// 除了LeaderSelector内置监听,额外添加数据Watch
zkClient.getData().usingWatcher((Watcher) event -> {
if (event.getType() == Watcher.Event.EventType.NodeDeleted) {
System.out.println("Leader节点被删除,立即触发选举");
}
}).forPath("/scheduler/leader");
2. 选举性能优化
参数 | 推荐值 | 说明 |
---|---|---|
sessionTimeoutMs | 10000-15000ms | 根据网络状况调整 |
leaderSelector.autoRequeue() | 必须启用 | 保证节点退出后重新参与选举 |
retryPolicy.baseSleepTimeMs | 1000ms | 首次重试延迟 |
3. 故障转移时间控制
// 在ZK配置中优化
@Bean
public CuratorFramework zkClient() {
return CuratorFrameworkFactory.builder()
.connectString("zk1:2181,zk2:2181,zk3:2181")
.sessionTimeoutMs(15000) // 会话超时
.connectionTimeoutMs(5000) // 连接超时
.retryPolicy(new ExponentialBackoffRetry(1000, 3)) // 重试策略
.build();
}
故障转移时间 = 会话超时时间 + 选举时间(通常可控制在15秒内)
四、生产环境建议
1. 监控指标
指标名称 | 采集方式 | 告警阈值 |
---|---|---|
ZK选举次数 | ZK的leader_election 计数器 |
1小时内>5次 |
Master存活时间 | 节点数据中的时间戳 | 连续3次<30秒 |
节点连接状态 | Curator事件监听 | RECONNECTED状态持续>1分钟 |
2. 部署架构
[微服务实例1] [微服务实例2] [微服务实例3]
| | |
+------------+------------+
|
[ZooKeeper Ensemble]
|
[监控系统(Prometheus + Grafana)]
3. 异常场景处理
- 脑裂防护:启用ZK的
quorum
机制(至少3节点) - 网络分区:配合Sidecar代理检测真实网络状态
- 持久化问题:定期备份
/scheduler
节点数据
五、与Spring Cloud集成
1. 健康检查端点
@RestController
@RequestMapping("/leader")
public class LeaderController {
@Autowired
private ZkLeaderElection election;
@GetMapping("/status")
public ResponseEntity<String> status() {
return election.isLeader()
? ResponseEntity.ok("MASTER")
: ResponseEntity.ok("FOLLOWER");
}
}
2. 调度任务示例
@Scheduled(fixedRate = 5000)
public void scheduledTask() {
if (zkLeaderElection.isLeader()) {
System.out.println("只有Master执行的任务...");
}
}
六、对比Redisson方案
维度 | ZooKeeper方案 | Redisson方案 |
---|---|---|
实时性 | 秒级(依赖ZK会话超时) | 秒级(依赖Redis TTL) |
可靠性 | 高(CP系统) | 中(依赖Redis持久化) |
运维复杂度 | 较高(需维护ZK集群) | 较低(复用Redis) |
适用场景 | 强一致性要求的系统 | 允许短暂脑裂的场景 |
通过以上方案,你的微服务可以实现:
- 秒级故障检测:基于ZK临时节点和Watcher机制
- 自动快速选主:利用Curator的选举算法
- 生产级可靠性:多重监控和防护机制
- 无缝集成Spring生态:与
@Scheduled
等组件协同工作
基于Zookeeper实现调度任务选主及心跳检测的更多相关文章
- kazoo python zookeeper 选主
本文讲述基于zookeeper选主与故障切换的方法.我们的例子使用的是python. 使用的库是kazoo,安装方式 pip install kazoo 应用场景: 多个实例部署,但不是" ...
- 简述 zookeeper 基于 Zab 协议实现选主及事务提交
Zab 协议:zookeeper 基于 Paxos 协议的改进协议 zookeeper atomic broadcast 原子广播协议. zookeeper 基于 Zab 协议实现选主及事务提交. 一 ...
- 聊聊Zookeeper应用场景、架构设计、选主机制
Zookeeper作为一个分布式协调系统提供了一项基本服务:分布式锁服务,分布式锁是分布式协调技术实现的核心内容.像配置管理.任务分发.组服务.分布式消息队列.分布式通知/协调等,这些应用实际上都是基 ...
- zookeeper curator选主(Leader)
在分布式系统设计中,选主是一个常见的场景.选主是一个这样的过程,通过选主,主节点被选择出来控制其他节点或者是分配任务. 选主算法要满足的几个特征: 1)各个节点均衡的获得成为主节点的权利,一旦主节点被 ...
- Zookeeper笔记之使用zk实现集群选主
一.需求 在主从结构的集群中,我们假设硬件机器是很脆弱的,随时可能会宕机,当master挂掉之后需要从slave中选出一个节点作为新的master,使用zookeeper可以很简单的实现集群选主功能. ...
- 基于zookeeper+mesos+marathon的docker集群管理平台
参考文档: mesos:http://mesos.apache.org/ mesosphere社区版:https://github.com/mesosphere/open-docs mesospher ...
- 基于zookeeper的activemq的主从集群配置
项目,要用到消息队列,这里采用activemq,相对使用简单点.这里重点是环境部署. 0. 服务器环境 RedHat710.90.7.210.90.7.1010.90.2.102 1. 下载安装zoo ...
- ActiveMQ 基于zookeeper的主从(levelDB Master/Slave)搭建以及Spring-boot下使用
0:说明 ActiveMQ 5.9.0新推出的主从实现,基于zookeeper来选举出一个master,其他节点自动作为slave实时同步消息.因为有实时同步数据的slave的存在,master不用担 ...
- 基于zookeeper实现分布式配置中心(一)
最近在学习zookeeper,发现zk真的是一个优秀的中间件.在分布式环境下,可以高效解决数据管理问题.在学习的过程中,要深入zk的工作原理,并根据其特性做一些简单的分布式环境下数据管理工具.本文首先 ...
- Etcd 使用场景:通过分布式锁思路实现自动选主
分布式锁?选主? 分布式锁可以保证当有多台实例同时竞争一把锁时,只有一个人会成功,其他的都是失败.诸如共享资源修改.幂等.频控等场景都可以通过分布式锁来实现. 还有一种场景,也可以通过分布式锁来实现, ...
随机推荐
- 云辅助隐私集合求交(Server-Aided PSI)协议介绍:学习
原文来自:云辅助隐私集合求交(Server-Aided PSI)协议介绍,下面学习一波,并记录一些笔记. 背景 总结: 1.PSI-CA和PSI相比,前者在乎的是交集的大小,后者在乎的是交集本身.另外 ...
- 重写equals()方法(idea生成的高效方法)
equals 方法Object 类中的 equals 方法用于检测一个对象是否等于另外一个对象.在 Object 类中,这个方法将判断两个对象是否具有相同的引用.如果两个对象具有相同的引用, 它们一定 ...
- 自定义swagger扩展解析jsondoc
需求规定 为了减少注释和swagger注解的重复定义, 通过规范注释, 让swagger可以通过javadoc来产生 替换@Api.@ApiOperation.@ApiModel.@ApiModelP ...
- uni-app无法触发onReachBottom事件
我们经常会遇见列表; 但是今天却发现下拉的时候: 无法触发onReachBottom事件; 原来是因为列表内容嵌套出现问题: 导致onReachBottom事件无法被触发 记住:列表内容如果是组件:外 ...
- OpenStack基本介绍
本文分享自天翼云开发者社区<OpenStack基本介绍>,作者:m****n 基本介绍 OpenStack是一个开源的云计算管理平台项目,由几个主要的组件组合起来完成具体工作.OpenSt ...
- idea遇见Command line is too long. Shorten command line for Main or also for Application default configuration?
<property name="dynamic.classpath" value="true" /> 第一步:找到项目目录下的.idea\works ...
- Mac安装Zookeeper
软件版本:3.4.10 一.软件下载 下载链接:http://archive.apache.org/dist/zookeeper/ 解压缩:tar -zxf zookeeper-3.4.10.t ...
- Shell脚本常用写法
一.变量定义 | 赋值 | 输出 1.debugmap #!/bin/bash source /etc/profile # hive_json_tuple_params_orignal.tmp # e ...
- NOI春季测试游记
Day -20 本来以为不能报名,但听说初中生可以报名,遂报名. Day -20~-2 刷一些题,并学了大量新知识如DP. Day n(-15≤n≤-5) 在公众号的名单上看到我的名字. 同校还有人参 ...
- Flink学习(十七) Emitting to Side Outputs(侧输出)
我们在生产实践中经常会遇到这样的场景,需把输入源按照需要进行拆分,比如我期望把订单流按照金额大小进行拆分,或者把用户访问日志按照访问者的地理位置进行拆分等.面对这样的需求该如何操作呢? 大部分的Dat ...