影视网站如何做seo,网页搭建环境,爱站网官网查询域名,高校网站首页设计文章目录 前言一、架构图和流程图二、流程说明1.服务启动初始化ZK、注册所有服务节点信息-MasterRegister2.创建、运行服务节点#xff0c;并管理服务节点-LeaderSelectorZkClient。3.典型场景-调度服务单体执行-DigitalEmpTask 总结参考 前言
Spring Boot 主备切换可以采用数… 文章目录 前言一、架构图和流程图二、流程说明1.服务启动初始化ZK、注册所有服务节点信息-MasterRegister2.创建、运行服务节点并管理服务节点-LeaderSelectorZkClient。3.典型场景-调度服务单体执行-DigitalEmpTask 总结参考 前言
Spring Boot 主备切换可以采用数据库的主从同步、Zookeeper选举、Redis Sentinel等技术实现高可用。
其中数据库的主从同步可以通过配置数据库的主从复制来实现。在主节点出现故障时从节点可以自动接管并成为新的主节点。这种方式实现简单但需要手动配置主从复制。
Zookeeper选举可以利用Zookeeper的特性来实现即在Zookeeper上创建一个临时节点作为选举的标志节点创建成功的服务就是主节点其他服务则是备节点。在主节点出现故障时Zookeeper会重新选举一个新的主节点。这种方式实现相对较为复杂但具有更好的灵活性和可扩展性。
Redis Sentinel是Redis提供的一种高可用性解决方案可以自动完成主从切换同时具有自动故障检测和恢复等功能。Redis Sentinel需要在多个节点上运行并且可以配置多个从节点来实现数据备份和故障转移。当主节点故障时Redis Sentinel会自动将其中一个从节点升级为新的主节点保证服务的高可用性。 一、架构图和流程图 说明 主备模式中有1个主服务节点、多个备服务节点由主服务节点向外提供服务备服务节点监听主机状态一旦主服务节点宕机备服务节点速接管主服务继续向外提供服务。 通过Zookeeper集群服务注册/发现特性完成主备切换;
1-工作服务器启动时各服务节点在ZooKeeper的Servers节点下创建临时节点并把基本信息写入临时节点完成注册;2-各服务节点实时监听Servers节点的子节点列表并尝试创建Master临时节点谁创建成功谁就是Master其他的服务节点就作为Slave3-所有的服务节点关注Master节点的删除事件通过监听Master节点的删除事件来体现Master服务器是否宕机创建临时节点的服务器一旦宕机它所创建的临时节点即会自动删除4-.一旦Master服务器宕机其它服务节点开始新一轮的Master选举计算新的Master服务器。
二、流程说明
1.服务启动初始化ZK、注册所有服务节点信息-MasterRegister 代码如下示例 package com.merak.hyper.automation.zk;
import com.merak.hyper.automation.util.ZkHelper;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/*** author harry* version 1.0* ClassName: ZkMasterRegister* description: zk主备MasterRegister:启动时初始化ZK、注册所有服务节点信息*/
Component
Order(1)
public class ZkMasterRegister implements CommandLineRunner {public static final Logger log LoggerFactory.getLogger(ZkMasterRegister.class);Value(${zk_master.status})private String status;Value(${zk_master.serviceurl})private String serviceurl;Overridepublic void run(String... args) {if( ZkHelper.getInstance().zookeeperOpen(status) ) {String[] workServerArr ZkHelper.getInstance().workServerInfo();if (!StringUtils.isBlank(workServerArr[0]) !StringUtils.isBlank(serviceurl)) {LeaderSelectorZkClient.getInstance().initZk(serviceurl, workServerArr[0], workServerArr[1], workServerArr[2], ZkHelper.getInstance().zkMasterPath());log.info(程序启动,初始化ZK、注册服务节点等信息!);} else {log.warn(参数未配置zookeeper服务器的地址[sys.zookeeper.serviceurl],请检查!);//ip 和 name}}else{log.warn(当前调度服务为单节点服务未配置zookeeper服务器);}}
}2.创建、运行服务节点并管理服务节点-LeaderSelectorZkClient。
工作服务器节点的基本信息 每个分布式服务节点基本信息包括serviceIp、servicePort和name 确保分布式服务节点的唯一性。
package com.merak.hyper.automation.zk;
import java.io.Serializable;/*** 工作服务器节点的基本信息*/
public class RunningData implements Serializable {private static final long serialVersionUID 4260577459043203630L;private String serviceIp;private String servicePort;private String name;public String getServiceIp() {return serviceIp;}public void setServiceIp(String serviceIp) {this.serviceIp serviceIp;}public String getServicePort() {return servicePort;}public void setServicePort(String servicePort) {this.servicePort servicePort;}public String getName() {return name;}public void setName(String name) {this.name name;}Overridepublic String toString() {return RunningData{ serviceIp serviceIp \ , servicePort servicePort \ , name name \ };}
}创建、运行服务节点并管理服务节点 代码如下示例
/*** description: ZOOKEEPER_SERVER连接和服务节点管理* param: [zookeeper_server, session_connection_timeout, serviceIp, serviceName] * return: void*/public void initZk(String zookeeper_server,String serviceIp, String serviceName, String servicePort,String zkMasterName) {try {log.info(创建服务器节点[serviceIp,serviceName]开始!);//创建zkClientclient ZkConnect.getInstance().connectZkSever(zookeeper_server);//创建serverDatarunningData new RunningData();runningData.setServiceIp(serviceIp);runningData.setName(serviceName);runningData.setServicePort(servicePort);//创建服务workServer new WorkServer(runningData,zkMasterName);workServer.setZkClient(client);workServer.start();log.info(创建服务器节点[serviceIp,serviceName]结束!);} catch (Exception e) {log.error(zookeeper_server init error,msg e.getMessage());} finally {log.info(zookeeper_server finally ...);}}服务节点启动、订阅Master节点删除事件、争抢Master权利成为master节点 代码片断如下 //初始化工作服务器WorkServer信息public WorkServer(RunningData rd, String zkMasterName) {this.serverData rd; // 记录服务器基本信息this.MASTER_PATH zkMasterName;this.dataListener new IZkDataListener() {public void handleDataDeleted(String dataPath) {//master切换时需要重置 调度云托管任务表 schedule_status initzkResetScheduleStatus.switchResetScheduleStatus();log.info(dataPath 路径已经删除开始新一轮Master抢占);if (masterData ! null masterData.getName().equals(serverData.getName()) masterData.getServiceIp().equals(serverData.getServiceIp()) masterData.getServicePort().equals(serverData.getServicePort())) {takeMaster();//自己就是上一轮的Master服务器则直接抢} else {//否则延迟5秒后再抢。应对网络抖动给上一轮的Master服务器优先抢占master的权利避免不必要的数据迁移开销delayExecutor.schedule(new Runnable() {public void run() {log.info(服务器开始抢占Master权利);takeMaster();}}, delayTime, TimeUnit.SECONDS);}}public void handleDataChange(String dataPath, Object data) {log.info(IZkDataListener - handleDataChange,dataPath dataPath ,data data.toString());}};}.....// 1 启动服务器public void start() throws Exception {if (running) {throw new Exception(server has startup...);}running true;// 2 订阅Master节点删除事件zkClient.subscribeDataChanges(MASTER_PATH, dataListener);// 3 争抢Master权利takeMaster();}.....// 争抢Masterprivate void takeMaster() {if (!running)return;try {if (!zkClient.exists(MASTER_PATH)) {// 尝试创建Master临时节点zkClient.create(MASTER_PATH, serverData, CreateMode.EPHEMERAL);masterData serverData;log.info(服务器节点[ serverData.getServiceIp() , serverData.getName() , serverData.getServicePort() ]争抢Master成功成为master[isMaster]!);} else {// 已被其他服务器创建了,读取Master节点信息RunningData runningData zkClient.readData(MASTER_PATH, true);log.info(master已被服务器节点[ runningData.getServiceIp() , runningData.getName() , runningData.getServicePort() ]占有,当前节点[ serverData.getServiceIp() , serverData.getName() , serverData.getServicePort() ]只能读取master节点信息!);if (runningData null) {takeMaster(); // 没读到或读取瞬间Master节点宕机可争抢} else {masterData runningData;}}} catch (ZkNodeExistsException e) {log.error(当前节点 serverData.getServiceIp() , serverData.getName() , serverData.getServicePort() ]创建Master临时节点异常,msg e.getMessage());} catch (Exception e) {log.error(当前节点 serverData.getServiceIp() , serverData.getName() , serverData.getServicePort() ]争抢Master异常,msg e.getMessage());}}3.典型场景-调度服务单体执行-DigitalEmpTask
需求某个时刻只允许Master节点执行调度服务其它Slave从节点处于闲置、不执行状态。
package com.merak.hyper.automation.quartz.task;
import com.merak.hyper.automation.util.DateUtils;
import com.merak.hyper.automation.util.ZkHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/*** author harry* version 1.0* ClassName: BizOrderTask* description: 任务队列服务调度*/
Component
public class DigitalEmpTask {public static final Logger log LoggerFactory.getLogger(DigitalEmpTask.class);Value(${zk_master.status})private String status;Scheduled(cron 0/30 * * * * ?)protected void digitalEmpTaskScheduler() {//1.判断是否开启zookeeper分布式调度模式if( ZkHelper.getInstance().zookeeperOpen(status) ) {//2.判断当前工作服务节点为Master节点if( ZkHelper.getInstance().checkMaster() ) {executeCloudTask();}}else{//1.未开启zookeeper分布式调度模式为单节点部署executeCloudTask();}}public void executeCloudTask(){log.info(任务开始执行,时间: DateUtils.dateTimeNow(DateUtils.YYYY_MM_DD_HH_MM_SS));try {} catch (Exception e) {log.error(调度失败原因 e.getMessage());}}}
总结
1.线上1主2从已运行半年可达到HA业务需求、自动切换能力 2.前端采取Nginx负载、分流配置多个工作服务节点
参考
浅析如何基于ZooKeeper实现高可用架构 源代码下载