源码分析ElasticJob 失效转移

源码分析ElasticJob 故障转移

原理描述:

ElasticJob设计核心理念:充分利用服务器资源执行任务,确保每个任务可以在多个节点上执行
ElasticJob失效转移过程:如果在任务执行过程中有一个执行实例挂了,那么之前被分配到这个实例的任务(或者分片)会在下次任务执行之前被重新分配到其他正常节点实例上执行

失效转移核心类如下:

FailoverService 作业失效转移服务
FailoverNode 作业失效转移数据存储路径。
FailoverListenerManager 作业失效转移监听管理器

失效转移监听管理器详解

class JobCrashedJobListener extends AbstractJobListener {
        protected void dataChanged(final String path, final Type eventType, final String data) {
			//判断1
            if (isFailoverEnabled() && Type.NODE_REMOVED == eventType && instanceNode.isInstancePath(path)) {
                String jobInstanceId = path.substring(instanceNode.getInstanceFullPath().length() + 1);
                if (jobInstanceId.equals(JobRegistry.getInstance().getJobInstance(jobName).getJobInstanceId())) {
                    return;
                }
                List<Integer> failoverItems = failoverService.getFailoverItems(jobInstanceId);
                if (!failoverItems.isEmpty()) {   
                    for (int each : failoverItems) {
                        failoverService.setCrashedFailoverFlag(each);                                                                                      
                        failoverService.failoverIfNecessary();
                    }
                } else {
                    for (int each : shardingService.getShardingItems(jobInstanceId)) {
                        failoverService.setCrashedFailoverFlag(each);
                        failoverService.failoverIfNecessary();
                    }
                }
            }
        }
    }

源码讲解:
1.如果配置中开启故障转移机制,监听/instances/{jobName}/leader 子节点删除事件,此时认为有节点宕机,执行故障转移方式
2.接着获取节点实例对象
3.此时删除任务节点id匹配当前实例节点id,如果一致忽略
4.获取当前失效转移分片集合,获取特定集合failoverService.getFailoverItems()实现如下

public void setCrashedFailoverFlag(final int item) {  
if (!isFailoverAssigned(item)) {    //创建节点 /{jobName}/leader/failover/items/{index}
    jobNodeStorage.createJobNodeIfNeeded(FailoverNode.getItemsNode(item));
 }

public List<Integer> getFailoverItems(final String jobInstanceId) {
        List<String> items = jobNodeStorage.getJobNodeChildrenKeys(ShardingNode.ROOT);
        List<Integer> result = new ArrayList<>(items.size());
        for (String each : items) {
            int item = Integer.parseInt(each);
            String node = FailoverNode.getExecutionFailoverNode(item);
            if (jobNodeStorage.isJobNodeExisted(node) && jobInstanceId.equals(jobNodeStorage.getJobNodeDataDirectly(node))) {
                result.add(item);
            }
        }
        Collections.sort(result);
        return result;
}

继续分析:
1.创建节点 /{jobName}/leader/failover/items/{index}
2.获取/{jobName}/leader/sharding 子节点集合
3.判断failover节点是否存在,存在判断该分片是否为当前任务的分片节点
4.循环分片集合,查看是否执行失效转移failoverService.failoverIfNecessary() 实现如下

public void failoverIfNecessary() {
        if (needFailover()) {//选举主节点
            jobNodeStorage.executeInLeader(FailoverNode.LATCH, new FailoverLeaderExecutionCallback());
        }
    }

public void executeInLeader(final String latchNode, final LeaderExecutionCallback callback) {     
 try (LeaderLatch latch = new LeaderLatch(getClient(), jobNodePath.getFullPath(latchNode))) {         
     latch.start();                                                                                   
     latch.await();                                                                                   
     callback.execute();                                                                              
     //CHECKSTYLE:OFF
     } catch (final Exception ex) {                                                                       
      //CHECKSTYLE:ON                                                                                      
     handleException(ex);                                                                             
    }                                                                                                    
}                                                                                         
 

private boolean needFailover() {
        return jobNodeStorage.isJobNodeExisted(FailoverNode.ITEMS_ROOT) && !jobNodeStorage.getJobNodeChildrenKeys(FailoverNode.ITEMS_ROOT).isEmpty()
                && !JobRegistry.getInstance().isJobRunning(jobName);
    }
}

1.失效转移过程中,需要判断是否需要失效转移,并判断是 否/{jobName}/leader/failover/items/{index}该节点存在
2.然后选举主节点 /{jobName}/leader/failover/latch( 分配失效转移分片项时占用的分布式锁为curator的分布式锁使用)
3.选举成功的主节点实例会在/{jobName}/leader/sharding/items/failover中设置当前实例instanceId
4.删除/{jobName}/leader/failover/items/分片项(新的实例接替失效转移分片)
5.回调过程中,存在多个分片情况,批量处理 job实例jobInstanceId绑定到分片参数路径下
5.获取分片信息,执行分片任务调度

作者简介:张程 技术研究

更多文章请关注微信公众号:zachary分解狮 (frankly0423)
my

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值