elastic-job中最關鍵的特性之一就是失效轉移。配置了失效轉移之后,如果在任務執行過程中有一個執行實例掛了,那么之前被分配到這個實例的任務(或者分片)會在下次任務執行之前被重新分配到其他正常節點實例上執行。
簡單的HA
當某一個任務實例節點宕機(離開與zookeeper的連接),會觸發elastic-job主節點的重新分片邏輯。elastic-job啟動任務節點以后生成的zookeeper中的instance節點是一個臨時節點EPHEMERAL。為什么要用EPHEMERAL節點,就是為了能在任務實例出現問題與zookeeper斷開以后,能觸發zookeeper的節點移除的事件,從而重新調整分區或者運行節點。既然是EPHEMERAL節點,就可以在zookeeper中配置sessionTimeoutMs參數。在使用spring的elastic-job配置中在如下地方配置:
如果在sessionTimeoutMs的時間段之內觸發任務,則異常分片的任務會丟失。舉個例子:假如sessionTimeoutMs被設置成1分鍾,而本身的任務是30秒執行一次,有三個任務實例在三台機器各自執行分片1,2,3。當分片3所在的機器出現問題,和zk斷開了,那么zk節點失效至少要到1分鍾以后。期間30秒執行一次的任務分片3,至少會少執行一次。1分鍾過后,zk節點失效,觸發ListenServersChangedJobListener類的dataChanged方法,在這里方法中判斷instance節點變化,然后通過方法shardingService.setReshardingFlag設置重新分片標志位,下次執行任務的時候,leader節點重新分配分片,分片3就會轉移到其他好的機器上。
復雜的失效轉移
elastic-job的任務配置有個failover,如果開啟設置為true的時候,會啟動真正的失效轉移:,elastic-job的任務又兩個配置failover(默認值為false)和monitorExecution(默認值是true)。只有對monitorExecution為true的情況下才可以開啟失效轉移。
所謂失效轉移,就是在執行任務的過程中遇見異常的情況,這個分片任務可以在其他節點再次執行。這個和上面的HA不同,對於HA,上面如果任務終止,那么不會在其他任務實例上再次重新執行。
Job的失效轉移監聽來源於FailoverListenerManager中JobCrashedJobListener的dataChanged方法。FailoverListenerManager監聽的是zk的instance節點刪除事件。如果任務配置了failover等於true,其中某個instance與zk失去聯系或被刪除,並且失效的節點又不是本身,就會觸發失效轉移邏輯。
首先,在某個任務實例失效時,elastic-job會在leader節點下面創建failover節點以及items節點。items節點下會有失效任務實例的原本應該做的分片好。比如,失效的任務實例原來負責分片1和2。那么items節點下就會有名字叫1的子節點,就代表分片1需要轉移到其他節點上去運行。如下圖:
然后,由於每個存活着的任務實例都會收到zk節點丟失的事件,哪個分片失效也已經在leader節點的failover子節點下。所以這些或者的任務實例就會爭搶這個分片任務來執行。為了保證不重復執行,elastic-job使用了curator的LeaderLatch類來進行選舉執行。在獲得執行權后,就會在sharding節點的分片上添加failover節點,並寫上任務實例,表示這個故障任務遷移到某一個任務實例上去完成。如下圖中的sharding節點上的分片1:
執行完成后,會把相應的節點和數據刪除,避免下一次重復執行。





