Lambda架构在有赞广告平台的应用与演进
https://tech.youzan.com/lambda/
有贊廣告平臺依托于有贊微商城,幫助商家投放廣告。通過有贊廣告平臺,商家可以在騰訊廣點通、云堆、小博無線等流量渠道投放廣告。 對于有贊廣告平臺,除了提供基礎的廣告編輯、投放、素材管理等功能,最重要的就是廣告的投放效果的展示、分析功能了。有贊廣告平臺的數據分析模塊提供了不同的時間維度(天、小時),不同的實體維度(廣告計劃、廣告、性別、年齡、地域)下的不同類型指標(曝光、點擊、花費、轉化下單、增粉數)的分析。所有這些數據都是秒級到10min級別的準實時數據,為了做到將實時數據和離線數據方便的結合,我們引入了大數據系統的lambda架構, 并在這樣的lambda架構的基礎下演進了幾個版本。在這里想把廣告系統的數據統計服務演進歷程以及踩過的坑、得到的感悟和各位同僚分享一下?
大數據系統的Lambda架構
大數據處理技術需要解決數據的可伸縮性與復雜性。首先要很好地處理分區與復制,不會導致錯誤分區引起查詢失敗。當需要擴展系統時,可以非常方便地增加節點,系統也能夠針對新節點進行rebalance。其次是要讓數據成為不可變的。原始數據永遠都不能被修改,這樣即使犯了錯誤,寫了錯誤數據,原來好的數據并不會受到破壞。
Lambda架構的主要思想是將大數據系統架構為多個層次:批處理層(batchlayer)、實時處理層(speedlayer)、服務層(servinglayer)。批處理層生產離線數據,是每天重新計算的,實時處理層的數據增量更新,數據時效過去之后會被清理,由批處理層的數據替代。服務層則對外提供數據服務,綜合批處理層以及實時處理層的數據。典型的lambda架構圖如下:?
- 批處理層每天離線的計算歷史數據,全量刷新昨日之前的歷史統計數據,產生batch Views - 實時處理層實時的獲取增量數據,產生當日實時的增量統計數據,產生real-time Views - 服務層從batch Views以及real-time View讀取數據,向外提供實時+離線的數據統計服務
有贊廣告平臺的數據來源
有贊廣告平臺展示的數據指標包含兩類:曝光類(包括曝光數、點擊數、點擊單價、花費),轉化類(包括轉化下單數,轉化下單金額,轉化付款數,轉化付款金額)。前一類的數據主要由流量方以接口的方式提供(比如對接的騰訊廣點通平臺),后一類則是有贊特有的數據,通過買家的瀏覽、下單、付款日志算出來。
第一版架構
第一版采用了典型的lambda架構形式。批處理層每天凌晨將kafka中的瀏覽、下單消息同步到hdfs中,再將hdfs中的日志數據解析成hive表,用hive sql/spark sql計算出分區的統計結果hive表,最終將hive表導出到mysql中供服務層讀取。另一方面,曝光、點擊、花費等外部數據指標則是通過定時任務,調用第三方的api,每天定時寫入另一張mysql表中。
實時處理層方面,用spark streaming程序監聽kafka中的下單、付款消息,計算出每個追蹤鏈接維度的轉化數據,存儲在redis中。
服務層則是一個java服務,向外提供http接口。java服務讀取兩張mysql表+一個redis庫的數據。
第一版的數據處理層比較簡單,性能的瓶頸在java服務層這一塊。 java服務層收到一條數據查詢請求之后,需要查詢兩張mysql表,按照聚合的維度把曝光類數據與轉化類數據合并起來,得到全量離線數據。同時還需要查詢業務mysql,找到一條廣告對應的所有redis key,再將redis中這些key的統計數據聚合,得到當日實時的數據。最后把離線數據和實時數據相加,返回給調用方。?
這個復雜的業務邏輯導致了java服務層的代碼很復雜,數據量大了之后性能也跟不上系統要求。
另一方面,實時數據只對接了內部的kafka消息,沒有實時的獲取第三方的曝光/點擊/瀏覽數據。因此,第一版雖然滿足了歷史廣告效果分析的功能,卻不能滿足廣告操盤手實時根據廣告效果調整價格、定向的需求。
第二版架構
針對第一版的兩個問題,我們在第二版對數據流的結構做了一些修改: - 在實時處理層做了一個常駐后臺的python腳本,不斷的調用第三方api的小時報表,更新當日的曝光數據表。 這里有一個小技巧:由于第三方提供的api有每日調用次數上限的限制,將每天的時間段分為兩檔:1:00-8:00為不活躍時間段,8:00-第二天1:00為活躍時間段,不活躍時間段的同步頻率為30min一次,活躍時間段為10min一次。每次同步完數據之后會根據當天消耗的api調用次數和當天過去的時間來計算出在不超過當天調用次數前提下,下一次調用需要間隔的時間。同步腳本會在滿足不超過當天限額的前提下盡可能多的調用同步api。從而避免了太快消耗掉當日的調用限額,出現在當天晚上由于達到調用限額而導致數據無法更新的情況。 - 在批處理層,把轉化數據表和曝光數據表導入到hive中,用hive sql做好join,將兩張表聚合而成的結果表導出到mysql,提供給服務層
完成第二版改動之后,java服務的計算壓力明顯下降。性能的瓶頸變成了查詢redis數據這一塊。由于redis里面的實時數據是業務無關的,僅統計了追蹤鏈接維度的聚合數據。每次查詢當日的轉化數據,需要現在mysql中查詢出廣告和跟蹤鏈接的關系,找出所有的跟蹤鏈接,再查詢出這些跟蹤鏈接的統計數據做聚合。
另一方面,離線計算的過程中涉及到多次mysql和hive之間的導表操作,離線任務依賴鏈比較長,一旦出錯,恢復離線任務的時間會比較久。
第三版架構
考慮到mysql方便聚合、方便服務層讀取的優點,在第三版中我們對lambda架構做了一些改動,在數據層面只維護一張包含所有指標的mysql表。mysql表的stday(統計日期)字段作為索引,stday=當天的保存實時數據,st_day<當天的保存離線數據。
在第三版中,我們只維護一張mysql數據統計表,每天的離線任務會生成兩張hive表,分別包含轉化數據和曝光數據。這兩張hive表分別更新mysql表的st_day<today的行中的曝光類指標和轉化類指標< p="">
在實時數據這塊,常駐后臺的python腳本更新stday=當天的數據的曝光類字段。spark streaming程序在處理kafka中的實時下單消息時,不再統計數據到redis,而是請求業務java服務暴露出來的更新數據接口。在更新數據的接口中,找到當前下單的追蹤鏈接所屬的廣告,更新mysql中stday=當天的數據的轉化類字段。這樣就把查詢階段的關聯操作分散在了每條訂單下單的處理過程中,解決了實時數據查詢的瓶頸。最終的java服務層也只需要讀取一個mysql表,非常簡潔。
總結
有贊廣告平臺經歷了三版的數據架構演進,歷時大半年,最終做到了結合內部、外部兩個數據源,可以在多維度分析離線+實時的數據。在數據架構的設計中,我們一開始完全遵照標準的lambda架構設計,發現了當數據來源比較多的時候,標準lambda架構會導致服務層的任務過重,成為性能的瓶頸。后續兩版的改進都是不斷的把本來服務層需要做的工作提前到數據收集、計算層處理。第二版將不同來源的指標合并到了同一個mysql表中。第三版則將redis數據與業務數據關聯的工作從統計階段提前到了數據收集階段,最終暴露給服務層的只有一張mysql表。
綜合這兩版的經驗,我們發現在lambda架構的基礎上,盡可能的將一些復雜的合并、關聯工作從服務層前提到數據采集層,能夠讓整個數據流結構更加簡潔,最終向外提供的服務性能也會更高。
轉載于:https://www.cnblogs.com/davidwang456/articles/9238844.html
總結
以上是生活随笔為你收集整理的Lambda架构在有赞广告平台的应用与演进的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 从 Spring Cloud 看一个微服
- 下一篇: 有赞API网关实践