1. 程式人生 > >史上最詳細的新浪廣告系統技術架構優化歷程

史上最詳細的新浪廣告系統技術架構優化歷程

內容來源:2017 年 08 月 10 日,新浪廣告開發技術專家徐挺在“第二屆APMCon中國應用效能管理大會【大規模網路架構優化專場】”上進行的《新浪廣告系統的服務化優化歷程》演講分享。IT 大咖說作為獨家視訊合作方,經主辦方和講者審閱授權釋出。

閱讀字數:4858 | 13分鐘閱讀

觀看嘉賓演講視訊及PPT,請點選: t.cn/EAEQLSN

摘要

其實新浪很早就開始研究廣告系統了,根據UserID + CookieID + 使用者行為日誌等多重要素進行使用者區分,進而針對個體使用者做控頻投放。同時為了更好的監控廣告服務平臺的效能和準確性,新浪廣告技術團隊在此基礎上進行了眾多改善措施。

技術架構和痛點

sinaX 服務化之前的架構

可能有些朋友對網際網路廣告的技術架構不太瞭解,這裡先介紹下大概的構造。基本上所有的公司的技術方案中都有一個adexchange——負責廣告流量接入以及流量優化的模組(圖中的中間模組)。

從上端過來的廣告流量都會進行流量優化,優化完成後將向下方的各個投放DSP詢價。

整個過程類似拍賣,一個流量進來後,如果被判斷為優質流量,就會向一些DSP發起競價請求,DSP根據內部的演算法優化以及使用者行為優化給出價格,adexchange接收到這些報價後會決策出勝出者,最後廣告請求被給到勝出者。這裡面adexchange主要在做兩件事,一是決策出競價勝出者,二是生態層面的調整,adexchange對下方所有投放引擎並不是一致均等對待的,而是根據階段性廣告生態的要求做出調整。

早期我們的adexchange是基於Nginx伺服器,在伺服器內部有Lua寫的業務邏輯,也就是前面提到的競價規則和流量最優化排程。

SinaX 舊架構的痛點

由於adexchange對投放引擎並非是一視同仁,所以整個流量呈現的是一個漏斗模型。

在adexchange的開發過程中,為了能夠更好的實現漏斗模型以及業務提升,我們在內部進行了二次開發,開發過程中發現了很多問題。

用Lua做功能開發並不方便,因為需求的頻繁變化導致需要即時響應,而即時響應的過程中有些功能使用Lua嵌入非常麻煩。Lua程式碼可維護性差,一旦出現人員變動,新人閱讀之前程式碼的成本很高。

第三是業務內的監控很難做,如果採用Nginx加Lua的方式,嚴格來說唯一的解決方案就是使用某種方式將日誌輸出,很難在Nginx內部提取狀態量傳送到關鍵業務檢測點上。最後是測試問題,基於Nginx加Lua的環境做完全量測試或者全量灰度測試很麻煩,一般只能通過直接嵌程式碼的方式解決,無法採用一些傳輸的技術方案。

當時之所以要選擇Nginx加Lua的方式,是因為覺得Nginx效能不錯,配合Lua也能很好解決效能方面的問題。所以對我們來說效能不是瓶頸,真正的痛點在於二次開發。

廣告引擎舊架構的痛點

在最前面提到的技術架構圖下方有著很多的投放引擎,上圖就是引擎的具體實現。2014年的時候這些引擎都是基於tomcat伺服器實現,包括使用者畫像查詢、投放單檢索、演算法粗排等功能都在tomcat伺服器上。

這樣的架構所帶來的最大問題就是執行緒模型,Tomcat是阻塞式的執行緒模型,執行緒分配出去後必須完成請求後才能釋放,但是當時我們的日流量非常大,使用tomcat成本很高,效率也很低。

(基於tomcat系統碰到的問題)

Tomcat架構帶來的最大業務痛點在於無法應對突發的流量衝擊。如果流量在某一時刻突發性的增長几倍,這時除非之前的負載很低,否則只能採用降級和熔斷的方式減輕tomcat的壓力,但是這樣的做法其實會損失公司的收入。

技術痛點總結

我們整個2014年所碰到的技術痛點總結起來主要有四點。

  • 功能單體化嚴重。所有的廣告投放邏輯和投放業務都實現在單個的Nginx加Lua,以及tomcat中,任何的改動都面臨著很大的風險。

  • 模組間的功能互動是plug-in方式。這裡的模組指的是演算法,對於廣告來說每天都會有上線,這就意味著要頻繁更換plug,增大了系統風險。

  • 程式設計模型不適應業務的發展。程式設計模型指的是tomcat單執行緒必須完成任務才能釋放,這種方式很容易堵塞業務,唯一的解決辦法就是不計成本部署大量的tomcat伺服器。

  • 系統執行狀態不透明。

痛點問題的技術分析與選擇

針對以上的這些痛點,我們進行了技術分析和選擇。

功能服務化。各服務相互獨立,降低業務耦合度,提高產品需求開發的響應時間。

RPC。服務間的通訊採用RPC,我們在對比各個thrift、gRPC、dubbo和Finagle等RPC框架的生態圈後,最後採用Twitter開源的finagle RPC框架。

監控。對於廣告系統來說監控方面最關需注的有兩點,一是系統狀態實時監控與跟蹤,二是業務資料實時分析與統計。系統實時狀態不僅限定於物理機,還要關注qps和超時率以及請求花費的平均時間。業務資料主要和廣告業務相關,比如某個廣告的實時點選率以及變化,這些業務的實時分析需要及時的反饋給廣告投放家或代理商,因為他們會直接對效果不好的廣告進行優化。

新浪廣告系統的服務化過程

技術的權衡取捨

1、服務分化問題

過去在服務化的初始階段,我們認為可以將漏斗模型每層需要過濾的量都做為一個服務,這樣不僅在業務邏輯上很自然,對於業務開發和新功能增加來說也很方便,要增加產品功能只需要改動對應的服務。

但是後續在原型測試的時候發現部分服務的上下游呼叫過於頻繁,這是因為看上去是經過抽象的漏洞模型,其實流量在模型中未必是平均漏下去的,有可能在某一層會漏的比較少。上下游的頻繁呼叫帶來的最直接影響是頻寬佔用過大,處理時間的I/O佔比高。

後來我們對最初設計的原型進行了改動,現在可以自動的根據流量特徵來實現服務的合併。

(重構之後的架構圖)

新架構中流量下來後會先經過RB和PB,也就是價格最高的在頂層然後往下一層一層篩選。可以看到有些流量是直接到引擎的,它繞開了中間環節,提高了I/O和效率。

在adx的服務化過程中我們最大的體會就是,不要完全的根據業務邏輯進行服務化劃分,一定要通過原型用真實流量進行測試才會發現實際上需要做的服務劃分。

2、廣告檢索

(廣告引擎服務化的架構)

在廣告系統中會碰到這樣幾個過程,所有流量下來後會經過adx被漏到具體的投放引擎中。投放引擎執行投放過程中,由使用者立項服務查詢使用者畫像,根據使用者畫像會拿到一堆投放單存放在待投候選集中,之後與演算法進行互動判斷出最適合的投放單,廣告投出去後會有計費服務進行計費。所有的服務都會接入到log service進行日誌處理。

當時對整個技術的權衡取捨中,我們在Index service上花費了很多精力。最初的方案是直接將Index service做成一個服務,但是隨著qps增加資料量已經影響到了Index service的可擴充套件性。後來我們決定通過rsync的方式週期性的推資料集到投放服務中,這樣就解決了呼叫傳輸資料量大,影響系統擴充套件性的問題。

高可靠性和可擴充套件性的架構

1、系統容錯性

在考慮高可靠性和可擴充套件性的過程中,我們認為有一點最需要解決,即系統容錯性,這也是分散式系統中需要考慮的問題。系統容錯性具象化來看主要有三點,一是面向錯誤進行系統設計,這些錯誤不僅是通訊錯誤、還包括物理機宕機以及一些不可預測的錯誤;二是服務的無狀態設計;三是故障服務的自動替換。

2、系統可靠性

對於系統可靠性,我們在架構過程中體會最深的有三點。

  • 跟蹤監控程式執行狀態和熱點。執行狀態的監控很好理解,而之所以要跟蹤熱點,是因為服務程式中一些過去未發現的熱點隨著時間的推移可能會被引發出來,這些熱點如果沒有及時跟蹤,一旦碰到意外狀態會馬上變成災難。

  • 實時監控系統異常處理,直接隔離異常服務。

  • 服務分等級做多重備份。一般考慮到容錯性和高可靠性我們可能會對同一個的服務部署多個備份,同時這也意味著成本增加。而在廣告系統中,我們會將服務進行分級,對於第一等級的做N重備份,對於低等級的考慮到成本問題只做1到2重備份。

3、系統處理能力的可擴充套件性

做系統架構的時候開發人員通常認為新增伺服器一定能提高系統處理能力,其實是未必的,我們不能指望通過簡單的增加物理機和計算資源來提升系統的整體處理能力,它們甚至在某些qps峰值的時候還會拉低處理能力。

只有當單機服務處理能力的達到線性化能力的情況下,才能夠保證後續系統處理能力的可擴充套件。

系統的服務處理能力擴充套件關鍵在資源分配上,一個分散式系統的關鍵點在於排程控制,過去排程控制可能只是一些請求,現在更多的是強調資源的合理分配。對於廣告來說流量的峰值變化是很嚴重的,一般凌晨流量不會很多,在早上和中午會分別達到高峰,這樣情況下資源的動態分配能夠很大程度上緩解資源浪費。

過去我們認為廣告請求最值得關注,但是在已做到前兩個可擴充套件性的情況下,輸入其實並不是問題,最關鍵的還是系統的資料熱點。因為它往往是系統的瓶頸,比如在資料一致性無法保障的情況下,我們為了一些業務只能去提升一致性等級,這時候就很容易形成資料熱點。

在設計系統的過程中一定要結合業務來看資料熱點是否一直在,如果存在就將它降級。只有保證資料熱點在監控或者系統分析中,不會被判斷為一段時間內的熱點的情況下,我們才會認為這個系統是可擴充套件性的。

4、系統架構的可擴充套件性

在系統架構的可擴充套件性上我們參考了lambda架構模式,它將系統分為批處理層、服務層、速度層,這樣就可以將離線資料和實時資料結合起來對系統提供服務。

廣告系統中其實很強調實時資料反饋,比如對於模型計算、投放效果、使用者畫像等,如果只採用離線資料效果並不會很好。第二個要點是資料一致性,由於廣告系統內部的資料量並不是很大,所以最簡單的做法是採用分級別的方式來給予保證。

第三點則涉及到一致性hash,雖然一致性hash可以恢復已經掛掉的節點,但是同時也會損失流量。所以我們後續去掉了過去採用的所有請求進來的一致性hash分配,而直接根據下面服務的負載能力來進行流量分發。

(系統優化效果)

技術收穫和經驗總結

服務劃分粗細粒度把握

對於服務劃分粗細粒度把握,首先要明確的是切忌簡單按照業務邏輯進行服務邏輯劃分;第二服務劃分的核心是找出真正的業務中心和業務支撐;第三整個過程中沒有統一標準,關鍵在於權衡。

服務的優化重點在業務邏輯的優化

對於系統問題開發人員一般認為通過服務化就可以解決,但現實是系統的熱點不會隨著服務化自然消失。

所以在進行服務化優化過程中一定要將重點放在業務邏輯的優化上,因為所有的服務化都是為了實現業務邏輯,只有在對業務邏輯有深刻理解情況下,服務的優化才是有目的的,而不是單純從技術角度考慮。我們認為在服務化的過程中一定要遵循的原則是技術的實現只是手段。

服務需要平滑地切換上線

要對於已經現有的系統進行服務化,這就意味著一定時間內有兩套系統需要平滑地切換上線。開發過程中我們開發部門的某個同事就曾表示系統的服務化就像飛行過程中換引擎。

這樣高風險的過程中有兩個關鍵點,一是灰度上線階段時一定要考慮新舊系統並行相互相容。第二是考慮單個功能的服務化上線對整體系統的影響。

服務治理

對於服務治理我們認為沒有必要完全遵循它的原則,而更多的是從分散式系統角度來看,從資料一致性、容錯性等方面考慮服務治理。我們對此做了一些劃分。

首先是服務處理能力的自動降級和恢復;其次是服務保護,包括負載均衡和熔斷;最後是服務的透明化執行,在服務化治理實踐過程中會有很多的服務,要對這麼多服務進行監控和跟蹤,如果使用手動或者指令碼的方式效率會很低,而且很不直觀,這時候服務透明化就顯的很重要。

以上為全部分享內容,謝謝大家!