2021-12-06---2021SC@SDUSC---DolphinScheduler(11)

2021-12-06
2021SC@SDUSC

2021-12-06-DolphinScheduler(11)

1.ZKMasterClient

private ZKMasterClient(ProcessDao processDao){
	this.processDao = processDao;
	init();
}

public void init(){
	// init dao
	this.initDao();

	InterProcessMutex mutex = null;
	try {
		// create distributed lock with the root node path of the lock space as /dolphinscheduler/lock/failover/master
		String znodeLock = getMasterStartUpLockPath();
		mutex = new InterProcessMutex(zkClient, znodeLock);
		mutex.acquire();

		// init system znode
		this.initSystemZNode();

		// monitor master
		this.listenerMaster();

		// monitor worker
		this.listenerWorker();

		// register master
		this.registerMaster();

		// check if fault tolerance is required,failure and tolerance
		if (getActiveMasterNum() == 1) {
			failoverWorker(null, true);
			failoverMaster(null);
		}

	}catch (Exception e){
		logger.error("master start up  exception : " + e.getMessage(),e);
	}finally {
		releaseMutex(mutex);
	}
}
总结:
initDao。其实就是初始化alertDao,调DaoFactory.getDaoInstance
(AlertDao.class)。
申请/dolphinscheduler/lock/failover/master路径的分布式锁。
申请到锁之后,依次调用initSystemZNode、listenerMaster、
listenerWorker、registerMaster.
如果当前活动的master个数为1则进行容灾。

listenerMaster是监听到其他master节点被移除后调用removeZKNodePath
如果是当前节点就退出。

removeZKNodePath,它主要是处理死掉的节点、进行预警,
如果要进行故障转移,就调用failoverServerWhenDown。
这是一个非常重要的方法,它在里面按照不同情况调用了failoverMaster或failoverWorker。也就是说master和worker的故障转移都是在master处理的。

2.failoverMaster

failoverMaster查询了指定master节点运行的流程定义实例,然后调动processNeedFailoverProcessInstances进行处理。

private void failoverMaster(String masterHost) {
	logger.info("start master failover ...");

	List<ProcessInstance> needFailoverProcessInstanceList = processDao.queryNeedFailoverProcessInstances(masterHost);

	//updateProcessInstance host is null and insert into command
	for(ProcessInstance processInstance : needFailoverProcessInstanceList){
		processDao.processNeedFailoverProcessInstances(processInstance);
	}

	logger.info("master failover end");
}
processNeedFailoverProcessInstances是更新为当前流程定义实例host字段为null字符串
插入一条类型为RECOVER_TOLERANCE_FAULT_PROCESS的Command,
参数是流程定义实例id。
@Transactional(rollbackFor = Exception.class)
public void processNeedFailoverProcessInstances(ProcessInstance processInstance){
    //1 update processInstance host is null
    processInstance.setHost("null");
    processInstanceMapper.updateById(processInstance);

    //2 insert into recover command
    Command cmd = new Command();
    cmd.setProcessDefinitionId(processInstance.getProcessDefinitionId());
    cmd.setCommandParam(String.format("{\"%s\":%d}", Constants.CMDPARAM_RECOVER_PROCESS_ID_STRING, processInstance.getId()));
    cmd.setExecutorId(processInstance.getExecutorId());
    cmd.setCommandType(CommandType.RECOVER_TOLERANCE_FAULT_PROCESS);
    createCommand(cmd);
}

3.RECOVER_TOLERANCE_FAULT_PROCESS

之后我们定位到ProcessDao.constructProcessInstance,
如果是RECOVER_TOLERANCE_FAULT_PROCESS类型,则调用processInstance.setRecovery(Flag.YES)。

case  RECOVER_TOLERANCE_FAULT_PROCESS:
      processInstance.setRecovery(Flag.YES);
      runStatus=processInstance.getState();
      break;

回到cmd的构造上,它设置了4个值,就得研究下这跟普通的Command的其他区别了。

Command command = new Command();
command.setCommandType(CommandType.SCHEDULER);
command.setExecutorId(schedule.getUserId());
command.setFailureStrategy(schedule.getFailureStrategy());
command.setProcessDefinitionId(schedule.getProcessDefinitionId());
command.setScheduleTime(scheduledFireTime);
command.setStartTime(fireTime);
command.setWarningGroupId(schedule.getWarningGroupId());
command.setWorkerGroupId(schedule.getWorkerGroupId());
command.setWarningType(schedule.getWarningType());
command.setProcessInstancePriority(schedule.getProcessInstancePriority());

现在回过头去ProcessScheduleJob.execute看一下,普通Command是如何构造的。大家会发现RECOVER_TOLERANCE_FAULT_PROCESS的Command多了一个commandParam的设置,这个param的key是Constants.CMDPARAM_RECOVER_PROCESS_ID_STRING。
定位到ProcessDao.constructProcessInstance,这里有对Constants.CMDPARAM_RECOVER_PROCESS_ID_STRING的处理。

if(cmdParam != null{
 Integer processInstance =0;
 //recover from fallure or pause tasks
 if(cmdParam.containsKey(Constants.CMDPAPM_RECOVER_PROCESS_ID_STRING)){
   String procssId = cmdParam.get(Constants.CMDPARAM_RECOVER_PROCESS_ID_STRING);
   processInstanceId = Integer.parseInt(processId);
   if(processInstanceId==0){...}
   

 }else if(cmdParam.containsKey(Contants.CMDPARAM_SUB_PROCESS)){
   //sub process map
   String pId =cmdParam.constainsKey(Constants.CMDPARAM_SUB_PROCESS);
   processInstanceId=Integer.parseInt(pId);
 }else if(cmdParam.containsKey(Constants.CMDPARAM_RECOVERY_WAITING_THREAD)){...}
     if(processInstanceId ==0 ){
  processInstance = generateNewProcessInstance(processDefinition,command,cmdParam);
     }else{
   processInstance = this.findProcessInstanceDetailById(processInstanceId);
     }
      processDefiniton = processDefineMapper.selectById(processInstance.getProcessDefinitionId());
      processInstance.setProcessDefinition(processDefinition);
 
//reset command parameter
        if(processInstance.getCommendParam()!= null){
         Map<String,string> processCmdParam =JSONUtils.toMap(processInstance.getCommandParam());
           for(Map.Enrty<String,String>entry:processCmdParam.entrySet()){
               if(!cmdParam.containsKey(entry.getKey())){
                     cmdParam.put(entry.getKey(),entry.getValue());
                }

         }
    }
 }

if(cmdParam.containsKey(Contains.CMDPARAM_SUB_PROCESS)){...}

}else{
//generate one new process,instance
  processInstance = generateNewProcessInstance(processDefinition,command,cmdParam);
  }
处理就是获取到Constants.CMDPARAM_RECOVER_PROCESS_ID_STRING的值,
然后查询到流程定义实例对象而不是重新创建一个。
后续逻辑就是把流程定义实例的参数,全都put到cmdParam中进行后续的逻辑判断

根据流程实例id查询,而不是重新创建。
这样的好处是可以避免已经执行成功的任务不再重复执行。
那处于running状态的任务呢?这个就要结合master的退出来看了。
其实master会等待所调度的所有流程定义实例中的任务直至结束的。
也就是说,调度的任务应该会被正常的执行完毕的,
状态最终会被更新成失败或者成功。

如果宕掉的master没有能成功更新作业的状态,
DolphinScheduler没有处理这部分异常,
此时的作业只能是永久处于running状态,除非手动干预。
到这里就会发现,其实master的故障转移就是把某个master节点的流程定义实例
交由其他master节点去驱动,原来的流程定义实例中的任务状态没有任何改变。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

奋斗的仓鼠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值