當前位置: 妍妍網 > 碼農

京東商城高效能多執行緒並行編程與動態編排框架

2024-06-07碼農

一、計畫介紹

Gobrs-Async 是一款功能強大、配置靈活、帶有全鏈路異常回呼、記憶體最佳化、異常狀態管理於一身的高效能多執行緒並行編程和動態編排框架。為企業提供在復雜套用場景下動態任務編排的能力。針對於復雜場景下,異步執行緒復雜性、任務依賴性、異常狀態難控制性;

二、解決什麽問題

在開發復雜中台業務過程中,難免會遇到呼叫各種中台業務數據, 而且會出現復雜的中台數據依賴關系,在這種情況下。程式碼的復雜程度就會增加。如下圖所示:

在請求呼叫各大中台數據時,難免會出現多個中台數據互相依賴的情況,現實開發中會遇到如下場景。

並列常見的場景 1 客戶端請求伺服端介面,該介面需要呼叫其他N個微服務的介面

譬如 請求我的購物車,那麽就需要去呼叫使用者的rpc、商品詳情的rpc、庫存rpc、優惠券等等好多個服務。同時,這些服務還有相互依賴關系,譬如必須先拿到商品id後,才能去庫存rpc服務請求庫存資訊。最終全部獲取完畢後,或超時了,就匯總結果,返回給客戶端。

2 並列執行N個任務,後續根據這1-N個任務的執行結果來決定是否繼續執行下一個任務,如使用者可以透過信箱、手機號、使用者名稱登入,登入介面只有一個,那麽當使用者發起登入請求後,我們需要並列根據信箱、手機號、使用者名稱來同時查資料庫,只要有一個成功了,都算成功,就可以繼續執行下一步。而不是先試信箱能否成功、再試手機號。

再如某介面限制了每個批次的傳參數量,每次最多查詢10個商品的資訊,我有45個商品需要查詢,就可以分5堆並列去查詢,後續就是統計這5堆的查詢結果。就看你是否強制要求全部查成功,還是不管有幾堆查成功都給客戶做返回

再如某個介面,有5個前置任務需要處理。其中有3個是必須要執行完畢才能執行後續的,另外2個是非強制的,只要這3個執行完就可以進行下一步,到時另外2個如果成功了就有值,如果還沒執行完,就是預設值。

3 需要進行執行緒隔離的多批次任務。

如多組任務, 各組任務之間彼此不相關,每組都需要一個獨立的執行緒池,每組都是獨立的一套執行單元的組合。有點類似於hystrix的執行緒池隔離策略。

4 單機工作流任務編排。

5 其他有順序編排的需求。

三、核心能力

四、框架設計

Gobrs-Async 在設計時,就充分考慮了開發者的使用習慣, 沒有依賴任何中介軟體。對並行框架做了良好的封裝。主要使用 CountDownLatch ReentrantLock volatile 等一系列並行技術開發設計。

任務觸發器

任務流的啟動者, 負責啟動任務執行流

任務觸發器

負責解析使用者配置的規則,同時於Spring結合,將配置的 Spring Bean 解析成 TaskBean,進而透過解析引擎載入成 任務裝飾器。進而組裝成任務樹

任務啟動器

負責透過使用解析引擎解析的任務樹。結合 JUC 並行框架排程實作對任務的統一管理,核心方法有

  • trigger 觸發任務載入器,為載入任務準備環境

  • 任務載入器

    負責載入任務流程,開始呼叫任務執行器執行核心流程

  • load 核心任務流程方法,在這裏阻塞等待整個任務流程

  • getBeginProcess 獲取子任務開始流程

  • completed 任務完成

  • errorInterrupted 任務失敗 中斷任務流程

  • error 任務失敗

  • 任務執行器

    最終的任務執行,每一個任務對應一個 TaskActuator 任務的 攔截、異常、執行、執行緒復用 等必要條件判斷都在這裏處理

  • prepare 任務前置處理

  • preInterceptor 統一任務前置處理

  • task 核心任務方法,業務執行內容

  • postInterceptor 統一後置處理

  • onSuccess 任務執行成功回呼

  • onFail 任務執行失敗回呼

  • 任務匯流排

    任務流程傳遞匯流排,包括 請求參數、任務載入器、 響應結果, 該物件暴露給使用者,拿到匹配業務的數據資訊,例如:返回結果、主動中斷任務流程等功能 需要任務匯流排(TaskSupport)支持

    核心類圖

    五、落地場景

    目前 Gobrs-Async 已經在京東商城商詳團隊落地使用,經受嚴酷的並行考驗。對各種中台呼叫應對自如

    透過 Gobrs-Async 管理中台介面請求 耗時任務請求 請求依賴關系等核心場景。充分利用CPU資源

    六、規則範例

    場景一

    如圖1-1

    說明 任務A 執行完了之後,繼續執行 B、C、D

    配置

    gobrs:
    async:
    rules:
    - name: "ruleName1"
    content: "A->B,C,D"

    場景二

    如圖1-2

    說明 任務A 執行完了之後執行B 然後再執行 C、D

    配置

    gobrs:
    async:
    rules:
    - name: "ruleName1"
    content: "A->B->C,D"

    場景三

    如圖1-3

    說明 任務A 執行完了之後執行B、E 然後按照順序 B的流程走C、D、G。E的流程走F、G

    配置

    gobrs:
    async:
    rules:
    - name: "ruleName1"
    content: "A->B->C->D->G;A->E->F->G"

    場景四

    如圖1-4

    說明 這種任務流程 Gobrs-Async 也能輕松支持

    配置

    gobrs:
    async:
    rules:
    - name: "ruleName1"
    content: "A->B->C,D,E;A->H->I,J,K"

    場景五

    如圖1-5

    範例一

    說明 A、B、C 執行完之後再執行D

    配置

    gobrs:
    async:
    rules:
    - name: "ruleName1"
    content: "A,B,C->D"

    範例二

    說明 A、B、C 任務任意一個執行完成,則立即執行任務D( 誰最快執行誰執行, 類似於任務流程競爭關系 ) 此時可以使用 配置關鍵字 :any

    配置

    gobrs:
    async:
    ## :any 是關鍵字 表示任意 依賴的任務執行完成立即執行自己
    rules:
    - name: "ruleName1"
    content: "A,B,C->D:any"

    範例三

    說明 A、B、C 任務任意一個執行完成,則立即執行任務D( 誰最快執行誰執行, 類似於任務流程競爭關系 ) 與範例不同的是, 如果 D拿到執行權後,會將自身所依賴的未完成的任務 強制中斷執行(避免浪費資源,業務執行等) 此時可以使用 配置關鍵字 :exclusive

    配置

    gobrs:
    async:
    ## :exclusive 是關鍵字
    rules:
    - name: "ruleName1"
    content: "A,B,C->D:any:exclusive"

    範例四

    同範例二有點類似,在範例二的場景下,無法根據某一個任務的執行成功或者失敗進行後續任務的處理,範例二完全根據執行緒排程執行的隨機順序進行執行,即誰先執行完 誰有資格繼續往下執行,所以如果想 執行結果的條件 即: task 方法返回 true 則立即執行,返回false則不執行的判斷條件進行控制。那麽就有以下的實作方式。

    原始碼下載地址:

    https://gitee.com/dromara/gobrs-async.git

    看到最後,如果這個計畫對你有用,一定要給我點個「 在看和贊 」。