elastic-job-lite 既然去中心化,為何要選舉主節點

a_wei發表於2019-09-29

開篇語

上一篇文章介紹了elastic-job-lite的入門,架構。使用和一些流程,裡面提到elastic-job-lite是一個去中心化,輕量級的任務排程框架,那為什麼elastic-jib-lite在啟動時要選取主節點呢?難道我看錯了,哈哈,不可能的,後文 elastic-job-lite簡稱ejl。

leader選舉

ejl定位為輕量級,去中心化,其任務排程由各自的機器驅動,各臺機器之間透過zk去協調,ejl為每個任務都建立一個JobScheduler,而在JobScheduler的初始化中回為每個job選舉一個主節點,記住不是全域性一個主節點,而是每個任務一個主節。如下圖,每個節點上都執行兩個任務job1,job2,那麼在啟動時每個節點就會建立兩個JobScheduler物件,為每一個任務在叢集中選舉一個leader。

這個leader是怎麼選舉出來的呢?什麼時候開始選舉?一、在整個叢集啟動時為每個任務選舉leader; 二、當有些任務的leader下線時,會重新選舉。

叢集啟動時選舉leader

在JobScheduler中
public void init(){
    schedulerFacder.registerStartUpInfo();
}
public void registerStartUpInfo(){
    leaderService.electLeader();
}
/** * 選舉主節點. */
public void electLeader() {    
    log.debug("Elect a new leader now.");
    jobNodeStorage.executeInLeader(LeaderNode.LATCH,
        new   LeaderElectionExecutionCallBack());    
    log.debug("Leader election completed.");
}

public void executeInLeader(final String latchNode, 
    final LeaderExecutionCallback callback) {
    //透過LeaderLatch進行選舉
    //這是curator(zk的客戶端)中類
    LeaderLatch latch =
        new   LeaderLatch(getClient()jobNodePath.getFullPath(latchNode));
    //開始選舉
    latch.start();
    //阻塞,直到選舉成功
    latch.await();
    //在回撥方法中寫入主節點標記
    callback.execute();
}

在callback.execute()中執行如下,再次判斷沒有主節點,將當前機器示例id寫入

 if (!hasLeader()) {
    jobNodeStorage.fillEphemeralJobNode(
                    LeaderNode.INSTANCE,instanceId));   
 }

leader重新選舉,主要是透過LeaderElectionJobListener這個監聽器來實現leader重新選舉,當一個job還在執行,但leader節點下線了,就要重新選舉leader

class LeaderElectionJobListener extends AbstractJobListener{
    protected void dataChanged(){
        //具體選舉看上面的程式碼
        leaderService.electLeader()
    }
}

主節點的選舉的本質就是大夥競爭一個zk的分散式鎖。誰先得到鎖,誰就是主節點。

何時使用leader?有什麼作用?

分散式系統中,在一個任務執行過程中,有多個機器,多個分片,那麼如何去分配呢?哪些機器執行哪些分片呢,如果大家都參與豈不是亂了,這個時候就需要一個領導者來拍板。在ejl中有兩處需要leader節點來參與:

  1. 機器啟動後,任務開始第一次執行時,需要leader來分片
  2. 當叢集中有新的節點增加時,分片的數量有變化時或者有一些節點下線時都會觸發重新分片

主要程式碼如下,大家閱讀原始碼時可從AbstractElasticJobExecute類中execute方法開始看起。

AbstractElasticJobExecute類中
public final void execute(){
    //獲取分片,這個方法中主節點leader會分片
    ShardingContexts shardingContexts = 
        jobFacade.getShardingContexts();
}

在 getShardingContexts()中,有如下方法
shardingService.shardingIfNecessary();
/** 
    如果需要分片且當前節點為主節點, 則作業分片. 
    如果當前無可用節點則不分片.
*/
public void shardingIfNecessary() {
    //不是主節點直接返回,不允許分片
    if (!leaderService.isLeaderUntilBlock()) {   
        blockUntilShardingCompleted();       
        return;
    }
    ....
}

leader節點刪除的時機

leader節點刪除的時機有三處,一,在leader節點所在機器程式CRASHED時,jvm透過鉤子方法刪除自己;二,作業被禁用時刪除leader節點,三,主節點程式遠端關閉

leader機器程式關閉

JobShutdownHookPlugin類中
public void shutdown() {
    if (leaderService.isLeader()) {    
        leaderService.removeLeader();
    }
}

作業被禁用時

LeaderAbdicationJobListener類中
protected void dataChanged(
    //判斷是leader,並且作業被禁用
    if (leaderService.isLeader() 
        && isLocalServerDisabled(path, data)) {  
        leaderService.removeLeader();
    }
}

作業終止排程時

InstanceShutdownStatusJobListener類中
    protected void dataChanged(
        //當job未暫停,
        //並且排程控制器未暫停,
        //並且事件是移除這個例項,
        //並且執行例項未被移除
        if (!JobRegistry.getInstance().isShutdown(jobName) 
            &&
             !JobRegistry.getInstance()
             .getJobScheduleController(jobName).isPaused() 
            &&
            isRemoveInstance(path, eventType) 
            &&
            !isReconnectedRegistryCenter()) {  
        //在這個方法中removeLeader    
        schedulerFacade.shutdownInstance();
    }
}

EJL的leader在zk中的資料結構

程式碼在LeaderNode類中

leader在zk中的根路徑

String ROOT = "leader";

這是leader進行選舉的父路徑 /leader/election

String ELECTION_ROOT = ROOT + "/election";

儲存主節點的地址 /leader/election/instance 這是一個臨時節點,leader所在的機器下線後,這個路徑就會消失,對於重新選舉有作用

 String INSTANCE = ELECTION_ROOT + "/instance";

leader選舉的分散式鎖 /leader/election/latch

String LATCH = ELECTION_ROOT + "/latch";

elastic-job-lite 既然去中心化,為何要選舉主節點

本作品採用《CC 協議》,轉載必須註明作者和本文連結
那小子阿偉

相關文章