導讀:百度Feed信息流推薦系統服務於手百、好看、全民、貼吧等公司絕大多數信息流業務場景,隨着業務的高速發展,整個系統承載的流量已經高達數十億,在龐大的流量規模背後是數百個微服務和數萬臺機器作支撐。如何保證整套系統對外的高可用性是整個系統能力建設的關鍵,也是咱們團隊的一個很是核心的工做方向。爲了保障信息流推薦系統常態5個9的可用性目標, 本文將基於咱們實際的工做經驗分享介紹百度Feed在線推薦系統是如何建設高可用性架構的。
1、背景
算法
百度Feed信息流推薦系統服務於公司絕大多數信息流業務場景,目前已經承載了手百、好看、全民、貼吧等多端產品的信息流推薦能力。以下是從資源漏斗維度給出的百度feed推薦系統的一個簡化示意圖。後端
△圖1:系統簡化示意圖緩存
系統簡要說明以下:網絡
資源索引庫:基於倒排索引或是向量索引提供數千萬資源的索引查詢能力,一般會有數十甚至數百的不一樣的資源索引庫,分別提供不一樣類型的資源索引能力。架構
召回層:從數千萬的資源中召回跟用戶相關的數十萬的資源,一般與資源索引庫強綁定,好比一些顯式召回會在召回層基於用戶的tag去相應倒排索引庫找到用戶相關的文檔資源。app
排序層:在大型推薦系統中,爲了平衡算力和效果會構建粗排&精排兩層排序體系,基於統一的預估打分機制從數萬的資源中找到用戶最感興趣的數百條資源送給混排層。框架
混排層:混排層從數百資源中根據用戶上下文信息推薦出最終用戶看到的十幾條資源,一般也會耦合產品的干預能力,好比資源的多樣性控制等。運維
用戶模型:用戶模型服務提供用戶級別的特徵獲取能力,好比用戶感興趣的標籤集合。異步
文檔特徵:文檔特徵服務提供文檔級的全特徵服務,一般基於文檔id訪問獲取獲得。ide
隨着業務的高速發展,百度Feed推薦系統目前已經承載了數十億的在線請求流量,在龐大的流量規模背後是數百個微服務和數萬臺機器作支撐。如何保證系統的高可用是整個系統架構設計的關鍵能力之一,也是咱們整個團隊工做的一個核心方向。
爲了保證在線推薦系統常態5個9的高可用目標,基於咱們實際工做的不斷抽象沉澱,造成了咱們整個架構的柔性處理能力。
△圖2:多層級柔性處理能力
如圖2所示,從對單請求的長尾超時異常到IDC級大規模故障,基於咱們的實際工做總結,都造成了相應的架構設計方案來應對,接下來進行具體的介紹
在線推薦系統是由數百個微服務所組成,而且在私有云上進行了大規模的混部, 對於常態可用性指標影響最大的因素主要有兩個方面:
單實例故障所引發的可用性抖動,可能的引起緣由包括機器死機、磁盤打滿,混部致使的cpu過載等。
長尾請求超時所致使的失敗, 這一般是因爲系統的一些隨機因子所致使,引起的緣由多種多樣,且很難被抽象歸一,好比資源的競爭、接收流量的瞬時不均、週期性的內存清理、旁路日誌操做等運維活動。
一般對於這類問題的解決方案是增長重試機制和對於異常實例的屏蔽探活機制,咱們的解決思路相似,但在實現方面對可能引起的問題作了進一步演進。
1.1 動態重試調度
重試機制最大的問題是重試時間的設定和雪崩問題:
重試時間設置的短,意味着常態下重試流量的比例會相對較大,形成資源的浪費,同時會更容易引起下游服務的雪崩,好比一旦下游出現大面積的延遲退化,就會致使流量的總體翻倍,進而整個下游服務都將被拖垮。
重試時間設置的長,意味着整個服務的超時都會長,不然重試的效果就起不到有效的做用,在複雜的微服務調度鏈路上很容易引發超時的倒掛。
固然重試時間的設定,咱們能夠基於某個狀態下去權衡利弊,給出一個近似的解來避免上面的問題, 但業務的快速迭代須要咱們不斷的基於新的條件去更新這個值,這會帶來極大的運維成本。
基於上述問題的考慮,咱們設計並實現了動態重試調度機制, 其核心思想是嚴格控制重試流量的比例(好比只容許3%的流量觸發重試),同時基於分位耗時的實時動態採集機制,將重試的機會分配給須要重試的流量,這同時也意味着咱們再也不須要手動去維護超時時間的設定了。
以下是一個實現對比圖:
△圖3:動態重試調度
其核心實現包括:
後端分位耗時統計機制:將時間序列劃分爲週期性的間隔(好比20s一個週期),基於前一個週期的流量去統計分位耗時值,並結合配置化的重試比例來動態的肯定backup_request_ms的值,基於rpc的請求級重試時間設定機制,就達成了咱們動態超時調度的目標了。
熔斷控制機制: 從分位耗時統計機制來看,能夠發現這裏有個週期的滯後, 但不會對咱們效果產生大的影響,這是由於先後兩個週期服務的延時變化不會發生很大的波動,只要可以處理極端狀況下滯後所致使的流量超發(可能引起的雪崩)問題就能夠了, 而這正是熔斷控制機制所要解決的問題, 熔斷控制機制經過實時統計重試請求數量,並基於更小時間窗口來控制請求的比例,同時會經過平滑的機制去處理小窗口帶來的統計不許問題。
整個方案在推薦系統應用後,在常態下可用性相對可以提高90%以上。
1.2 單實例故障處理
應對單實例故障一般採起的方案是屏蔽和探活機制,但在高可用架構上面還面臨以下挑戰:
識別能力上:這裏包含幾個維度的考量,準確率、召回率和時效性三個方面, 一方面基於單機視角的探活在時效性方面雖然可以作到實時的效果,但因爲局部視角的緣由準確率每每不高,誤識別的機率較大,而基於全局信息的採集每每會帶來時效性的大幅下降,同時在性能方面也會帶來必定折損。
策略處理上:一方面探活流量會致使小部分流量的折損,同時非全局視角的屏蔽會致使可用集羣的服務容量風險,從而帶來總體的惡化。
基於上述問題的考慮,咱們在動態重試調度的基礎上,作了進一步的演進, 其核心思想在於實時動態的儘量下降損失,異步準實時的作全局異常處理控制。
實時動態止損:動態重試機制應對的場景是無實例差別的長尾請求,爲了應對單實例故障這個特定化的場景,這裏有兩個抽象的處理方案來解決,其一基於可用性和耗時反饋的權重調節機制,利用可用性能夠感知到異常實例的存在,從而快速下降權重訪問,同時在重試實例的選擇上也會加以區分;利用耗時反饋的平滑調節,會基於壓力去自適應的調節正常實例的權重,保證正常實例的可用性不會由於容量問題打垮。
全局準實時的止損:基於咱們集成在brpc框架內部的組件可以快速的收集單機視角的實例級信息,而後週期級別的去上報給統一的控制匯聚層。 經過高效的代碼實現以及兩層的匯聚機制基本上能夠作到對client的性能無影響。更重要的是咱們基於與pass的聯動來進一步控制咱們對異常實例的控制策略,從而在保證可用性容量的前提下作完全的止損。
△圖4:全局準實時止損方案
基於上述方案的實現,咱們的系統基本上可以自動的應對單實例故障的問題,可用性抖動相較於單純的動態重試方案,抖動區間更小,基本上在5s內就能獲得收斂,同時在抖動區間可用性的下降幅度也相較於以前降低了50%。
這裏講的服務級故障指的是在微服務體系下某個子服務出現大規模不可用,基本上沒法對外提供任何服務能力。目前基於雲原生的微服務化架構是整個業界的發展趨勢,設計良好的微服務體系可以極大的提升整個系統開發的迭代效率,同時在穩定性方向也提供了更多可探索的空間。在微服務架構的基礎上,咱們經過柔性架構的設計思想並結合多層級的容災設計來應對這種大規模的服務故障場景。這裏先給出其核心要點:
差別化對待異常:好比對於核心服務,咱們須要有必定的機制應對可能潛在的異常;對於非核心的服務,咱們要作的可能僅僅是控制它的異常不要擴散到核心鏈路。
多層級容災機制:經過多層級的容災機制,當大規模故障發生時,可以在必定的時間內保障用戶體驗的基本無損。
固然服務級故障的處理須要依託於具體的業務場景來作具體的設計,這裏給出部分例子來講明在Feed推薦系統是如何來進行處理的。
2.1 多召回調度框架
在推薦系統中,因爲召回方式的差別性,每每會設計成多召回框架,每路召回負責某種具體的召回能力,好比從資源層面看,咱們能夠分爲圖文召回,視頻召回, 從召回算法層面,咱們能夠分爲itemcf召回,usercf召回等。就單召回路而言,對總體服務的影響取決於它的功能劃分:
一級召回:好比運營控制相關的召回, 直接影響產品的體驗感知, 不容許失敗;
二級召回:決定了信息流分發效果,這些召回路若是失敗,會致使大盤分發降低顯著, 單路可容許短時間失敗,但多路不能同時失敗;
三級召回:補充召回路,好比探索興趣召回,對長期效果起到必定增益做用,短時間對產品效果影響不顯著,容許短時間失敗。
對於三級召回路,服務調用失敗雖然短時間對產品影響不顯著,但大規模的超時失敗會致使總體性能的延遲退化,進而影響到總體服務的可用性。一種直接粗暴的解決方案就是調小這些召回路的超時時間,使得其即便超時也不會影響到總體,但這顯然會下降這些服務的常態可用性,不是咱們想要的效果, 爲了抽象統一的解決這個問題, 咱們設計了多召回調度框架, 具體設計以下:
△圖5:多召回調度框架
其核心設計包括:
召回等級劃分:一級召回不容許主動丟棄;二級召回路劃分多個羣組,目前咱們按照資源類型劃分,圖文召回羣組&視頻召回羣組&...;每一個召回羣組由對分發貢獻最大的幾個召回路組成, 羣組內部容許超過40%(可配)的召回路主動丟棄;三級召回路則容許主動丟棄;
丟層機制:當知足要求的召回路都返回後,剩下沒有返回的召回路會主動丟棄,不在等待返回結果了;
補償機制:丟棄對產品效果始終仍是有影響的,只是影響較小而已, 爲了將這部影響下降到最小,咱們設計了旁路的cache系統,當主動丟棄發生後,利用上次的結果cache做爲本次的返回,從而必定程度的下降損失。
基於上述方案的實現,經過咱們實際的演練結果,目前咱們整個系統能自動應對二/三級召回隊列服務級故障的處理。
2.2 排序層故障解決方案
排序服務構建在召回之上,提供對多路召回數據的一個統一打分機制,從而完成資源的總體排序, 目前業界一般採用粗排&精排的兩層排序體系來解決算力和效果相矛盾的問題。
粗排經過雙塔模型的設計能在一次用戶請求中支持數萬的資源排序預估,但效果相對來講偏弱;
精排經過更復雜的網絡模型能提供效果更優的排序能力,但支持的預估數量級只有千級別;
召回 → 粗排 → 精排 的漏斗過濾體系在算力必定的狀況下很好的提高了推薦效果。
能夠看到,排序服務對整個推薦效果相當重要,一旦排序服務出現大規模異常,基本上就是在數萬的資源裏面進行隨機推薦了。爲了防止這類問題的發生,在設計之初咱們也是充分考慮了故障的應對場景,其核心思路是建設層級的降級機制。
△圖6:排序層降級方案設計
其核心設計包括:
構建一層穩定的中間代理層Router:改層邏輯簡單,迭代少,穩定性高,提供異常發生時的降級能力;
粗排異常處理方案:旁路建設一路基於資源的點展比和時長信息的排序能力,數據由離線後延統計信息挖掘獲得,當粗排服務發生大規模異常時,利用該路信息提供應急排序能力;
精排異常處理方案:粗排的排序效果相比精排要差,但能夠做爲精排異常的時候降級數據供整個系統使用,當精排服務發生大規模異常時,直接利用粗排服務進行降級。
相比於隨機推薦來講,整套排序層故障解決方案可以大幅下降故障時對推薦效果的影響。
2.3 彈性容災機制
基於排序層故障解決方案的進一步演進,咱們構建了針對全系統的彈性容災機制,其目標是用一套統一的架構支持異常的處理,當異常發生的時候,下降對用戶的體驗感知和策略效果的影響。
△圖7:彈性容災新架構
其核心設計包括:
穩定的推薦系統入口模塊Front:該模塊是推薦系統的入口層,定位是不耦合任何業務邏輯,只支持彈性容災相關的能力;
分層的異常數據建設:個性化容災數據 + 全局容災數據, 個性化容災數據一般基於跨刷新數據的緩存來構建, 全局容災數據經過旁路挖掘來構建;
統一的異常感知機制:跨服務的異常透傳能力,當上層Front感知到核心服務異常時,就優先獲取個性化容災數據來進行容災,若無個性化容災數據,即訪問全局容災數據來進行容災。
咱們經過信息流的置頂數據的異常處理來作說明。
全量容災數據的挖掘:旁路週期性的將全部可用的置頂數據寫入全局的容災cache中;
個性化容災數據的構建:當用戶前一刷的時候,置頂召回服務會取出符合用戶條件的最佳置頂數據集合,將這部分數據寫入個性化容災數據cache;
服務失敗感知:當置頂召回訪問失敗,或是從Front到置頂召回服務之間任何鏈路失敗時, Front接收到的數據返回包裏面都沒有標誌置頂數據成功的標記;
容災控制:Front會基於返回數據作判斷,如沒有成功標記,則開始進行容災處理,優先讀取個性化置頂容災數據,沒有讀取到,則開始利用全局容災數據進行容災。
該機制構建了統一的彈性容災能力,一方面利用個性化數據在容災時儘量保證策略的損失最小,另外一方面利用全局的容災數據進行兜底容災儘量的保證用戶體驗的無感知。
IDC級的故障解決方案一般採用異地多主方案來解決,即故障發生時經過idc切流來及時止損, 百度推薦系統也採用相似的方案來解決,這裏咱們經過下發歷史存儲服務的異地多主方案設計來作個介紹。
下發歷史存儲服務提供用戶級別最近的下發、展示、點擊過的資源。基於它提供跨請求的策略支持,好比多樣性控制, 更重要的是防止重複資源的下發。一旦服務掛掉將整個推薦服務將沒法對外提供服務。
其總體設計以下:
△圖8:下發歷史存儲服務多主架構
其核心設計包括:
每一個地域維護一份全量的存儲;
對於讀請求,只容許讀本地idc;
對於寫請求,同步寫入本地機房,同時進行跨idc同步寫入,若寫入失敗,則寫入消息隊列,由消息隊列進行異步跨idc進行寫操做更新。
當出現idc級故障時,基於異地多主多活架構可以快速支持切流止損。
百度Feed推薦架構支持着業務的高速迭代發展,在整個架構演進過程,可用性建設一直是系統架構能力的關鍵指標,咱們經過柔性架構的建設,保證了對外常態5個9的高可用目標,並具有應對常規大規模故障的能力。
△圖9:近一個月的出口可用性指標
本期做者 | windmill & smallbird
閱讀原文:https://mp.weixin.qq.com/s/sm8eehjoUEqvF_PS4VcRKg
推薦閱讀
|百度信息流和搜索業務中的彈性近線計算探索與應用
|有趣!有料!有溫度!「百度技術沙龍」全新升級,重磅迴歸!
---------- END ----------
百度架構師
百度官方技術公衆號上線啦!
技術乾貨 · 行業資訊 · 線上沙龍 · 行業大會
招聘信息 · 內推信息 · 技術書籍 · 百度周邊
歡迎各位同窗關注!