導讀
移動運營推廣平台(OPS)承載着百度內部移動應用/移動搜索業務的用户增長預算的全流程結算線上化管控功能,為了解決用增業務發展規模擴大、原有技術架構老舊、無離線數倉系統等一系列的問題,針對全域結算數據啓動了整體的架構改造。為了解決業務中存在的問題,本文深入探討並提出了一類在線、離線結合的任務調度解決方案,完成了結算業務架構更新換代,更好地服務於業務發展。
01 背景簡述
1.1 業務/技術背景
移動運營推廣平台(OPS)承載着百度內部的移動應用/移動搜索業務的用户增長預算的全流程結算線上化管控功能(包括合作方-渠道信息註冊管理、內/外部結算數據接入/展示、預提單/賬單計算-審批-結算確認支付等一系列主要流程),已為移動搜索分成、用增推廣等業務線提供了十餘年的服務。
隨着用增業務發展與線上化管控規模的擴大,業務結算量級、結算數據量與審批單量提升,原有數據層技術架構老舊,逐漸承載不住日益增長的結算時效性、準確性要求,導致結算出賬數據異常/產出失敗,造成實際業務損失。
平台歷史上的結算指標、賬單數據均通過PHP/Java腳本計算,通過MySQL數據庫對儲存中間數據與結果數據,無離線數倉,存在易篡改、無留痕等數據審計風險。因此針對用增結算全域結算數據立項,啓動了離線任務的數倉化改造。為了解決在線業務與離線結算計算間天然不兼容的問題,綜合考慮用增結算運營的靈活性和結算數據計算的準確性,我們提出了一類在線與離線結合的任務調度解決方案,目前已承載了線上億級別月度結算賬單的計算、出賬、按時產出和更新。
1.2 名詞解釋
TDS:Turing Data Studio 是基於圖靈(百度內部數據分析平台)的數據建設解決方案,提供 數據開發、數倉管理、監控運維、資源管理等一站式服務的數據開發平台。
BigPipe(現DataHub):百度內部維護的分佈式消息系統,可通過Topic或Queue方式使用。
02 技術方案設計
2.1 業務特點分析
用增結算相較於其他業務離線數倉的特點是:業務受外部影響較大,操作和策略的制定較為靈活;業務側的變更需要及時同步到數據層計算/重算,同時需要保證計算流程的準確合規。經常存在依賴數據的小範圍更新case(如個別渠道作弊判定、某個合作方合同信息的修改、出賬方案調整等),因此開發的任務都擁有較強的靈活性,相關離線腳本也都支持對單條/指定範圍的數據進行計算/更新重算。
原來的離線腳本模塊經過長時間的迭代發展,存在以下問題:
- 數據計算/更新時無法感知非預期的變更。合同更新、反作弊處理等流程作為成熟的業務流程擁有較完善的實時/定時處理機制(針對上游業務數據變更更新對應的下游報表、賬單數據),但面對非架構原生、後續迭代新增的功能,只能通過運營/產品側通過範圍標記(指定合作方/結算類型等)手動發起相應的重算,在此過程中可能存在信息丟失/誤操作等情況,導致全局上下游不一致;
- 數據領域劃分模糊,存在同一字段由多個線上模塊/腳本負責更新的情況,在邏輯衝突時存在潛在的冪等性問題;
- 腳本服務語言架構舊(PHP+Shell腳本),無可視化界面和運維手段,存在比較嚴重的單機熱點問題/BigPipe API穩定性問題,影響賬單計算的準確性/時效性。
為了克服舊架構的缺點,同時保留其靈活響應運營動作的優點,需要對數倉化改造方案以及平台間的銜接控制進行充分設計。
2.2 平台數倉化架構設計和改造思路
架構改造應基於業務特點與合適的設計進行,那麼該如何改進現架構,保證功能不損失還有新收益?
由於PHP在我廠早期普遍用於快速開發平台與腳本,因此邏輯在平台與腳本上耦合度很高。平台業務,定時調度,甚至腳本自身都可以調起腳本進程,且平台和離線腳本均直接對線上庫進行讀寫操作。這種架構靈活性很高、有利於功能快速迭代,但兩側邏輯一旦產生差異,就會丟失數據的一致性;相關的中間件也沒有統一的狀態查詢管理界面,消息的堵塞和丟失都會導致問題溯源十分困難。
同時,我們觀察到目前的數據邏輯中,很大一部分代碼被用於判斷狀態流轉(當前單據/合同是否應被重算),但這部分邏輯對於金額計算是完全無關的,而且對應的查詢花銷在整個計算過程中的耗時也達到30%以上,存在優化的空間。
為了解決當前邏輯耦合、冗餘的問題,我們決定在啓動改造時將平台與數倉的邏輯分離:平台專注於業務數據錄入和狀態流轉,數倉專注於結算數據計算如具體的指標和結算金額。把賬單計算邏輯沉澱到離線側,避免計算/修改邏輯分離產生的數據不一致風險,利用數倉層的數據版本控制和血緣追溯等能力,確保結算數據的準確性、一致性和可追溯性,同時將數據任務統一接入TDS等成熟的數據任務管理平台,簡化了分散在多個平台上的數據管理和運維工作。
具體的邏輯拆分思路如下:
- 首先將依賴離線任務產出的數據報表進行字段級領域劃分,確認兩方職責:數倉層負責產出結算支付相關字段,平台層負責對外展現,同時負責在審批、業務流程中更新狀態類字段。
- 收攏調度入口,例行類和事件觸發類調度的底層由分別發送異構BigPipe消息啓動改為統一記錄業務操作記錄,由專門的調度體系統一發起調度。
- 對當前觸發離線計算的事件進行邏輯歸因:
- 業務操作(平台自身的數據變更、數據任務觸發的業務變更)驅動的數據變更,計算/重算任務應當由平台主動發起,均通過專門的調度體系統一調度。
- 外部數據源驅動的數據變更,計算/重算任務應當由數倉主動發起,通過TDS的調度回溯功能進行統一管理。
2.3 在/離線調度系統
在上述思路的基礎上,我們設計與實現了一個專門的調度系統來統籌管理離線計算任務:該系統同時兼顧業務上下游依賴關係和數據上下游血緣關係,對計算任務進行有序的調度管理。
對於結算類數據,在數據時效性(操作命令及時產出對應的結算數據)和一致性之間,一致性更重要(每次計算均需要保證結算數據的全量準確性),時效性相對而言是可犧牲的(產出晚好過產出錯誤的結算賬單)。在此假設下,需要設計構建一個能保證結算數據準確性,同時時效性相對不差(發起變更1小時內可完成計算)的結算類任務調度系統。
整體設計
調度系統的整體架構和流程見下圖:
通過以上3個步驟,完成業務層與離線計算層間的交互:
1.操作入庫:向操作MySQL表中寫入待執行任務如反作弊報表重算、賬單重算等;因操作基本按月/日維度執行,絕大部分操作類型的操作數不超過100次/月,故暫不引入緩存等中間件,減少系統複雜度。
2.任務編排:通過批處理的方式,將入庫操作中寫入的操作進行分析後進行聚合/關聯/派生等操作,生成一批待執行任務實例(保存為數據庫記錄);對於數據結算類任務,還會處理成與任務和批次對應的離線文件,供計算任務調用獲取實際需要計算的數據範圍。
3.任務調度:將上一步中編排好執行關係的任務實例轉為TDS任務Schema後,調用TDS-OpenAPI,在TDS上觸發對應的調度,並將對應的任務狀態回寫到平台側。可以通過平台進行任務狀態的監控和控制。
TDS任務執行完成例行任務/重算任務後,將待更新數據通過算子推送到平台在線庫;具體推送的數據取決於不同離線任務的導入配置和業務需求,但每個任務都會將更新寫回到數倉,保證數倉中的數據是最新、最準確的版本。
- 例1:調用例行的數據拉取重算,將每日結算數據重新拉起計算,並同步到在線庫中供平台查詢;
- 例2:調用反作弊重算任務,調起對應的任務後,更新數倉結果,並將新老結果中diff部分(更新的數據)同步到在線庫中。
操作入庫
針對改造前任務啓動方式各自成體系、編程語言混雜、難以進行統計和迭代改造的情況,本次改造過程中將任務啓動統一優化為兩種固定方式:
- Java平台側:通過統一的RPC調用記錄操作至數據表。對平台而言,有且僅有該入口用於操作的入庫,方便後續的任務審計、切面管理、功能統一迭代升級;
- Spark數倉離線側:通過固定的數據Schema導入至操作表。該類直接寫入的操作源於歷史任務中存在的離線任務中通過BigPipe消息觸發調用下游任務,為簡化邏輯重構成本保留已有特性。後續將不再新增此類入庫方式,並計劃隨迭代逐步下線、收攏至平台側。
任務編排
編排組件週期運行,針對一批待執行的業務操作進行聚合/任務實例化/任務依賴管理,並生成一個全局隨時間遞增的批次號。主要操作如下:
- 操作聚合
基於發起的業務變更操作進行分析,根據需要操作的數據時間和對應的任務集合(如需要修改x月y日的某業務某類型數據)進行聚合分組;這樣做的原因是TDS平台的任務組調度均為基於時間序列的調度,將操作按照任務元(從任務類型映射)-任務執行時間(根據週期類型(月/日/實時)與數據時間轉換)分組後,合併/分配到同一個或一組類似的數據任務實例,可以最小化調度資源與執行資源的使用。
- 任務實例化
操作聚合到任務類型-任務時間後,根據對應的任務上下文(TaskContext)和相應的配置構造需要啓動的1~n個任務實例。任務上下文有如下定義:
- 數據範圍:用於確定需要計算的範圍條件(如指定某條/批賬單、某個日期、某個業務類型等)。
- 任務類型:包含固定類型、業務/功能類型
- 固定類型主要用於固定的任務,大部分不需要參考數據範圍,如某個表數據的全量同步;同類型下每個任務上下文代表一個獨立的任務或功能步驟。
- 業務/功能類型主要用於需要控制數據範圍執行的任務,如某產品線-某數據版本-某個週期的激活數據拉取;同類型下每個任務上下文代表相同功能下不同的數據範圍,可精確控制計算維度。
- 任務元組:用於對接任務調度平台(接口定義,對於TDS包括數據任務組、起始算子、全流程算子),如任務啓動和獲取任務實例狀態,可通過配置MySQL表實現動態熱加載。
依賴管理
實際操作中一批數據任務的執行可能是存在先後邏輯關聯,不能同時啓動的,因此需要組織合理的調度次序保證準確性。為了保證該次序是最優、最簡化和容易理解的,我們引入了以下設定:
- 前置依賴(隱式依賴)關係:發起業務變更時平台側不關心對應的底層數據邏輯,但隱藏數據邏輯是需要在實際調度中表現的(比如:數據重算髮起時,可能需要提前發起一個線上數據同步任務/上游數據拉取任務。任務上游可能因為邏輯、架構迭代而變更,但平台側並不關心其調整)。任務計劃中可能存在業務側不關心但必須執行的前置任務,此時需要根據依賴關係,自動構建和生成對應的任務實例;若對應的任務實例已存在,則直接進行前置關聯。通過該步驟,可以構建出一組相互間無依賴關係的任務依賴樹(為避免引入過多依賴管理的邏輯,不允許多依賴,但允許有多下游),將單獨的一棵樹稱為業務組(該業務組執行完成時表明業務對應的數據任務執行完成,前後數據一致且可信)
- 業務依賴(顯式依賴)關係:針對某些業務組間存在前後序關聯的情況(如A業務依賴B業務數據,恰巧在同一批次內A、B業務都有操作發起),需要保證執行次序,避免產生後序業務先行計算導致的計算結果錯誤、異常等情況。
- 如何建立業務組間串行執行的關係?對於系統而言調度的單位是實例,不存在業務組這樣一個動態的實體,因此我們通過上下文映射實例對應的任務類型,通過類型間業務依賴關係配置(從業務動作的角度進行關聯),建立任務實例間的樹狀依賴,進而控制業務組間的執行次序,組成整體的運行拓撲。
-
為了分離數倉血緣治理問題,保證在/離線調度的業務導向,在編排中不支持多上游依賴,實際存在的多上游依賴通過上下文中的任務元組進行配置,將多個任務抽象集中到單個調度實例中。在這個設計基礎上,引入了動態依賴(根據時間版本-數據範圍匹配,建立業務功能類任務間的依賴)、依賴鏈與依賴繼承(A-B-C依賴鏈上業務實例不全時(如僅存在A、C)根據優先級建立實際業務依賴(A-C))等設定,更好地服務於業務邏輯與數據邏輯的銜接。
通過以上三個步驟,我們將業務側發起的業務請求轉換、構建為同批次下的一系列需要執行的數據任務實例以及方便依次處理的執行次序,並交付由調度平台執行。
任務調度
為了保證數據任務的正常執行和處理以及及時反饋進度到平台側,調度組件包含以下功能:
- 任務執行&狀態同步:根據任務實例記錄,轉換為TDS平台的任務運行實例,並根據當前狀態、依賴任務狀態等信息判斷是否啓動調度平台任務實例或獲取對應的任務狀態;任務的調度以批次號為單位,當前批次未執行完之前不可執行下一批次,確保全局不出現數據任務的亂序執行。
- 任務管理:可以通過任務批次、任務狀態以及任務管理界面,或利用TDS平台來管理和感知任務的執行情況。
- 任務監控:對當前批次內未執行&執行中的任務定時巡檢,並通過IM/郵件/短信等方式報警,及時感知任務異常,並由RD人工介入修復。
03總結
用增結算類業務作為內部應用推廣對外結算的唯一業務平台,對結算數據的準確性、一致性的要求非常高。
針對平台離線計算曆史架構中存在的系統性問題,根據當前業務特點進行分析、設計,進行了整體離線層數據架構的重構,保證結算數據的邏輯解耦、版本管理、準確性時效性提升、進度與異常及時感知、簡化接入與降低運營成本。針對在線業務平台與離線數倉架構的銜接方案,設計了一套適用於結算業務的在線/離線調度系統,在保證結算數據計算準確有序的前提下,保留了平台對業務管控的靈活性,同時通過離線任務統一治理減少了數據層運維和排查成本,有效支持用增線上化結算業務的快速發展。
———— END————
推薦閲讀
百度視覺搜索架構演進實踐
智算基石全棧加速,百度百舸 4.0 的技術探索和創新
HelixFold 3 全球首個完整復現 AlphaFold 3,百度智能雲 CHPC 為人類生命探索提供算力平台支撐
百度搜索結果波動的極致治理
PaddleX圖像分割賦能醫療領域篩查檢測,打造智能醫療診斷系統