快手數據成本白盒化治理實踐
一、數據治理體系
和行業大部分公司一樣,快手數據治理也是分為四大部分:成本、質量、效率和安全。
1. 效率
分為數據開發效率和數據消費效率。開發效率主要關注模型開發效率,消費效率主要關注模型是否足夠易用,查詢響應是否足夠快。
2. 安全
同樣也是分為生產階段的安全、還有消費階段的安全。
3. 質量
分為避免發生、主動發現、故障結果、故障復盤。
- 避免發生:在設計、開發、測試和驗收環節,是否符合規范。
- 主動發現:出了問題之后,一定是我們自己先發現,而不是用戶告訴我們。首先要做到監控覆蓋全面,其次還要實現有效的告警,確認告警的有效率,是非常關鍵、也是最難的部分。
- 故障結果:各個級別故障數量,是否在預期范圍內,我們對故障是容忍的,只要控制在一定數量內。
- 故障復盤:首先,復盤要足夠深刻,抓住問題本質、找到共性。其次,復盤會產生很多待改進問題,這些問題是否被及時解決了。
4. 成本
數據成本由三部分組成:存儲成本、計算成本、流量成本。
- 存儲成本:存儲效率是白盒化的重點:壓縮比、壓縮性能、副本數。壓縮比關注存儲密度,壓縮性能關注壓縮耗時,副本數關注能否用較少的副本存儲數據,確保數據不丟失。
- 計算成本:CPU 平均利用率衡量資源調度能力。如果調度能力不行,很容易出現負載不均,可能部分機器打滿,另一部分卻很空閑,導致集群整體利用率上不去。單 CU 處理數據量衡量引擎算力水平,隨著我們不斷去優化計算引擎,單 CU 處理的數據量也會隨之升高。
- 流量成本
本次分享主要是講成本部分,我們通過三個白盒化實現:引擎白盒化 + 數倉白盒化 + 工具白盒化。
二、引擎白盒化
“引擎白盒化”,是一個具體的項目代號,這個項目包含很多優化點:HBO 自動化調參、壓縮算法替換、引擎算子分析……
1. HBO 自動調參
什么是 HBO 自動調參?可以想象一下,在沒有 HBO 之前,調參主要通過人工完成的,但有三大弊端:
難度高:對于一個普通數據開發者來說,這無疑是一件很難做好的事情。首先需要理解引擎原理,分析作業的幾十個指標,找到性能問題,再調參,還不一定能調好。
易失效:隨著時間推移,計算邏輯、數據內容可能早已發生改變,之前的調參過一段時間就失效了。
成本大:可以想像一下,對幾萬、十萬個作業進行人工調參,基本是不可能完成的事情。
HBO 的出現就可以很好地解決這三大問題,它是通過分析任務運行歷史,自動優化作業執行參數,從而使作業一直處于貼近最優的狀態。
HBO 為什么可以提升性能、降低成本?主要通過三個方面來實現的:
(1)合理資源配額:通過識別作業對 CPU 和內存的需求,自適應擴縮容,防止錯配。
(2)優化任務分片:通過分析任務時長,靈活調整分片參數,以防止過短或過長。
(3)任務優化功能參數:通過調整小文件合并、壓縮算法、Broadcast 等參數,以提升性能。
HBO 調參過程就是數據驅動的過程:
第1步,構建畫像,需要采集幾十個決策指標,指標的質量直接決定了 HBO 效果,需要的是嚴謹。
第2步,參數粗調,通過數據指標+預設規則,進行首次粗調參,粗調時會盡量的保守,比如:CPU/內存會盡可能多預留一些,以防止運行變慢。
第3步,參數下發,將調參的結果下發給各個任務,下發之后,下一個周期就會產生影響。
第4步,參數精調,粗調之后,我們能感知調參效果,根據最新反饋進一步精調、再精調。
以上列舉了部分調參列表,供參考。接下來我們看看第二個優化項,存儲壓縮算法替換。
2. 壓縮算法替換
先看看快手大數據存儲現狀:
- 技術選型:湖倉的底層存儲是 PARQUET + GZIP。
- 數據規模:新增 PB / 存量 EB。
- 數據讀寫:讀寫比大于 20:1,讀取數據量遠高于寫入數據量,所以我們會更加關注解壓性能,而壓縮性能稍微差點,是可以接受的。
- 存儲周期:很多數據存儲周期比較長,甚至是永久存儲,滿足審計相關的需求,所以對于存儲系統來說,壓縮比永遠是我們首要考慮的。
在壓縮算法這塊,快手選型是 GZIP,縱觀行業里的很多公司,一開始也都是 gzip,不過這些公司都逐步切換到了 zstd,因此為他們節省了大量的成本。以上圖片列舉了:亞馬遜、推特、優步幾家公司在推特上的一些討論。
Zstd 既有著和 zlib 相當的壓縮率,同時還有媲美 snappy 的壓縮性能,可謂是集合了兩者的優勢。
另外,我們也在線上進行了實測,壓縮率提升 3%~12%,壓縮級別越高,壓縮率也就越高。Zstd 壓縮級別分為 1-22,根據我們的觀察,壓縮級別超過 12 之后,壓縮率提升的就不是很明顯了,所以我們最終選擇的壓縮級別,最高不超過 12。
此外,我們還做了很多其它的測試,穩定性、準確性、兼容性,這三方面都沒有問題。提示一下:zstd-jni 1.5.0 以下的版本有不少的 bug,建議升級到 1.5 以上,完全向下兼容。
3. 引擎算子分析
什么是引擎算子分析?通過對 Spark 引擎進行多視角、多維度深度剖析,提升對引擎的認知,使算力可解釋、明確算力瓶頸、挖掘算力潛在優化點。
通過不同的視角進行深度剖析,在不同的視角下,能發現不一樣的問題,找到不同的潛在優化點。本次介紹最重要的 3 個分析視角,分別是執行過程視角、物理算子視角、UDF 函數視角。
(1)執行過程視角:將計算劃分為十大過程,分析這十大過程的構成、資源開銷、時間開銷。
(2)物理算子視角:物理算子和邏輯算子有著對應關系,一個邏輯算子有多種不同物理實現,在不同的場景下,匹配不同物理算子。物理算子內部實現是否高效,以及是否被正確使用,都對性能有重大影響。
(3)UDF 函數視角:對幾百個 UDF 函數使用情況進行分析,既包含引擎內置的,也包含用戶實現的。
引擎理解同樣也是數據驅動的,拆解引擎需要用到四大數據源:
(1)QueryPlan:通過解析 SQL,生成執行計劃,從而對算子進行分析。
(2)StackTrace:用于分析調用堆棧,生成直方圖、火焰圖,進行性能分析。
(3)EventLog:作業在運行過程中生成的 DAG 圖譜以及各種指標,這對引擎理解也有極大的幫助。
(4)GcLog:最后是 GcLog,主要用來精準分析內存用量,減少 OOM 發生的概率。
接下來看一組數據,以上是對執行過程的分析,我們看看耗時最大的四個過程,有了數據之后,只需要通過進一步下鉆分析,就能找到優化方向:
數據掃描:占比最大,超過 30%,有點超出預期,說明潛在優化空間是非常大的。
數據交換:占比第二,大概 20%,也是非常高的。
數據聚合:占比第三,大概 15%。
UDF 調用:占比第四,大概 14%。
Aggregate:整體比較健康。
Join:SortMergeJoinExec 性能差,但占比 95.3%,可通過 HBO 調參轉換BroadcastHashJoinExec。
Scan:數據讀取和壓縮占比低,而數據處理占比 75.94%,后續主要考慮如何提升數據處理的效率(包含 schem 處理,行列轉換等)。
首先,Json 處理占了 1/3 還要多,這是非常不健康的,這是重點要去解決的。第一,要優化 JSON 處理性能,第二,我們也得看看為什么有這么多的 JSON 要處理?肯定有哪里不對勁。
其次,平臺公共 UDF,整體看起來還算可以。
最后,業務 UDF,可以看到占比也很高,也是需要重點去解決的。
當我們有了數據、看清了現狀,接下來應該如何應對呢?
(1)我們需要去做分析,判斷。判斷是否合理?是否有優化空間?空間有多大?
(2)需要確保使用方法正確。如果有一輛好賽車,但是不懂駕駛,就很難發揮出應有的性能。
(3)可以看看某些零部件,是否有替代方案。例如 JSON 處理,壓縮算法。
(4)如果以上都解決不了,那就只能自己動手去重構某些零部件了,尤其是一些關鍵零部件。
更多的優化,也還在進行當中。
三、數倉白盒化
1. 數倉架構度量
講數倉白盒化之前,我們必須先要弄清楚,好的數倉標準是什么樣的?只有搞清楚了數倉架構的量化指標,才能指導我們進行優化:
完整度:衡量數據模型建設,是不是足夠完整、通用,滿足的需求是不是足夠廣泛。其實就是分析跨層引用多不多?跨層引用過多,數倉模型一定不是完整的。
復用度:主要看三個指標(引用系數、重復計算、鏈路深度)。
規范性:這是基礎要求,但做好并不容易,尤其是一開始沒做好,后續想要撿起來,會非常困難。
2. 如何減少重復計算
先來看一個相似算子的示例。圖中給出了三個查詢,拆解為語法樹之后,不難發現,這其中隱藏了非常多的相似代碼片段。圖上用了四種不同顏色,進行標識,相同的顏色代表此部分計算邏輯是相似的,這些相似片段,通常都會帶來數倍資源開銷。
如何識別相似的代碼片段呢?
第1步,獲取任務列表,我們要獲取到所有執行任務的 SQL。
第2步,生成執行計劃。
第3步,逐層算子簽名,通過后序遍歷 AST,逐層向上展開,直到完成整棵數的簽名,得到簽名集合。
第4步,重復算子識別,通過簽名碰撞,去發現重復的算子。
第5步,計算算子代價,代價越高的重復算子,就越應該抽象、沉淀下來。
第6步,合并重復算子,提升處理速度,降低成本。
這是我們內部的一組數據,直觀的感覺就是重復比例有點大。可以看到聚合的相似算子達到了驚人的 43%,這是非常之高的,連接算子也達到了 23%,最后,還有 4.5% 的 INSERT 算子是相似的,INSERT 是最后輸出的模型,這說明了有 4.5% 的模型是相似的。如果說,我們不去自動干預、自動治理,只會越來越惡化。
當我們識別了相似算子,看清了現狀,那么到底有什么價值呢?主要有三個:
指導治理:向用戶展示當前現狀,并給出整改優化建議.
輔助開發:主要包含模型選擇和優化。
查詢加速:通過自動物化視圖,實現查詢加速,這個過程對用戶是完全透明的。
3. 如何降低鏈路層級
想要降低鏈路層級,我們得先了解現狀。上圖是線上某條生產鏈路,展示的是任務依賴關系。可以獲得一些信息:首先是,鏈路層級非常深:達到了驚人的 39 層。其次是,跨層依賴非常多:可以明顯看出來很多末尾的 ADS 節點,甚至會依賴最源頭ODS。這也間接導致了很多問題,例如:數據及時性差、生產成本高、數據質量難以控制。
為什么會出現這種現象?既要滿足快速變化的業務需求,又要不斷地抽象和沉淀,還要確保不出現質量問題。既要又要還要,通常來說,這三者很難同時兼顧,所以隨著時間變化,導致數倉劣化。
那么怎么去改變現狀呢?第一種解決方案是機器輔助治理。首先,通過構建算子級血緣,還原數據加工邏輯。其次,分析并發現模型中的不合理,生成整改優化建議。最后,由用戶根據建議去優化。
第一種解決方案,只是用于短期治理,并沒有從根本解決問題。那么終極方案是什么呢?我認為是邏輯層和物理層解耦,將邏輯模型和物理模型完全分離開來。
邏輯層:數據開發者只需要根據業務需求去設計邏輯模型,而完全不用理會底層實現。
物理層:物理模型和鏈路,完全由機器自動化構建,并且根據邏輯模型的變化,不斷的迭代和調整,使數倉一直處于貼近最優的狀態。
4. 常規治理自動化
首先我們不得不聊一下現狀:治理屬于一種事后清理工作,善后工作,大家普遍不會太重視,或者說優先級低,沒時間處理。做數據治理平臺的同學無一例外,都遇到了這個問題,就是推不動業務去治理。
那到底應該怎么辦呢?我們的答案是:常規治理自動化!但是自動化治理,面臨的最大挑戰就是怎么確保自動的過程中可靠安全?萬一刪錯了數據怎么辦?萬一導致了故障怎么辦?其實并沒那么可怕,再難的事情,只要有體系化的保障,就不用害怕,我們給出的方案是五步法自動治理:
制定標準:自動化治理一定要有嚴格的標準,只有形成了標準,才有可能自動化,這是先決條件。
問題識別:根據標準、根據規則去識別生產待治理的問題。
質量檢驗:第一道防火墻,通過波動檢測、交叉驗證等方式阻斷部分問題發生。
治理預告:第二道防火墻,對于非常 critical 的治理動作,通過治理預告,讓用戶幫助阻攔問題。
快速回滾:第三道防火墻,即使出現了問題,也能快速回滾。所有的治理動作,必須是可以回滾的,否則就不能納入到自動化范圍。
四、收益分析
數據存儲壓縮率:提升 5%,計算資源收益:提升 16%,作業運行時長:和計算資源收益相當,縮短 14%。此外,作業失敗率、GC 時間、OOM 等也有不同程度的下降
五、未來規劃
未來工作更多的是延續,因為很多工作才剛開始起步,還比較淺。總的來說,有這么幾件事:
數據壓縮:之前主要是替換壓縮算法,這個紅利已經吃完了。接下來還要再繼續提升的話,就需要在動態壓縮、編碼等方面下功夫。
數倉架構:前面我們講的數倉白盒化,很多工作都才剛開始,特別是在模型設計、模型生產等方面。
深度范圍:進一步提升引擎白盒化治理深度。
下代技術:要想在效率和成本上產生突破,必須要布局下一代技術,跳出我們現有的認知,在技術范式上取得進展。