開發與維運

批處理框架問題排查記錄

1.背景

assetbatch升級3.0版本後,發現有個窗口任務(上下午窗口),未能執行成功,甚至存在未執行的情況。如下所示,一直處於初始狀態,且系統未出現任何報錯。
窗口任務一:1.png
窗口任務二:2.png

    /** 初始 */
    INIT("I", "INIT", "初始", "初始"),
    /** 處理 */
    PROCESS("P", "PROCESS", "處理", "處理"),
    /** 成功 */
    SUCCESS("S", "SUCCESS", "成功", "成功"), ;

2.排查思路

2.1 調度任務是否開啟了?
是。通過branchJob表的狀態來看,子任務已經處於init狀態,說明是被調度任務激活了的。為了確認問題還是check了下DSS配置,確認正常。

2.2 任務初始化後,分支任務是否擴散了?
是。任務被初始化後,後續會被激活,之後進行任務擴散,查看機器日誌,任務確實開始擴散了。
3.png

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.簡要分析
初步懷疑是新版本線程池做了隔離導致的任務被阻塞。首先分析下當前系統中的所有任務,列表如下:
1.png
系統中存在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、最關鍵的,沒發現框架中有對線程池的監控,不利於線上運維;

5.參考

批量任務3.0接入指引
批量任務3.0系分

Leave a Reply

Your email address will not be published. Required fields are marked *