源碼分析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)