廣告平臺化的探索與實踐 | 美團外賣廣告工程實踐專題連載

隨着美團外賣業務不斷髮展,外賣廣告引擎團隊在多個領域進行了工程上的探索和實踐,目前已經取得了一些成果。我們計劃通過連載的形式分享給大家,本文是《美團外賣廣告工程實踐》專題連載的第一篇。本文針對業務提效的目標,介紹了美團外賣廣告引擎在平臺化過程中的一些思考和實踐。

1 前言

美團外賣已經成爲公司最爲重要的業務之一,而商業變現又是整個外賣生態重要的組成部分。經過多年的發展,廣告業務覆蓋了Feed流形式的列表廣告,針對KA以及大商家的展示廣告,根據用戶查詢Query的搜索廣告,以及一些創新場景的創新廣告等多個產品線,並對應十幾個細分的業務場景。

從技術層面而言,一次廣告請求的過程,可以分爲以下幾個主要步驟:廣告的觸發、召回、精排、創意優選、機制策略等過程。如下圖所示:即通過觸發得到用戶的意圖,再通過召回得到廣告候選集,通過預估對候選集的店鋪打分、排序,再對於Top的店鋪再進行創意的選擇,最後經過一些機制策略得到廣告結果。

2 現狀分析

在業務迭代的過程中,隨着新業務場景的不斷接入,以及原有業務場景功能的不斷迭代,系統變得越來越複雜,業務迭代的需求響應逐漸變慢。在業務發展前期,開展過單個模塊的架構重構,如機制策略、召回服務,雖然對於效率提升有一定的改善,但是還會存在以下一些問題:

  1. 業務邏輯複用度低:廣告業務邏輯比較複雜,比如機制服務模塊,它主要功能是爲廣告的控制中樞以及廣告的出價和排序的機制提供決策,線上支持十幾個業務場景,每種場景都存在很多差異,比如會涉及多種召回、計費模式、排序方案、出價機制、預算控制等等。此外,還有大量業務自定義的邏輯,由於相關邏輯是算法和業務迭代的重點,因此開發人員較多,並且分佈在不同的工程和策略組內,導致業務邏輯抽象粒度標準不夠統一,使得不同場景不同業務之間複用程度較低。
  2. 學習成本高:由於代碼複雜,新同學熟悉代碼成本較高,上手較難。此外,線上服務很早就進行了微服務改造,線上模塊數量超過20個,由於歷史原因,導致多個不同模塊使用的框架差異較大,不同模塊之間的開發有一定的學習成本。在跨模塊的項目開發中,一位同學很難獨立完成,這使得人員效率沒有得到充分利用。
  3. PM(產品經理)信息獲取難:由於目前業務場景較多、邏輯複雜,對於信息的獲取,絕大多數同學很難了解業務的所有邏輯。PM在產品設計階段需要確認相關邏輯時,只能讓研發同學先查看代碼,再進行邏輯的確認,信息獲取較難。此外,由於PM對相關模塊的設計邏輯不清楚,往往還需要通過找研發人員線下進行詢問,影響雙方的工作效率。
  4. QA(測試)評估難:QA在功能範圍評估時,完全依賴於研發同學的技術方案,且大多數也是通過溝通來確認功能改動涉及的範圍和邊界,在影響效率的同時,還很容易出現“漏測”的問題。

3 目標

針對以上的問題,我們從2020年初,啓動美團外賣廣告引擎平臺化項目,旨在通過平臺化的項目達成以下目標。

  1. 提升產研效率

    • 高功能複用度,提升開發效率。
    • 降低研發人員(RD)、PM、QA之間的協作成本,提升產研協作的效率。
  2. 提升交付質量

    • 精確QA測試的範圍,提升交付的質量。
    • 對業務進行賦能。
  3. PM可通過可視化的平臺化頁面,瞭解其他產品線的能力,互相賦能,助力產品迭代。

4 整體設計

4.1 整體思想

目前,業界已經有不少“平臺化”方向的研究,比如阿里巴巴的TMF,定位於泛交易類系統的平臺化領域範疇,主要建設思想是,流程編排與領域擴展分層,業務包與平臺分離的插件化架構,管理域與運行域分離。而阿里巴巴的AIOS則定位於搜推平臺化領域範疇,主要依賴於底層5大核心組件,以算子流程圖定製的模式對組件快速組合與部署,從而實現了業務的快速交付。

美團外賣在平臺化項目啓動時,從業務場景和業務痛點出發,確定了我們項目的核心目標:利用平臺化設計理念構建相適應的技術能力,將現有外賣廣告的業務系統和產研流程轉變爲平臺化模式,快速支持外賣廣告多業務進行交付。我們借鑑了行業內平臺化的成熟思想,確定了以業務能力標準化爲基礎、構建平臺化框架技術能力爲支撐、產研平臺化模式升級爲保障的平臺化建設整體思想,整體思想可分爲三部分:業務能力標準化、技術能力框架化、平臺化產研新流程。

  • 業務能力標準化:通過對現有邏輯的梳理,進行標準化的改造,爲多業務場景、多模塊代碼複用提供基礎保證。
  • 技術能力框架化:提供組合編排能力將標準化的邏輯串聯起來,通過引擎調度執行,同時完成了可視化能力的透出,幫助用戶快速獲取信息。
  • 平臺化產研新流程:爲保證項目上線之後實現研發迭代的整體提效,我們對於研發流程的一些機制也進行了一些優化,主要涉及研發人員、PM、QA三方。

即通過標準化提供複用的保證,通過框架承載平臺化落地的能力,通過產研新流程的運行機制保證了整體提效的持續性。整個廣告引擎服務涉及到的模塊都遵循了平臺化的思想,支撐上游各個產品場景,如下圖所示:

4.2 業務標準化

4.2.1 業務場景與流程分析

提效是平臺化最重要的目標之一,而提效最重要的手段是讓功能在系統中得到最大程度上的複用。我們首先針對外賣廣告業務線場景和流量的現狀做了統一的分析,得出以下兩點結論:

第一,各業務線大的流程基本類似,都包括預處理、召回、預估、機制策略、排序、創意、結果組裝等幾個大的步驟;同時,不同業務相同的步驟裏會有很多相似的功能和業務線特有的功能。第二,這些功能理論上都是可以整體進行復用的,但現狀是這些功能都集中在業務線內部,不同的業務線之間,不同的小組之間的複用狀況也不盡相同。而造成這一問題的主要原因是:

  • 不同業務處在不同的發展階段,也有着不同的迭代節奏。
  • 組織結構天然存在“隔離”,如推薦和搜索業務分在兩個不同的業務小組。

因此,阻礙外賣廣告進一步提升複用程度的主要原因,在於整體的標準化程度不足,各業務線間沒有統一的標準,所以我們要先解決標準化建設的問題。

4.2.2 標準化建設

標準化建設的廣度和深度決定了系統複用能力的高低。因此,本次標準化的建設目標要覆蓋到所有方面。我們對廣告系統所有的服務,從業務開發的三個維度,包括實現的功能、功能使用的數據、功能組合的流程出發,來進行統一廣告的標準化建設。從而使得:

  • 在個體開發層面:開發同學不用關注如何流程調度,只需將重心放在新功能的實現上,開發效率變得更高。
  • 從系統整體角度:各個服務對於通用的功能不用再重複開發,整體的複用程度更高,節省了大量的開發時間。

4.2.2.1 功能的標準化

針對功能的標準化問題,我們首先依據功能是否跟業務邏輯相關,將其劃分爲兩部分:業務邏輯相關和業務邏輯無關。

① 與業務邏輯無關的功能通過雙層抽象來統一共建

  • 所有業務線統一共建的標準化形式是進行雙層抽象。對於單個的、簡單的功能點,抽象爲工具層;對於可獨立實現並部署的某一方面功能,比如創意能力,抽象爲組件層。工具層和組件層統一以JAR包的形式對外提供服務,所有工程都通過引用統一的JAR包來使用相關的功能,避免重複的建設,如下圖所示:

② 與業務邏輯有關的功能,在複用範圍上進行分層複用

  • 業務邏輯相關的功能是此次標準化建設的核心,目標是做到最大程度的業務複用。因此,我們將最小不可拆分的業務邏輯單元抽象爲業務同學開發的基本單位,稱爲Action。同時根據Action不同的複用範圍,將其劃分爲三層,分別是所有業務可以複用的基礎Action,多業務線複用的模塊Action,具體單一業務定製的業務Action,亦即擴展點。所有的Action都是從Base Action派生出來的,Base Action裏定義了所有Action統一的基礎能力。
  • 不同的Action類型分別由不同類型的開發同學來開發。對於影響範圍比較大的基礎Action和模塊Action,由工程經驗豐富的同學來開發;對於僅影響單個業務的業務Action或擴展點,由工程能力相對薄弱的同學來進行開發。
  • 同時我們把多個Action的組合,抽象爲Stage,它是不同Action組合形成的業務模塊,目的在於屏蔽細節,簡化業務邏輯流程圖的複雜度,並提供更粗粒度的複用能力。

4.2.2.2 數據的標準化

數據作爲實現功能的基本元素,不同業務的數據來源大同小異。如果不對數據進行標準化設計,就無法實現功能標準化的落地,也無法實現數據層面的最大化複用。我們從數據來源和數據使用方式兩方面來劃分數據:對於業務能力的輸入數據、中間數據,輸出數據,通過標準化的數據上下文來實現;同時對於第三方外部數據及詞表等內部數據,通過統一的容器存儲和接口獲取。

① 使用上下文Context描述Action執行的環境依賴

  • 每個Action執行都需要一定的環境依賴,這些依賴包括輸入依賴、配置依賴、環境參數、對其他Action的執行狀態的依賴等。我們將前三類依賴都抽象到業務執行上下文中,通過定義統一的格式和使用方式來約束Action的使用。
  • 考慮不同層級Action對於數據依賴使用範圍由大到小,遵循相同的分層設計,我們設計了三層依次繼承的Context容器,並將三類依賴的數據標準化存儲到相應的Context中。
  • 使用標準化Context進行數據傳遞,優勢在於Action可自定義獲取輸入數據,以及後續擴展的便利性;同時標準化的Context也存在一定的劣勢,它無法從機制上完全限制Action的數據訪問權限,隨着後續迭代也可能導致Context日漸臃腫。綜合考慮利弊後,現階段我們仍然採用標準的Context的模式。

② 第三方外部數據的統一處理

  • 對於第三方的外部數據的使用,需要成熟的工程經驗提前評估調用量、負載、性能、批量或拆包等因素,所以針對所有第三方外部數據,我們統一封裝爲基礎Action,再由業務根據情況定製化使用。

③ 詞表數據的全生命週期管理

  • 詞表根據業務規則或策略生成,需要加載到內存中使用的KV類數據,標準化之前的詞表數據在生成、拉取、加載、內存優化、回滾、降級等能力上有不同程度的缺失。因此,我們設計了一套基於消息通知的詞表管理框架,實現了詞表的版本管理、定製加載、定時清理、流程監控的全生命週期覆蓋,並定義了業務標準化的接入方式。

4.2.2.3 調用流程的標準化

最後,將功能和數據進行組合的是業務的調用流程,統一的流程設計模式是業務功能複用和提效的核心手段。流程設計統一的最佳方式就是標準化業務流程。其中對於第三方接口的調用方式,讓框架研發的同學用集中封裝的方式進行統一。對於接口的調用時機,則基於性能優先併兼顧負載,且在沒有重複調用出現的原則下,進行標準化。

在具體實踐中,我們首先梳理業務邏輯所使用到的標準化功能,然後分析這些功能之間的依賴關係,最後以性能優先併兼顧負載、無重複調用等原則,完成整個業務邏輯流程的標準設計。

從橫向維度看,通過比較不同業務邏輯流程的相似性,我們也提煉了一定的實踐經驗,以中控模塊爲例:

  1. 對於用戶維度的第三方數據,統一在初始化後進行封裝調用。
  2. 對於商家維度的第三方數據,有批量接口使用的數據,在召回後統一封裝調用;無批量接口使用的數據,在精排截斷後統一封裝調用。

4.3 技術框架

4.3.1 整體框架介紹

平臺主要有兩個部分組成,一部分是平臺前臺部分,另一部分是平臺開發框架包。其中前臺部分是一個給研發人員、PM以及QA三種角色使用的Web前臺,主要功能是跟集成了平臺開發框架包的引擎服務進行可視化的交互,我們也給這個平臺起了個名字,叫Camp平臺,這是大本營的意思,寓意助力業務方攀登業務高峯。平臺開發框架包被引擎後臺服務所集成,提供引擎調度隔離、能力沉澱、信息上報等功能,同時還能確保各個模塊保持同樣標準的框架和業務能力風格。

各個在線服務都需要引入平臺開發框架包,服務性能與平臺通用性之間如何平衡也是我們需要着重考慮的地方。這是因爲,引入平臺框架會對原有的代碼細節進行增強性擴展;在C端大流量場景下,平臺框架做得越通用,底層功能做得越豐富,與單純的“裸寫”代碼相比,會帶來一些性能上的折損。因此,在性能開銷與平臺抽象能力上,需要儘量做到一個折中。我們結合自身業務的特性,給出的安全閾值是TP999損失在5ms以內,將各個業務通用的能力下沉至框架,提供給上層的在線服務。

綜上,整個系統架構設計如下:

① Camp平臺提供管理控制和展示的功能,該平臺由以下幾個子模塊包組成:

  • 業務可視化包,提供各個後臺系統上的能力的靜態信息,包括名稱、功能描述、配置信息等,這些信息在需求評估階段、業務開發階段都會被用到。
  • 全圖化編排和下發包,業務開發同學通過對已有的能力進行可視化的拖拽,通過全圖化服務自動生成並行化最優的執行流程,再根據具體業務場景進行調整,最終生成一個有向無環圖,圖的節點代表業務能力,邊表示業務能力之間的依賴關係。該圖會動態下發到對應的後臺服務去供執行框架解析執行。
  • 統計監控包,提供業務能力、詞典等運行期間的統計和異常信息,用於查看各個業務能力的性能情況以及異常情況,達到對各個業務能力運行狀態可感知的目的。

② 平臺開發框架包被廣告引擎的多個服務引入,執行編排好的業務流程並對外提供服務,平臺框架開發包由以下幾個子模塊包組成:

  • 核心包,提供兩個功能,第一個是調度功能,執行平臺下發的流程編排文件,按照定義的DAG執行順序和執行條件去依次或並行執行各個業務能力,並提供必要的隔離和可靠的性能保證,同時監控運行以及異常情況進行上報。第二個是業務採集和上報功能,掃描和採集系統內的業務能力,並上報至平臺Web服務,供業務編排以及業務能力可視化透出使用。
  • 能力包,業務能力的集合,這裏的業務能力在前面章節“4.2.2.1 功能的標準化”中已給出定義,即“將最小不可拆分的業務邏輯單元,抽象爲業務同學開發的基本單位,稱爲Action,也叫能力”。
  • 組件包,即業務組件的集合,這裏的業務組件在章節“4.2.2.1 功能的標準化”中也給出定義,即“對於可獨立實現並部署的某一方面功能,比如創意能力,抽象爲組件”。
  • 工具包,提供業務能力需要的基礎功能,例如引擎常用的詞典工具、實驗工具以及動態降級等工具。這裏的工具在章節“4.2.2.1功能的標準化”中同樣給出了定義,即單個的、簡單的非業務功能模塊抽象爲工具。

一個典型的開發流程如上圖所示 ,開發人員開發完業務能力後(1),業務能力的靜態信息會被採集到Camp平臺(2),同時,經過全圖化依賴推導得到最優DAG圖(3),業務同學再根據實際業務情況對DAG圖進行調整,引擎在線服務運行期間會得到最新的DAG流程並對外提供最新的業務流程服務(4,5),同時會把業務運行的動態信息上報至Camp平臺(6)。

在下面的章節中,我們將對幾個比較關鍵的技術點進行詳細描述,其中就包括了可視化相關的組件自動上報和DAG執行相關的全圖化編排、執行調度等,最後,本文還會介紹一下跟廣告業務強相關的、詞典在平臺化中統一封裝的工作。

4.3.2 業務採集&上報

爲了方便管理和查詢已有業務能力,平臺開發框架包會在編譯時掃描@LppAbility註解和@LppExtension註解來上報元數據到Camp平臺。業務同學可以在Camp平臺中對已有組件進行查詢和可視化的拖拽。

//原子能力(Action)
@LppAbility(name = "POI、Plan、Unit數據聚合平鋪能力", desc = "做預算過濾之前,需要把對象打平",
        param = "AdFlatAction.Param", response = "List<KvPoiInfoWrapper>", prd = "無產品需求", func = "POI、Plan、Unit數據聚合平鋪能力", cost = 1)
public abstract class AdFlatAction extends AbstractNotForceExecuteBaseAction {

}
//擴展點
@LppExtension(name = "數據聚合平鋪擴展點",
        func = "POI、Plan、Unit數據聚合平鋪", diff = "默認的擴展點,各業務線直接無差異", prd = "無", cost = 3)
public class FlatAction extends AdFlatAction {
@Override
    protected Object process(AdFlatAction.Param param) {
    //do something
      return new Object();
    }
}

4.3.3 全圖化編排

在廣告投放引擎服務中,每個業務的DAG圖,動輒便會有幾十甚至上百的Action,通過傳統的人工編排或業務驅動編排,很難做到Action編排的最優並行化。因此,平臺化框架包採用數據驅動的思想,通過Action之間的數據依賴關係,由程序自動推導出並行化最優的DAG圖,即全圖化編排,此後再由業務人員根據業務場景和流量場景進行定製化調整,動態下發到服務節點,交由調度引擎執行,這樣通過自動推導+場景調優的方式便達到了場景下的最優並行。

① 全圖化自動編排的基本原理

我們定義某個Action x的入參集合爲該Action x執行時使用的字段,表示如下:

$input_x(A,B,C......N)$

定義某個Action y的出參集合爲該Action執行後產出的字段,表示如下:

$output_y(A,B,C......M)$

當存在任意以下兩種情況之一時,我們會認爲Action x依賴於Action y。

  • input_x ∩ output_y ≠ ∅,即Action x的某個/某些入參是由Action y產出。
  • output_x ∩ output_y ≠ ∅,即Action x與Action y操作相同字段。

② 全圖化自動編排總設計

全圖化自動編排總體分爲兩個模塊:解析模塊、依賴分析模塊。

  • 解析模塊:通過對字節碼分析,解析出每個Action的input、output集合。
    • 字節碼分析使用了開源工具ASM,通過模擬Java運行時棧,維護Java運行時局部變量表,解析出每個Action執行依賴的字段和產出的字段。
  • 依賴分析模塊:採用三色標記的逆向解析法,分析出Action之間的依賴關係,並對生成的圖進行剪枝操作。
    • 依賴剪枝:生成圖會有重複依賴的情況,爲了減少圖複雜度,在不改變圖語義的前提下,對圖進行了依賴剪枝。例如:

③ 全圖化自動編排收益效果

自動糾正人工錯誤編排,並最大化編排並行度。某實際業務場景中,全圖化前後的DAG對比,如下圖所示:

標記藍色的兩個Action,會同時操作同一個Map,如果併發執行會有線程安全風險。由於方法調用棧過深,業務開發同學很難關注到該問題,導致錯誤的並行化編排。經過全圖化分析後,編排爲串行執行。

標記綠色、紅色、黃色的三組Action,每組內的兩個Action並沒有數據依賴關係,業務開發同學串行化編排。經過全圖化分析後,編排爲並行。

4.3.4 調度引擎

調度引擎的核心功能是對上述下發後的DAG進行調度。因此引擎需要具備以下兩個功能:

  • 構圖:根據Action的編排配置生成具體的DAG模板圖。
  • 調度:流量請求時,按照正確的依賴關係執行Action。

整個調度引擎的工作原理如下圖:

出於對性能的考慮,調度引擎摒棄了流量請求實時構圖的方法,而是採用“靜態構圖+動態調度”的方式。

  • 靜態構圖:在服務啓動時,調度引擎根據下發的DAG編排配置,初始化爲Graph模板並加載至內存。服務啓動後,多個DAG的模板會持久化到內存中。當Web平臺進行圖的動態下發後,引擎會對最新的圖進行構圖並完全熱替換。
  • 動態調度:當流量請求時,業務方指定對應的DAG,連同上下文信息統一交至調度引擎;引擎按照Graph模板執行,完成圖及節點的調度,並記錄下整個調度的過程。

由於廣告投放引擎服務於C端用戶,對服務的性能、可用性、擴展性要求很高。調度引擎的設計難點也落在了這三個方面,接下來我們將進行簡要的闡述。

4.3.4.1 高性能實踐

流程引擎服務於C端服務,與傳統的硬編碼調度相比,引擎的調度性能要至少能持平或在一個可接受的性能損失閾值內。下面,我們將從調度器設計、調度線程調優這兩個有代表性的方面介紹下我們的性能實踐。

① 調度器設計

含義:如何讓節點一個一個的執行;一個節點執行完成,如何讓其他節點感知並開始執行。如下圖中,A節點在執行完成後,如何通知B,C節點並執行。常見的思路是,節點的分層調度,它的含義及特點如下:

  • 依賴分層算法(如廣度優先遍歷)提前計算好每一層需要執行的節點;節點一批一批的調度,無需任何通知和驅動機制。
  • 在同批次多節點時,由於各節點執行時間不同,容易出現長板效應。
  • 在多串行節點的圖調度時,有較好的性能優勢。

另一種常見的思路是,基於流水線思想的隊列通知驅動模式:

  • 某節點執行完成後,立即發送信號給消息隊列;消費側在收到信號後,執行後續節點。如上圖DAG中,B執行完成後,D/E收到通知開始執行,不需要關心C的狀態。
  • 由於不關心兄弟節點的執行狀態,不會出現分層調度的長板效應。
  • 在多並行節點的圖調度時,有非常好的並行性能;但在多串行節點的圖中,由於額外存在線程切換和隊列通知開銷,性能會稍差。

如上圖所示,調度引擎目前支持這兩種調度模型。針對多串行節點的圖推薦使用分層調度器,針對多並行節點的圖推薦使用隊列流水線調度器。

分層調度器

依賴於上面提到的分層算法,節點分批執行,串行節點單線程執行,並行節點池化執行。

隊列流水線調度器

無論是外層的圖任務(GraphTask)還是內部節點任務(NodeTask)均採用池化的方式執行。

  • 節點調度機制

    • 調度機制:消費側收到消息到節點被執行,這中間的過程。如下DAG中,節點在接收到消息後需依次完成:檢驗DAG執行狀態、校驗父節點狀態、檢驗節點執行條件、修改執行狀態、節點執行這幾個過程,如下圖所示:

  • 這幾個步驟的執行,通常存在兩種方式:一種是集中式調度,由統一的方法進行處理;另一種是分散式調度,由每個後續節點獨自來完成。
  • 我們採用的爲集中式調度:某節點執行完成後,發送消息到隊列;消費側存在任務分發器統一負責消費,再進行任務分發。

這樣做的出發點是:

  • 如上圖中,ABC三個節點同時完成,到D節點真正執行前仍有一系列操作,這個過程中如果不加鎖控制,D節點會出現執行三次的情況;因此,需要加鎖來保證線程安全。而集中式任務分發器,採用無鎖化隊列設計,在保證線程安全的同時儘量規避加鎖帶來的性能開銷。
  • 再如一父多子的情況,一些公共的操作(校驗圖/父節點狀態、異常檢測等),各子節點都會執行一次,會帶來不必要的系統開銷。而集中式任務分發器,對公共操作統一進行處理,再對子節點任務進行分發。
  • 分散式調度中,節點的職責範圍過廣,既需要執行業務核心代碼,還需要額外處理消息的消費,職責非單一,可維護性較差。

因此,在項目實際開發中,考慮到實現的難度、可維護性、以及綜合考量性能等因素,最終採用集中式調度。

② 調度線程調優

調度引擎在DAG執行上,提供了兩種API給調用方,分別爲:

  • 異步調用:GraphTask由線程池來執行,並將最外層GraphTask的Future返回給業務方,業務方可以精準的控制DAG的最大執行時間。目前,外賣廣告中存在同一個請求中處理不同廣告業務的場景,業務方可以根據異步接口自由組合子圖的調度。
  • 同步調用:與異步調用最大的不同是,同步調用會在圖執行完成/圖執行超時後,纔會返回給調用方。

而底層調度器,目前提供上述講到兩種調度器。具體如下圖所示:

由此看出,調度引擎在內部任務執行上,多次用到了線程池。在CPU密集型的服務上,請求量過大或節點過多的話,大量線程切換勢必會影響到服務的整體性能。針對隊列通知調度器,我們做了一些調度優化,儘量將性能拉回到沒有接入調度引擎之前。

  • 調度線程模型調優
    • 針對同步調用的情況,由於主線程不會直接返回,而是在等待DAG圖執行完成。調度引擎利用這一特點,讓主線程來執行最外層的GraphTask,在處理每個請求時,會減少一次線程的切換。
  • 串行節點執行優化
    • 如上面DAG圖中,存在一些串行節點(如單向A→B→C→D),在執行這4個串行節點時,調度引擎則不會進行線程的切換,而是由一個線程依次完成任務執行。
    • 在執行串行節點時,調度引擎同樣不再進行隊列通知,而是採用串行調度的方式執行,最大化減少系統開銷。

4.3.4.2 高可用實踐

在高可用上,我們從隔離和監控上簡要介紹下我們的實踐,它的核心原理如下圖所示:

① 業務隔離

廣告場景中,同一服務中經常會存在多條子業務線,每條業務線的邏輯對應一張DAG。對於同一服務內各個業務線的隔離,我們採用的是“單實例-多租戶”的方案。這是因爲:

  • 流程引擎活躍在同一個進程內,單實例方案管理起來要更容易。
  • 流程引擎內部實現過程中,針對圖的粒度上做了一些多租戶隔離工作,所以在對外提供上更傾向於單實例方案。

除DAG調度和Node調度爲靜態代碼外,圖的存儲、DAG的選取與執行、Node節點的選取與執行、各DAG的節點通知隊列都採用多租戶隔離的思想。

② 調度任務隔離

調度任務主要分爲:DAG任務(GraphTask)、節點任務(NodeTask)兩類。其中一個GraphTask對應多個NodeTask,並且其執行狀態依賴所有的NodeTask。調度引擎在執行時,採用二級線程池隔離的方式將GraphTask和NodeTask的執行進行隔離。

這樣隔離的出發點是:

  • 每個線程池職責單一,執行任務更加單一,相應的過程監控與動態調整也更加方便。
  • 如果共用一個線程池,如果出現瞬時QPS猛增,會導致線程池全被GraphTask佔據,無法提交NodeTask最終導致調度引擎死鎖。

因此,無論是線程精細化管理還是隔離性上,兩級線程池調度的方式都要優於一級線程池調度。

③ 過程監控

對DAG調度的監控,我們將其分成三類。分別爲異常、超時、統計,具體如下:

  • 異常:圖/節點執行異常,支持配置重試、自定義異常處理。
  • 超時:圖/節點執行超時,支持降級。
  • 統計:圖/節點執行次數&耗時,提供優化數據報表。

4.3.4.3 高可用實踐

廣告業務邏輯複雜,在投放鏈路上存在大量的實驗、分支判斷、條件執行等。並且廣告投放服務的迭代頻率和發版頻率也非常高。因此,調度引擎在可擴展上首先要考慮的是如何調度條件節點,以及編排配置如何在無發佈下快速生效這兩個問題。

① 節點條件執行

對於節點的條件執行,我們在配置DAG時,需要顯示的增加Condition表達式。調度引擎在執行節點前,會動態計算表達式的值,只有滿足執行條件,纔會執行該節點。

② 配置動態下發

  • 如前圖所示,我們將構圖與調度通過中間態Graph模板進行解耦,編排配置可以通過Web平臺編輯後,動態下發到服務上。
  • 由於調度引擎在調度過程中,多次用到了線程池,對於線程池的動態更新,我們藉助了公司的通用組件對線程池進行動態化配置和監控。

4.3.4.4 調度引擎總結

① 功能方面

DAG核心調度

  • 調度引擎提供兩種常見調度器的實現,針對不同的業務場景,能較好的提供支持。
  • 調度引擎採用經典的兩級調度模型,DAG圖/節點任務調度更具有隔離性和可控性。

節點條件執行

  • 對於節點的調度前置增加條件校驗功能,不滿足條件的節點不會執行,調度引擎會根據上下文以及流量情況動態判斷節點的執行條件。

超時處理

  • 對DAG、Stage、Node節點均支持超時處理,簡化內部各個業務邏輯的超時控制,將主動權交給框架統一進行處理。在保證性能的前提之下,提高內部邏輯的處理效率。

節點可配置化

  • 同一個Node節點,會被對個業務場景使用,但各業務場景的其處理邏輯且不近相同。針對這種情況,增加節點的配置化功能,框架將節點的配置傳入邏輯內部,實現可配置。

② 性能方面

  • 在多串行節點的DAG場景下,性能基本可以持平原有的裸寫方式。
  • 在多並行節點的DAG場景下,由於池化的影響,在多線程池搶佔和切換上,存在一些性能折損;再進行多次調優和CPU熱點治理上,TP999折損值可以控制到5ms以內。

4.3.5 業務組件層沉澱

如“4.2.2.1 功能的標準化”中給出的定義,可獨立實現並部署的業務功能模塊抽象爲業務組件。從業務邏輯中提取高內聚、低耦合的業務組件,是提升代碼複用能力的重要手段。在實踐中,我們發現不同業務組件包含的邏輯千差萬別,具體實現方式和設計與代碼風格也參差不齊。因此,爲了統一業務組件的設計思路和實現方式,我們實現了一套標準化的組件框架,以減少新組件開發的重複性工作,並降低使用方的學習和接入成本。

上圖左邊展示了業務組件的整體框架,底層爲統一的公共域和公共依賴,上層爲業務組件標準的實現流程,切面能力則實現對業務邏輯的支持。右邊爲基於框架開發的智能出價組件示例。框架的作用是:

① 統一的公共域和依賴管理

  • 公共域是指在不同的業務組件中都會使用到的業務實體。我們將業務上的公用域對象提取出來,作爲基礎組件提供給其他業務組件使用,以減少域對象在不同組件重複定義。
  • 業務組件都有很多內部和外部的依賴。我們對公共依賴進行了統一的梳理和篩選,同時權衡各方面因素,確定了合理的使用方式。最終形成一套完整成熟的依賴框架。

② 統一的接口和流程

  • 我們將業務組件抽象爲三個階段:數據和環境準備階段Prepare、實際計算階段Process和後置處理階段Post。每個階段都設計了抽象的泛型模板接口,最後通過不同的接口組合完成組件中的不同業務流程。所有類在接口設計上都提供了同步和異步兩種調用方式。

③ 統一的切面能力

  • 目前所有的服務模塊均採用Spring作爲開發框架,我們利用其AOP功能開發了一系列的切面擴展能力,包括日誌採集、耗時監控、降級限流、數據緩存等功能。這些功能均採用無侵入式代碼設計,減少切面能力與業務邏輯的耦合。新的業務組件通過配置的方式即可完全複用。

智能出價組件即爲基於以上框架開發的業務組件。智能出價組件是對廣告出價策略的抽象聚合,包括PID、CEM等多個算法。出價策略依賴的用戶特徵獲取、實驗信息解析等數據統一採用Prepare模板實現;具體PID、CEM算法的實施統一採用Process模板實現;對出價結果的校驗、參數監控等後置操作則統一採用Post模板實現。整個組件所使用的公用域對象和第三方依賴也統一託管於框架進行管理。

4.3.6 工具包-詞典管理

在“4.2.2.1 功能的標準化”中也定義了工具包的含義,即單個的、簡單的非業務功能模塊抽象爲工具。工具包的建設是廣告平臺化工作提效的重要基礎,其主要的作用是處理業務邏輯無關的輔助類通用流程或功能。例如:廣告系統中存在大量的KV類數據需要加載到內存中使用,我們稱之爲詞表文件。爲了實現詞表文件的全生命週期管理,廣告平臺化進行了詞表管理工具的設計與開發,並在業務使用過程中積累了很好的實踐效果。

① 詞表管理的設計

上圖是詞表管理平臺的整體架構,詞表管理平臺整體採用分層設計,自上而下分別五層:

  • 存儲層:主要用於數據的存儲和流轉。其中美團內部的S3完成在雲端的詞表文件存儲,Zookeeper主要用於存儲詞表的版本信息,在線服務通過監聽的方式獲取最新的版本更新事件。
  • 組件層:每個組件可以視爲獨立的功能單元,爲上層提供通用的接口。
  • 插件層:業務插件的作用主要是提供統一的插件定義和靈活的自定義實現。例如:加載器主要用途爲提供統一格式的詞表加載和存儲功能,每個詞表可以動態配置其加載器類型。
  • 模塊層:模塊層主要是從業務角度看整體詞表文件不同流程的某一環節,模塊之間通過事件通知機制完成交互。例如:詞表管理類模塊包含詞表版本管理、事件監聽、詞表註冊、詞表加/卸載、詞表訪問等。
  • 流程層:我們將一個完整詞表業務行爲過程定義爲流程。詞表的整個生命週期可以分爲新增詞表流程、更新詞表流程、註銷詞表流程、回滾詞表流程等。

② 詞表管理的業務收益

平臺化詞典管理工具在業務實踐中具有的主要優勢爲:

  • 更靈活的服務架構:詞表流程的透明化。使用方無需關注詞表流轉過程,採用統一API訪問。
  • 統一的業務能力:統一的版本管理機制,統一的存儲框架,統一的詞表格式和加載器。
  • 系統高可用:快速恢復和降級能力,資源和任務隔離、多優先級處理能力等多重系統保障功能。

4.4 產研新流程

上文中提到,由於廣告業務線較多,且涉及諸多上下游,工程與策略經過幾年快速迭代之後,現有業務邏輯已極爲複雜,導致在日常迭代中,一些流程性問題也逐步凸顯。

① PM信息獲取困難

PM在進行產品調研與設計時,對涉及的相關模塊當前邏輯不是很清楚,往往通過線下諮詢研發人員的方式來解決,影響雙方的效率,同時產品設計文檔中純以業務視角和流程來闡述,導致每次評審時,QA和研發人員很難直觀獲取到改動點和改動範圍,中間又會花費大量時間來相互溝通,從而確認邊界與現有邏輯的兼容性等問題。

② 研發人員的功能評估完全依賴經驗

研發人員在方案設計時,很難直接獲取到橫向相關模塊是否有類似功能點(可複用或可擴展),導致複用率低,同時在項目排期時完全依賴個人經驗,且沒有統一的參考標準,經常出現因工作量評估不準而導致項目延期的情況。

③ QA測試及評估效率低

QA在功能範圍評估時,完全依賴研發同學(RD)的技術方案,且大多數也是通過口頭交流的方式來確認功能改動涉及的範圍和邊界,在影響效率的同時,還會導致一些測試問題在整個項目週期中被後置,影響項目的進度。同時,平臺化後基礎JAR包的管理完全依靠人工,對一些Action,尤其是基礎Action也沒有統一的測試標準。以上問題可以概括如下:

4.4.1 目標

藉助平臺化,對項目交付的整個過程(如下圖所示),實施產研新流程,以解決產品、研發與測試人員在迭代中遇到的問題,賦能業務,從而提升整體項目的交付效率與交付質量。

4.4.2 思考與落地

基於平臺化實施產研新流程,即利用Stage/Action的方式來驅動整個項目的交付,如下圖所示:

  • 對於PM(產品):建設Stage/Action可視化能力,並在項目設計中應用。
  • 對於RD(研發):統一採用新的基於Stage/Action的方案,設計及開發排期模式。
  • 對於QA(測試):統一溝通協作語言-Stage/Action,並推動改進相關測試方法和測試工具

4.4.2.1 產品側

下圖所示的是產研功能建設後的應用與實踐效果。前兩張爲建設的業務能力可視化,爲PM提供一個瞭解各業務最新流程及詳細Action能力的可視化功能,第三張圖爲產品設計中相關業務的調研與功能描述(出於數據安全原因,以下截圖採用非真實項目舉例說明)。

業務流程

業務功能詳情

產品設計中部分調研信息與功能描述

4.4.2.2 研發側

根據項目開發週期中研發工作的不同階段,我們制定了基於代碼開發前後的流程規範,以保證整個開發週期中研發同學能充分利用平臺的能力進行設計與開發提效。

  • 開發前

    • 技術設計:基於各業務涉及的現有Action功能與Action DAG的可視化能力,進行橫向業務的調研參考與複用評估,以及新增或變更Action功能的技術設計。
    • 項目排期:基於技術設計中Action能力的新增、變更、複用情況以及Action層級等,對開發工作量進行較爲標準化的評估。
  • 開發後

    • Action沉澱:系統統一上報並定期評估平臺Action能力的複用度和擴展情況。
    • 流程反饋:追蹤基於平臺化的每個項目,並對交付流程中的相關指標做量化上報,同時收集項目人員反饋。

4.4.2.3 測試側

  1. 採用Stage/Action統一溝通協作語言:在需求設計與評審、方案設計與評審、測試用例編寫與評審等多方參與的項目環節,統一採用Stage/Action爲功能描述與設計的溝通語言,以便將後續流程中問題的發現儘可能前置,同時各參與方更加明確變更及測試內容,爲QA更好的評估測試範圍提供支撐,進而更好的保證項目測試質量。

  2. 推動基礎Aaction UT全覆蓋:針對基礎Action,構建單元測試,在Merge代碼時自動觸發單元測試流水線,輸出執行單測的成功率和覆蓋率,並評定指標基線,保證可持續測試的效率與質量。

  3. 改進JAR管理工具化與自動化分析及測試:一級Action都集中寫在平臺JAR包中,對類似這種公共JAR包的管理,開發專屬的管理與維護工具,解決升級公共JAR自動化單測覆蓋問題以及每次升級JAR版本需要人工分析人工維護的測試效率問題,打通集成測試自動化的全流程。

5 效果

① 產研效率的提升

  • 系統能力沉澱

    • 外賣廣告所有業務線已經完成平臺化架構升級,並在此架構上持續的運行和迭代。
    • 業務基礎能力沉澱50+個,模塊共用能力沉澱140+個,產品線共用能力沉澱500+個。
  • 人效的提升

    • 研發效率提升:在各業務線平臺化架構遷移後,大的業務迭代20+次,業務迭代效率提升相比之前總計提升28+%。特別是在新業務的接入上,相同功能無需重複開發,提效效果更加明顯:
      • 能力累計複用500+次,能力複用比52+%;
      • 在新業務接入場景中,Action複用65+%。
    • 測試的自動化指標提升:藉助於JAR自動化分析、集成測試及流程覆蓋建設,廣告自動化測試覆蓋率提升了15%,測試提效累計提升28%,自動化綜合得分也有了明顯提升。

② 提升交付質量及賦能產品

  • 基於Action的變更以及清晰的可視化業務鏈路,能夠幫助QA更準確的評估影響範圍,其中過程問題數量及線上問題數量均呈下降趨勢,下降比例約爲10%。
  • 通過系統能力的可視化透出頁面,增加系統的透明度,在產品調研階段有效幫助產品瞭解系統已有的能力,減少了業務諮詢、跨產品線知識壁壘等問題(詳情可參見4.4.2.1)。

6 總結與展望

本文分別從標準化、框架、產研新流程3個方面介紹了外賣廣告平臺化在建設與實踐中的思考與落地方案。經過兩年的摸索建設和實踐,美團外賣廣告平臺化已經初具規模、有力地支撐了多條業務線的快速迭代。

未來,平臺化會細化標準化的力度,降低業務開發同學成本;深化框架能力,在穩定性、性能、易用性方面持續進行提升。此外,我們在產研新流程方向也會持續優化用戶體驗,完善運營機制,不斷提升產研迭代的流程。

以上就是外賣廣告針對業務平臺化上的一些探索和實踐,在廣告工程架構等其他領域的探索,敬請期待下一篇系列文章。

7 作者簡介

樂彬、國樑、玉龍、吳亮、磊興、王焜、劉研、思遠等,均來自美團外賣廣告技術團隊。

招聘信息

美團外賣廣告技術團隊大量崗位持續招聘中,誠招廣告後臺/算法開發工程師及專家,座標北京。歡迎感興趣的同學加入我們。可投簡歷至:[email protected](郵件主題請註明:美團外賣廣告技術團隊)

閱讀美團技術團隊更多技術文章合集

前端 | 算法 | 後端 | 數據 | 安全 | 運維 | iOS | Android | 測試

| 在公衆號菜單欄對話框回覆【2021年貨】、【2020年貨】、【2019年貨】、【2018年貨】、【2017年貨】等關鍵詞,可查看美團技術團隊歷年技術文章合集。

| 本文系美團技術團隊出品,著作權歸屬美團。歡迎出於分享和交流等非商業目的轉載或使用本文內容,敬請註明“內容轉載自美團技術團隊”。本文未經許可,不得進行商業性轉載或者使用。任何商用行爲,請發送郵件至[email protected]申請授權。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章