1.背景
assetbatch升級3.0版本後,發現有個窗口任務(上下午窗口),未能執行成功,甚至存在未執行的情況。如下所示,一直處於初始狀態,且系統未出現任何報錯。
窗口任務一:
窗口任務二:
/** 初始 */
INIT("I", "INIT", "初始", "初始"),
/** 處理 */
PROCESS("P", "PROCESS", "處理", "處理"),
/** 成功 */
SUCCESS("S", "SUCCESS", "成功", "成功"), ;
2.排查思路
2.1 調度任務是否開啟了?
是。通過branchJob表的狀態來看,子任務已經處於init狀態,說明是被調度任務激活了的。為了確認問題還是check了下DSS配置,確認正常。
2.2 任務初始化後,分支任務是否擴散了?
是。任務被初始化後,後續會被激活,之後進行任務擴散,查看機器日誌,任務確實開始擴散了。
2.3 client是否收到了擴散任務?
沒有。分支任務顯示開始擴散(rpc),但是在client機器上未檢索到server端發送的信息。回到代碼層面,可以發現,在兩次分發過程中,使用了隔離的線程池,查閱系分後得知,assetbatch3.0版本對子任務線程池、業務線程池進行了隔離,由於系統配置還是保持的1.0版本的配置,導致子任務線程池使用了默認值。初步懷疑是線程池這裡出了問題。
String jobDatacenter, String jobWorkspace, String spanTaskName,
String triggerDatacenter, String triggerWorkspace, String zoneInfo) {
DispatchRequest dispatchRequest = new DispatchRequest(tntInstId, taskId, branchId,
taskName, jobDatacenter, jobWorkspace, spanTaskName, triggerDatacenter,
triggerWorkspace, zoneInfo);
BatchLogger.infoLogger("分支任務開始擴散", tntInstId, taskId, branchId, taskName,
triggerDatacenter, triggerWorkspace, zoneInfo);
// rpc調用
batchDispatchClient.dispatch(dispatchRequest);
}
public void dispatch(final DispatchRequest request) {
try {
// 第一次分發
if (request.getLevel() == DispatchRequest.LEVEL_1) {
batchThreadPoolManager.getBranchJobExecutor().execute(
() -> spreadBranchJob(request)
);
} else {
// 第二次分發
String[] objects = request.getRequestObject().split("##");
for (String object : objects) {
final DispatchRequest realRequest = copyRequestAndReplace(request, object);
batchThreadPoolManager.getBizProcessExecutor().execute(
() -> spreadBiz(realRequest)
);
}
}
} catch (Exception e) {
BatchLogger.errorLogger("任務受理時,threadPoolTaskExecutor線程池運行異常", e);
}
}
public class BatchThreadConfig extends BaseToString implements Serializable {
private static final long serialVersionUID = 3787869583656441968L;
/** 子任務線程池,核心線程數: default=10 */
private int branchJobCorePoolSize = 10;
/** 子任務線程池,最大線程數: default=100 */
private int branchJobMaxPoolSize = 100;
/** 子任務線程池,idle線程的keepAlive時間: default=60s */
private int branchJobKeepAliveSeconds = 60;
/** 子任務線程池,緩衝隊列容量: default=100 */
private int branchJobQueueCapacity = 10000;
/** 業務處理線程池,核心線程池個數: default=10 */
private int corePoolSize = 10;
/** 業務處理線程池,最大線程池個數: default=100 */
private int maxPoolSize = 100;
/** 業務處理線程池,idle線程的keepAlive時間: default=60s */
private int keepAliveSeconds = 60;
/** 業務處理線程池,緩衝隊列容量: default=100 */
private int queueCapacity = 10000;
/** 是否子任務線程池與業務線程池共享 Default=false*/
private String share = "false";
3.簡要分析
初步懷疑是新版本線程池做了隔離導致的任務被阻塞。首先分析下當前系統中的所有任務,列表如下:
系統中存在4個永久任務,每個任務均有20個分片(子任務),每臺機器默認核心線程數10個,集群中共有10臺機器,總計核心線程數=10 * 10 = 100個。
永久任務,一旦執行起來,會長時間佔有線程,直到分支任務執行完成。但是Task004任務有點特殊,每30min驅動一次,30min的時間裡,Task004獨佔子任務線程。4個永久任務佔據了80個線程,剩餘20個線程。上午模式-Task007和上午模式-Task005在窗口期,有部分時間交集,40個branch job搶佔20個線程資源,故出現了背景所描述的現象。
4.解決方案
應急方案,將其中優先級較低的永久任務先暫停掉,後續新增branch job的線程池配置。不得不吐槽下:
1、assetbatch升級3.0版本後,線程池隔離,升級過程中,不看框架的系分、接入文檔容易採坑,為何不默認共享?
2、任務的暫停框架僅暫停一個,需要在load、process附加開關控制;
3、任務激活過程中,被暫停的任務依然被撈取,太不友好了;
4、最關鍵的,沒發現框架中有對線程池的監控,不利於線上運維;