百度搜索exgraph圖執行引擎設計重點分成三個部分:圖描述語言、圖執行引擎、對接擴展。 圖描述語言是一種基于文本可讀的圖描述語言,用于描述任務中的算子以及算子之間的依賴關系,即讓人可以理解,也可以被計算機理解并執行。 圖執行引擎是exgraph的核心,負責根據圖描述語言生成的圖語法樹進行高效執行。它支持如串行、并行、中斷、選擇等范式,以滿足不同場景下的需求。 對接擴展則提供了與其他協議框架的接口,方便用戶將exgraph集成到現有的系統中。 總之,exgraph圖執行引擎設計的目標是實現高效、靈活的任務編排,以滿足復雜邏輯處理需求。
01
背景
搜索展現架構承載模版選擇、實時摘要補充、展現數據適配、結果渲染等職責,當前由PHP開發、HHVM執行,對接數十個產品線,數百個精細化的展現策略由100+RD共同開發。隨著搜索業務產品日益復雜和生成式大模型產品開發需要,展現架構面臨以下難題:
1、HHVM基礎設施停止維護,且不支持異步并行支持,架構升級難度大;
2、歷史累計的多個展現策略框架分布在各個階段,且各自參數不同,研發難度大。
通過調研,了解到DAG有向無環圖,將DAG圖中頂點描述為業務拆分后的一個個算子,邊及其方向作為執行順序,一對一作為串行執行,一對多作為并發執行,即使是很復雜的業務也可以用這套邏輯進行表達。且代碼實現較簡單,還能用graphviz將DAG圖生成圖片,將整個邏輯可視化。
△算子化后的邏輯執行視圖
好像很完美~~
但似乎還有些問題:
1、對于簡單邏輯,DAG圖不復雜,用graphviz構建圖也很簡單,但一旦頂點數量爆發,可閱讀性急速下降。而不幸的是,搜索的PHP模塊幾百個策略,如果遷移進來,預計會有幾百個頂點,構建這個圖以及這個圖的可讀性,依然很差;
2、簡單意味著功能弱。
比如搜索有多種版式:手百內、手百外、純NA渲染等,下游頂點根據上游頂點的執行結果來選擇不同的版式渲染。這種場景下只能呆呆的在每個版式頂點內自行判斷是否執行,而不能由上游頂點直接選擇一個版式分支執行。
比如執行到某個頂點,發現后續不用執行了,邏輯執行沒有好的退場機制。
各個算子間傳遞數據怎么處理。
...
02
圖執行引擎
DAG能滿足大多數場景的需要,但依然不夠。所以搜索設計了一套超集于DAG的圖描述,并在這個描述上,添加邏輯執行的高級功能,與web框架進行融合,逐步誕生了exgraph圖執行引擎。
exgraph圖執行引擎設計重點分成兩個三個部分:圖描述語言、圖執行引擎、對接擴展(用來對接協議框架)。
? ?
2.1 圖描述語言
2.1.1 核心語法
算子:業務執行的最小單位,通常一個單詞就是一個算子(語法單獨定義的關鍵詞除外)。
串行組:即兩個算子按照順序執行,在圖上表示為用箭頭連接:
△串行組
并發組:即多個算子并發的執行,在圖上用中括號?[]?包圍:
△并發組
屬性:圖上所有用大括號?{}?包圍的,都是屬性。屬性用于通過圖描述傳遞參數給代碼。
△屬性
算子、串行組、并發組都是一個執行單元,意味著,他們可以互相包含(算子是最小的執行單元,不能包含別的執行單元)。比如:
△互相包含
上面的這個描述,用人話說就是:
1、執行a算子
2、并發地:
執行b算子,
執行c算子,然后執行d算子,然后執行e算子
執行f算子,然后再并發地執行g算子和h算子
3、最后再執行i算子
子圖:主圖支持通過文件引入的方式,引入另一個圖嵌入到主圖
△主圖引入sub_graph子圖
通過上面簡單的介紹,你已經掌握幾乎全部圖描述語言語法了,可以開始思考,將自己所負責的業務如何用圖進行描述了。
另外,為了更好的適配業務場景,exgraph還設計了幾種指令來處理特殊場景。
擴展指令
START指令:圖開始的標記,用做給圖設置屬性。
△START指令
目前START指令用來指導創建HTTP的handler,直接讓圖引擎承接http處理、streaming rpc處理請求。
MIDWARE指令:包裝含義。
△MIDWARE指令
可以在執行c算子前,先執行b算子,并控制是否執行c算子;也可以在執行c算子前后,執行一些通用的邏輯。
SWITCH指令:選擇執行分支。
△SWITCH指令
可以在?switch_pc_or_wise?算子內,選擇執行哪個分支。
基于圖描述語言,用純文本的方式就可以將業務整體描述,很好的解決了DAG圖構圖復雜性問題,并允許自定義一些高級用法。
2.2圖執行引擎
上面介紹的圖描述語言,讓“人”可以更加簡單的方式了解到程序的執行流程,但也僅僅只是個描述而已。
如何讓其按照我們設定的描述將邏輯跑起來呢?
首先介紹一個重要的、執行單元必須實現的接口:
type Job interface{ DoImpl(*engine.Context) error }
其中*Context負責傳遞所有信息到各個算子,提供:算子選項(算子{}附帶的內容)內容獲取、數據傳遞等功能。
在上面的章節中講到算子、串行組、并發組都是一個執行單元,其實就是說,它們都實現了Job接口。
exgraph圖執行引擎是:將圖解析后的語法樹作為入參,搭配全局算子注冊,讓算子按照預定的規則執行起來。
它的執行過程近似于:
em~~,簡單的有點像把大象放冰箱的過程,但實際遠不止如此。
想一下,如果你執行到a算子,發現沒有必要執行b算子了,怎么辦?又或者a有數據要傳遞到b算子,怎么辦?
2.2.1 對象容器
exgraph中實現了一個并發安全的對象容器,用戶可以通過*engine.Context提供的接口,方便的設置和獲取對象,就像這樣:
type a struct {} func (o *a) DoImpl(ctx *Context) error { // 算子a,設置對象 var a int = 2023 ctx.RegisterInstance(&a) return nil } type b struct {} func (o *b) DoImpl(ctx *Context) error { var a int // 通過類型獲取值 ctx.MutableInstance(&a) // 打印2023 fmt.Println(a) return nil }
對象容器再存入時,將其類型作為標識符,取值時也通過相同類型的變量,通過反射賦值。
2.2.2依賴注入和對象導出
有了對象容器,exgraph設計了支持基于struct tag的對象依賴注入和導出功能,且采用腳本生成代碼的方式實現:
type Operator struct { http.Request `inject:""` http.Response `inject:"canLost=true,canNil=true"` *Userinfo `extract:"canNil=true"` } type UserInfo struct { Name string } func (o *Operator) DoImpl(engine.Context) error { // 通過inject,算子內可以直接獲取到Request對象 if v, ok := o.Request.Header.Get("xx"); ok { // do something } return nil }
利用struct tag和生成的代碼,用戶在使用算子時,實現了以下功能:
1、inject tag可以直接通過算子屬性獲取對象,省去了繁瑣的取值過程,并支持:canLost=true表示允許對象不存在,canNil=true表示循序對象值為nil。
2、extract tag則允許用戶直接賦值為算子屬性,由生成的代碼賦值將對象導出到對象容器中,且支持:canNil=true表示允許導出對象值為nil,repace=true表示允許替換對象。
2.2.3 中斷和跳過
為方便程序邏輯執行,exgraph內置了幾種中斷跳過邏輯:
1、全局錯誤中斷
type a struct {} func (o *a) DoImpl(ctx *Context) error { // 模擬業務執行遇到了不可兜底的錯誤 err := errors.New("fatal error") // 調用Abort函數即可中斷整個圖執行引擎 ctx.Abort(err) return nil }
2、全局正常中斷
type a struct {} func (o *a) DoImpl(ctx *Context) error { // 發現沒必要走后面的邏輯 // 直接中斷整個圖執行引擎 ctx.Exit() return nil }
3、跳過串行組
type a struct {} func (o *a) DoImpl (ctx *Context) error { // a算子執行跳過`a -> b`這個子集串行組 // 即b算子不再執行,但c算子正常執行 ctx.SkipSerialGroup() return nil }
2.3執行優化
exgraph執行的一個聲明周期內,大部分對象都允許池化。
2.3.1對象池
對于算子:exgraph內部對每個注冊的算子,都是注冊到一個sync.Pool中,算子對象在執行完成后,執行reset后返回到對象池內。
對于放入對象容器的對象:在exgraph執行引擎結束時,會循環對每個對象檢測是否實現了Release接口,如果實現接口就會調用,用戶就可以在Release時將對象reset后返回對象池內。
2.3.2其他優化
exgraph在執行每個算子時默認在當前goroutine執行,除非用戶顯示的給算子設置了超時時間a{timeout="1s"}。
依賴注入和對象導出,是基于腳本生成代碼的,而非反射。
03
場景案例
3.1 同路徑不同邏輯
背景:搜索PC和wise(移動端)同模塊執行,檢索路徑都為/s
方案:可以用SWITCH選擇模式,通過一個算子來判斷使用哪個分支:
3.2PHP策略遷移Go
背景:搜索展現架構當前逐步由PHP遷移到Go。在過渡期,PHP代碼遷移到Go之后,需要通過抽樣驗證Go代碼邏輯無誤,即:命中抽樣,執行Go代碼,否則執行PHP代碼。而且需要遷移的PHP策略很多,如果沒有統一的機制來支持,成本很高。
方案:用MIDWARE指令,用CommonDealPhpOrGoStrategy算子作為判斷包裝,判斷命中抽樣時,允許執行DemoStrategy1算子,并帶標識到PHP,不執行PHP相應邏輯。
否則不執行DemoStrategy1而執行PHP相應邏輯。
關鍵的是,遷移后的Go算子都不需要做特殊處理,正常遷移代碼加上MIDWARE就能支持以上功能。
審核編輯:劉清
-
RPC
+關注
關注
0文章
111瀏覽量
11683 -
PHP
+關注
關注
0文章
454瀏覽量
27048 -
DAG
+關注
關注
0文章
17瀏覽量
8240
原文標題:百度搜索exgraph圖執行引擎設計與實踐
文章出處:【微信號:OSC開源社區,微信公眾號:OSC開源社區】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
百度搜索、文庫等全新升級!以智能體為支點,撬動時代紅利

發現百度搜索頁的網站前加了圖標
百度回應否認搜索漏洞 卻私下悄悄更正
百度回應搜索引擎半數文章出自百家號:屬于特例
百度開發者搜索Beta體驗 完全無廣告
百度、英偉達聯合舉辦搜索創新大賽 搜索引擎變革 搜索+AI
百度攜手 NVIDIA 舉辦“第二屆百度搜索創新大賽”火熱進行中,五大賽道等你挑戰!

評論