天天看點

騰訊廣告商品中台流程編排引擎架構實作

作者:閃念基因

本文詳細介紹商品中台(ps:騰訊廣告商品中台負責全行業商品管理與維護,商品用于廣告投放等衆多應用場景)如何通過自建流程編排引擎實作各業務場景服務的三高處理,進而提高整體研發效率并保證系統穩定性。

01

商品中台流程編排引擎的使用場景

1.1 場景一:商品庫商品加工

商品庫管理近40億商品,日加工商品量級8000萬+,為衆多業務提供能力支援,加工流程通過流程編排引擎來管理實作,主要加工能力包括:類目識别、屬性識别、品牌識别、商品打标、商品了解、商品稽核、圖檔轉存、視訊轉存、創意生成等等。

1.2 場景二:商品稽核治理

商品稽核治理為商品交易各場景做商品稽核,包括:公共特征稽核、底線畫風稽核、低質畫風稽核、侵權稽核、違禁稽核等等近百個稽核單元組合(被編排節點),同時需要支援人審異步回調繼續進行稽核流程的複雜互動。

02

為什麼使用流程編排引擎

在我們實作的各業務場景中,多服務協同調用最終組裝成一個複雜的業務流程,是每個開發人員面臨的主要場景。在這些場景的實作過程中,我們會浪費大量精力在服務對接、調用順序和并行處理、逾時重試、服務雪崩處理機制、分布式一緻性等問題處理上。如果能通過某種手段,快速實作并解決如上問題,能大大提高我們的研發效率、降低系統的維護成本。我們隻需要集中精力于各個高内聚、低耦合的服務節點開發上。為此,流程編排引擎應運而生。

03

建構一個流程編排的過程

在控制台建構一個流程編排的過程非常簡單,僅僅需要簡單的配置即可實作一個流程編排。

建構流程編排有兩種方式,一是可視化拖拽編輯,二是使用工作流語言定義編排邏輯。

3.1 可視化拖拽編輯

在控制台上,可以通過可視化界面,拖拽各種節點(任務節點/流程控制節點)來組合成複雜的業務流程。目前流程編排引擎能夠編排的任務節點類型包括雲函數 SCF、kafka 生産者、http 接口。

以業務 A 為例,其流程編排包括圖檔轉存和商品稽核兩個任務節點,且業務流程是先圖檔轉存完成後再稽核,拖拽節點,組成如下圖所示的圖即可。

騰訊廣告商品中台流程編排引擎架構實作

3.2 代碼建立

使用代碼建構一個流程編排要用到工作流語言,工作流基于 DSL 語言,用來描述和定義工作流中的業務邏輯。 在執行時,ASW 工作流服務會根據工作流定義依次執行相關步驟。

舉個簡單例子來說明怎麼使用工作流語言建構一個流程編排,以業務 A 這一個流程編排為例,編寫如下代碼,其表達的含義與上面可視化節點拖拽表達的含義一樣。

{
  "Comment": "業務A",
  "StartAt": "Parallel",
  "States": {
    "Parallel": {
      "Type": "Parallel",
      "Next": "FinalState",
      "Branches": [
        {
          "StartAt": "ImageSave",
          "States": {
            "ImageSave": {
              "Type": "Task",
              "Comment": "圖檔轉存",
              "Resource":"resource位址,支援http協定、kafka協定、Serverless協定",
              "Next": "NewAudit"
            },
            "NewAudit": {
              "Type": "Task",
              "Comment": "稽核流程",
              "Resource": "resource位址,支援http協定、kafka協定、Serverless協定",
              "InputPath": "$.inputAswStr",
              "End": true
            }
          }
        }
      ]
    },
    "FinalState": {
      "Type": "Task",
      "Comment": "DAG結束節點",
      "Resource": "resource位址,支援http協定、kafka協定、Serverless協定",
      "End": true
    }
  }
}           

04

流程編排引擎的架構實作

騰訊廣告商品中台流程編排引擎架構實作

05

流程編排引擎的三高處理方案

5.1 高可用

流程編排引擎作為各業務場景依賴的核心元件,系統的可用性尤為重要。但由于各業務被編排的服務穩定性差異大,這也對流程編排引擎的異常處理提出了很高要求。為保證高可用性,商品庫流程編排引擎做了如下處理:實作任務配置設定的負載均衡政策、異常熔斷政策、服務隔離政策、接口重試機制、接口逾時處理、接口限流政策。下面分别做介紹。

5.1.1 負載均衡政策

排程器服務負責将新執行任務配置設定到不同執行器去執行 DAG 任務,這裡核心能力要實作任務的均衡配置設定,保證執行器的平穩運作。我們常見的負載均衡政策包括:

  • 輪詢(Round-Robin):按依次循環的方式将請求排程到不同的伺服器上,該算法最大的特點就是實作簡單。輪詢算法假設所有的伺服器處理請求的能力都一樣的,排程器會将所有的請求平均配置設定給每個真實伺服器。
  • 最小連接配接(Least-Connection):該算法中排程器需要記錄各個伺服器已建立連接配接的數目,通過伺服器目前活躍的連接配接數來估計伺服器的情況。當一個請求被排程到某台伺服器,其連接配接數加 1;當連接配接中斷或者逾時,其連接配接數減 1。該算法将請求配置設定給目前連接配接數最少的伺服器,確定負載相對均衡,适用于長連接配接的場景。
  • 哈希(Hash):将請求中的某些特征資料(例如 IP、MAC 或者更上層應用的某些資訊)作為特征值來計算需要落在的節點。雜湊演算法會保證同一個特征值每一次都會落在相同的伺服器上。
  • 随機均衡(Random):此種負載均衡算法類似于輪詢排程,不過在配置設定處理請求時是随機的過程。由機率論可以得知,随着用戶端調用服務端的次數增多,其實際效果趨近于平均配置設定請求到服務端的每一台伺服器,也就是達到輪詢的效果。
  • 權重輪詢(Weighted Round Robin):根據伺服器的權重值,按比例配置設定請求,權重高的伺服器接收到的請求數更多。

假設現在有三個執行器1、2、3,使用随機負載均衡随機将300個任務配置設定給三個執行器,很可能的情況是每個執行器執行100個任務,考慮一種極端情況,執行器1配置設定的任務恰好每個都需要很長時間,比如每次執行要幾分鐘,執行器2和3的每次執行都是隻需要幾秒,那麼執行器1上就會一直有運作中的任務,接下來配置設定新任務,執行器1其實就不應該配置設定任務了,但是由于随機均衡政策,三個執行器配置設定任務的機率還是一樣的,那麼就有問題了。

從以上分析可以看出,由于不同任務的耗時可能差别比較大,使用單純的随機均衡政策會有負載不均衡的問題。為了使得每個執行器的負載差不多,一個比較直覺的想法就是排程器每次選擇負載最小的執行器,負載最小其實可以了解為執行中的任務數量最小,那麼排程器發起請求的時候,怎麼知道哪一個執行器執行中的任務數量最小呢?

可以通過健康檢查,排程器每1秒向所有執行器發起健康檢查,檢查的目的有兩個:1、看看節點是不是挂了 2、檢視節點的負載。通過這種方式,排程器維護了執行器清單以及每個執行器的負載,發起調用的時候查詢這個路由表就可以。然而這有個問題,執行器負載不是實時的,而是通過一秒一次的健康檢查更新的,按照簡單的選負載最小的邏輯,假如很短時間内有100個任務,這時候會将所有的任務都打到同一個執行器上,又會造成不均衡了。

假設每個執行器的負載可以用百分數來表示,0%表示沒有負載,100%表示滿載,滿載的機器不能再接受請求,那麼直覺的思想是負載低的機器(剩餘承載能力越高的機器),配置設定任務的機率就大一點,假如機器負載是 a%,剩餘承載能力可以用100% - a%來表示。假設有三台執行器1、2、3,負載分别是 a%、b%、c%,那麼各個機器配置設定的機率分别是。

執行器 負載 剩餘承載能力 被選中的機率
1 a% 100% - a% (100% - a%) / [(100% - a%)+(100% - b%)+(100% - c%)] = (100 - a) / [(100 - a)+(100 - b)+(100 - c)]
2 b% 100% - b% (100% - b%) / [(100% - a%)+(100% - b%)+(100% - c%)] = (100 - b) / [(100 - a)+(100 - b)+(100 - c)]
3 c% 100% - c% (100% - c%) / [(100% - a%)+(100% - b%)+(100% - c%)] = (100 - c) / [(100 - a)+(100 - b)+(100 - c)]

一個執行器的負載怎麼用百分數來表示呢,可以指定一個滿載能力值,比如說執行器執行中的任務數量為300即是滿載,那麼執行器的負載計算公式就是:執行中的任務數量/300。到此,我們自己實作的負載均衡算法就介紹完了。

5.1.2 接口調用重試政策

流程編排引擎當中編排的各服務節點是通過網絡請求的方式來進行資訊交換和編排,但網絡存在不确定性,會造成請求抖動。對抖動場景接口調用重試的支援,可以有效解決由于短暫抖動造成的編排任務執行失敗的場景。通過流程編排引擎統一編排的服務,可以做到單點重試,也避免了重試風暴服務雪崩問題。(重試風暴可自行查閱相關材料)

對于網絡通信失敗處理會分為以下幾步:

  1. 感覺錯誤:通過不同的錯誤碼來識别不同的錯誤,目前流程編排引擎支援的是 Http 接口編排,在 HTTP 中 status code 可以用來識别不同類型的錯誤。
  2. 重試決策:這一步主要用來減少不必要的重試,比如 HTTP 的 4xx 的錯誤,通常 4xx 表示的是用戶端的錯誤,這時候用戶端不應該進行重試操作,或者在業務中自定義的一些錯誤也不應該被重試。根據這些規則的判斷可以有效的減少不必要的重試次數,提升響應速度。
  3. 重試政策:重試政策就包含了重試間隔時間,重試次數等。如果次數不夠,可能并不能有效的覆寫這個短時間故障的時間段,如果重試次數過多,或者重試間隔太小,又可能造成大量的資源(CPU、記憶體、線程、網絡)浪費。

如果重試之後還是不行,說明這個故障不是短時間的故障,而是長時間的故障。那麼可以對服務進行熔斷降級,後面的請求不再重試,這段時間做降級處理,減少沒必要的請求,等服務端恢複了之後再進行請求。

針對如上的重試場景,編排引擎通過 Retry 子產品,配置 ErrorEquals、IntervalSeconds、MaxAttempts、BackoffRate(每次嘗試重試時間間隔倍數)來支援接口重試政策的支援。配置示例如下:

{
  "Comment": "業務A",
  "StartAt": "unit_a",
  "States":
  {
    "unit_a":
    {
      "Type": "Task",
      "Comment": "稽核A單元",
      "Resource":"resource位址,支援http協定、kafka協定、Serverless協定",
"Retry": [
      {
        "ErrorEquals":["StatesTimeout"],
        "IntervalSeconds": 1,
        "MaxAttempts": 2,
        "BackoffRate": 2.0
      }
    ],
      "End": true
    }
  }
}           

5.1.3 限流和熔斷處理機制

微服務系統中,一個服務可能依賴另外一個服務,另外一個服務可能也依賴其他服務。這就是我們俗稱的微服務調用深度,下面用下圖展示:

騰訊廣告商品中台流程編排引擎架構實作
  • 當商品稽核服務出現故障,創意服務隻能被動地等待依賴服務報錯或者請求逾時,這會導緻:
  • a. 下遊連接配接池會被逐漸耗光;
  • b. 入口請求大量堆積,CPU、記憶體等資源被逐漸耗盡,最終導緻服務宕掉。
  • 上遊依賴創意服務的視訊轉存服務,也會因為相同的原因出現故障,一系列的級聯故障最終會導緻整個系統不可用;

這裡對微服務治理當中,每個服務子產品都需要引入限流和熔斷降級處理機制來避免叢集雪崩,那麼通過編排引擎實作服務編排同樣的場景會變成下面這樣。

騰訊廣告商品中台流程編排引擎架構實作

因為所有服務都統一通過編排引擎來進行編排,我們可以把調用深度了解為1。同樣當商品稽核服務出現故障,編排引擎隻能等待請求逾時,如果同樣大量請求在不斷請求,同樣會導緻商品網關、編排引擎、商品稽核的級聯故障。

解決雪崩級聯故障的核心思路就是:1、引入熔斷器及限流器,請求不超載且服務異常盡早失敗避免雪崩。2、通過消息隊列抽象出反壓層,當下遊服務有抖動可以做緩沖和反壓。這裡采用的後者。

騰訊廣告商品中台流程編排引擎架構實作

5.1.4 服務隔離政策

騰訊廣告商品中台流程編排引擎架構實作

通過一張圖基本羅列出來了常見的隔離政策,商品庫流程編排引擎基于不同業務的執行特點,按照熱點和使用者場景次元進行了叢集的獨立部署,實作真正的實體隔離。

5.2 高性能

高性能方面,引擎做了充分的壓測,核心對存儲引擎 IO 耗時、大對象資料結構、并發處理、依賴元件包使用方式等方面做了不斷優化和性能提升。優化細節不在本篇文章做詳細闡述。

5.3 可擴充

可擴充性方面,引擎在騰訊雲 TKE 上使用 docker 進行部署,且引擎本身無狀态,是以基于 TKE 平台的排程政策實作了基于資源壓力情況進行資源的動态擴縮容。

作者:裴博

來源-微信公衆号:騰訊雲開發者

出處:https://mp.weixin.qq.com/s/GFQ5BFMH7-L-HUfgSgokig

繼續閱讀