vivo 海量基礎數據計算架構應用實踐
基礎數據是公司大數據應用的關鍵底座,價值挖掘的基石,內容包括:大數據集成,數據計算,架構容災等幾個主要方面。建設的目標包括:確?;A數據及時準確、計算性能好、資源成本消耗低、架構容災能力強、研發效率高,這也是基礎數據工作的核心能力。
一、基礎數據發展與挑戰
1.1 vivo 早期的基礎數據架構
為了滿足業務發展,0-1構建基礎數據的基礎框架,數據來源主要是日志,通過實時采集,緩存到Kafka,按小時離線轉存到ODS表,日處理數據量在百億級,整個數據鏈路簡潔高效,但是,隨著業務發展,數據增長,用戶的訴求多樣化,該基礎數據架構逐漸面臨諸多挑戰。
1.2 vivo 業發展帶來挑戰
一是:數據規模增長,日增記錄數從百億到萬億級,日增存儲量從GB級到PB級,實時并發QPS量級達到數據百萬。
二是:計算場景增加,從離線計算擴展到準實時,實時,甚至流批一體計算場景。
三是:性能要求提高,實時計算端到端延時,需要從小時到秒級;離線計算單小時數據量級從GB達到10TB+,業務發展速度超過了技術架構迭代速度,必然給技術帶來更大的挑戰。
1.3 技術挑戰
首先是單個Topic數據量每天數百億,多個消費組同時消費,重復消費導致計算和存儲資源浪費;Kafka集群穩定性越來越差。
數據量的增加,數據采集和ETL計算時延越來越長,無法滿足鏈路秒級時延,每小時超過10TB的離線處理時間超過2~3小時。
考慮存儲成本的原因,Kafka生命周期配置有限,長時間的故障會導致數據丟失。
由于計算性能和吞吐有限,需要不斷增加資源,運維值班的壓力日益增長,每月有超過20天都有起夜的情況。
當然,除了技術挑戰,還有面臨用戶的挑戰。
1.4 用戶訴求
- 數據安全方面:數據加密,計算|需要解密|和鑒權,確保數據的安全合規
- 帶寬成本方面:數據壓縮,計算|需要解壓縮|和拆分,降低傳輸的帶寬成本
- 存儲成本方面:數據輸出,需要支持|不同壓縮格式,以降低存儲成本
- 使用便捷方面:需要擴充|基礎數據|公共維度,避免下游重復計算
- 使用門檻方面:實時和離線數據|需要滿足SQL化查詢,降低用戶使用門檻
圖片
二、vivo 基礎數據架構應用實踐
2.1 整體架構
基于業務發展,構建多機房多集群,雙活容災鏈路基礎架構,全面支持多種周期(秒級/分鐘/小時/天等)數據計算場景。
相比較歷史架構,我們新增了離線采集鏈路,直接從源端拷貝LOG日志,緩存到HDFS目錄,再解析入庫寫ODS表,與原實時鏈路互備,可實現鏈路故障容災切換,同時,實時計算增加分揀層,收斂消費,支持多組件的配置化輸出,為了確保數據及時和準確性,構建了完善的數據校驗和監控體系。
顯然,當前的架構有點類似Lambda架構,可能會有以下幾個疑問:
- 實時和離線鏈路會出現存儲和計算冗余,浪費資源多;
- 實時和離線計算會存在數據一致性問題,運維成本大;
- 現在都發展到流批/湖倉一體計算,此架構不夠先進。
大數據計算架構,滿足公司和業務發展,才是最好的,過于追求先進,又或者太過落后,都不利于公司和業務的發展,基礎數據,重點是穩定高可用,通過持續的優化和迭代,將資源浪費問題,數據一致性問題和性能問題解決,構建一種雙活容災全新架構,才是我們初衷。
結合業務發展和使用調研,發現批計算場景遠多于實時計算場景,并且有以下特點:
- 因Kafka的存儲與HDFS存儲比較,成本高,如果將萬億級數據全部緩存Kafka,存儲成本巨大。
- 實時應用場景占比很少,約20%,海量數據消費資源持續空跑,導致大量計算資源浪費。
- Kafka數據使用門檻高,不能直接SQL查詢,理解和使用的效率太低。
- 離線重跑頻繁,Kafka消費重置offset操作不方便,運維難度較大。
- 流批/湖倉一體架構成熟度有限,技術挑戰難度較大,穩定性存在挑戰。
- 基礎數據的雙鏈路一致性問題、資源冗余問題、性能問題,通過架構調整是可以解決的。
圖片
2.2 雙鏈路設計
結合2種用數場景,將離線和實時計算鏈路,數據緩存和計算分離,減少實時存儲和計算的資源,減少故障風險。
只有實時計算訴求,開啟實時采集;寫入到Kafka或者Pulsar集群,緩存8-24小時(可根據需要調整),用于后續實時計算。
只有離線計算訴求,開啟離線采集;按小時拷貝到HDFS緩存集群,保存2-7天(可根據需要調整),用于后續離線計算。
同時,數據采集端確保實時和離線數據不冗余,這樣設計的好處就是:
- 數據緩存 HDFS 比 Kafka 成本更低(降低40%成本),不容易丟,離線重跑更加便捷;
- 實時鏈路出問題可立即切換到離線鏈路(定點采集,分鐘級切換入倉),容災能力會更加強大。
隨著業務發展,實時場景逐漸增加,切換到實時鏈路后,會與原離線數據比較,數據不一致性風險更大,為此,我們通過三個措施解決,將ETL過程組件化,標準化,配置化。
一是:開發上線通用組件,離線和實時ETL共用
二是:成立ETL|專屬團隊,統一處理邏輯
三是:構建ETL處理平臺,配置化開
這樣,通過鏈路切換,處理邏輯統一,功能和邏輯一致,既提升了研發效率,也消除了數據不一致風險;而在計算方面,實時和離線計算集群相互獨立,實時和離線數據緩存計算相互獨立,互不影響,計算更加穩定。
解決了Kafka存儲成本、雙鏈路數據不一致、鏈路容災問題,接下來就是計算性能的問題需要解決:
- 實時計算,存在每天百億級別的大Topic,多消費組重復消費,計算資源浪費。
- 實時計算,數據全鏈路端到端(數據生產端到數據用端)秒級延遲訴求無法滿足。
- 離線計算,單次處理數據量10TB+,計算時間長超過2小時,計算內存配置TB級,及時性沒法保證。
- 離線計算,單小時數據量級不固定,任務配置的計算資源是固定的,當數據量增加時,常有oom現象,必然,導致值班運維壓力就比較大。
2.3 實時計算性能優化
增加統一分揀層,通過Topic一次消費,滿足不同業務的數據要求,避免重復消費,存儲換計算,降低成本。
為了解決百億級大Topic=重復消費問題,我們構建了實時分揀層,主要是基于用戶不同訴求,將不同用戶,需要的部分數據,單獨分揀到子Topic,提供用戶消費,該分揀層,只需要申請一個消費組,一次消費,一次處理即可,有效避免重復消費和計算,這樣,通過對大Topic部分數據的適當冗余,以存儲換計算,可降低資源成本30%以上,同時,有效確保下游數據的一致性。
為了實現實時鏈路秒級延時,也遇到了一些困難, 主要介紹下高并發場景下的Redis批量動態擴容問題:
在實時ETL環節,會存在多個維表關聯,維表緩存Redis,實時并發請求量達到數百萬,因并發量持續增加,在Redis動態批量擴容時,會因數據均衡導致請求延遲,嚴重時達30分,單次擴容量機器越多越嚴重,這種延時部分業務無法接受, 我們考慮到=后續組件容災的需要,通過請求時延、并發量、擴容影響等幾個方面的kv組件驗證測試,最終采用了HBase2.0,得益于它毫秒級的請求延時,優秀的異步請求框架,擴容批量復制region功能,因此,我們將HBase引入到實時鏈路中,達到解決Redis批量擴容導致消費延時的問題。
對于動態擴容延時敏感業務,優先采用HBase緩存維表,Redis作為降級容災組件;對于動態擴容延時不敏感業務,優先采用Redis緩存維表,HBase作為降級容災組件。
在實際應用中,還有兩個小建議:
一是:實時任務重啟時,瞬間會產生大量Redis連接請求,Redis服務器負載急劇增加,會存在無法建立連接直接拋棄的情況,因此,建議在Redis連接代碼中增加重試機制,或者,連接量比較大時,可以適當分批連接。
二是:Redis組件的單點故障,不管是不是集群部署,難免出現問題,以免到時束手無策,建議增加額外組件降級容災,我們主要是HBase和Redis并存。
2.4 離線計算性能優化
批處理,參考流計算的原理,采用微批處理模式,解決超過10TB/小時的性能問題。
前面多次提到的離線計算,單次處理數據量超過10TB,消耗特別多的資源,數據經常出現延遲,從圖中可以看出,鏈路處理環節比較多,尤其在Join大維表時,會產生大量shuffle讀寫,頻繁出現7337端口異?,F象(這里的7337是ESS服務端口),因集群沒有類似RSS這樣的服務,即使有,也不一定能抗住這個量級的shuffle讀寫,所以,降低shuffle數量,是我們提升離線計算性能的關鍵。
為了降低shuffle數量,首先想到的就是降低單次處理數據量,于是,我們借鑒了流式計算模型,設計了微批計算架構,其原理介紹下:
數據采集寫HDFS頻率由小時改為分鐘級(如10分鐘);持續監控緩存目錄,當滿足條件時(比如大小達到1TB),自動提交Spark批處理任務;讀取該批次文件,識別文件處理狀態,并寫元數據,處理完,更新該批次文件狀態,以此循環,將小時處理,調整為無固定周期的微批處理;當發現某小時數據處理完成時,提交hive表分區(注意:是否處理完我們調用采集接口,這里不做詳細描述)。
這種微批計算架構,通過充分利用時間和資源,在提升性能和吞吐量的同時,也提升了資源利用率。至此,我們降低了單次處理的數據量,比如:業務表單次處理數據量從百億下將到10億,但是,join多張大維表時shuffle量依然很大,耗時較長,資源消耗較高,這不是完美的解決方案,還需要在維表和join方式上持續優化。
維表的優化,將全局全量維表,修改為多個業務增量維表,降低Join維表數據量,以適當冗余存儲換Join效率。
因為維表都是公司級的全量表,數據在4~10億左右,且需要關聯2到3個不同維表,關聯方式是Sort Merge Join,會產生shuffle和Sort的開銷,效率很低。
圖片
因此,我們做了降低維表量級,調整Join模式兩個優化,降維表如下:
首先:基于業務表和維表,構建業務增量維表,維表數據量從億級下降到千萬級;
其次:所有維表都存儲在HBase,增量維表半年重新初始化一次(減少無效數據);
最后:Join時優先使用增量維表,少部分使用全量維表,并且每次計算都會更新增量維表。
接下來,調整業務表和維表的Join方式,首先,來看下原來大表關聯使用的Sort Merge Join的原理。
先讀取數據,基于SortShuffleManager機制,做內存排序,磁盤溢寫,磁盤文件合并等操作,然后,對每個分區的數據做排序,最后匹配關聯,可以有效解決大數據量關聯,不能全部內存Join的痛點。
而我們降低了業務表和維表的數據量,分區減少了,shuffle量自然也會減少,如果再把消耗比較大的分區排序去掉,就可以大大提升關聯性能。
而對于千萬級維表如果采用廣播方式,可能造成Driver端OOM,畢竟維表還是GB級別的,所以,采用Shuffle Hash Join方式是最佳方案。
最大的優點就是,就是將維表分區的數據加載到內存中,并且使用Map結構保存,Join時,通過get的方式遍歷,避免排序,簡單高效。
這樣,通過降低業務表和維表數據量,改變Join方式,相比較原來計算性能提升60%+,至此,離線計算性能問題得到解決,數據產出及時性也就迎刃而解。
2.5 數據完整性
在數據采集,實時ETL和離線ETL,寫ODS過程中,如何確保數據不丟,不錯,保持數據完整性 ?其挑戰主要有三個。
- 數據完整如何判定,比如A表數據量,下降20%?或者30%,表示不完整?很難統一定義,也是行業痛點。
- 出現問題,并且是異常,如何快速定位?
- 不完整的數據,給到下游用戶,成千上萬的任務都在使用錯誤的數據計算,影響面很大,故障恢復成本很高。
而這一切的基礎,都需要依賴元數據,因此,元數據收集成了很關鍵的工作,必須優先設計和建設,這里不展開講實時元數據的收集內容。
當有了豐富的元數據后,利用實時元數據,我們在鏈路中,增加了三層實時數據完整性對賬校驗,它們分別是:
- 數據采集,完整性對賬
- ETL處理,完整性對賬
- 組件輸出,完整性對賬
這樣,通過可視化輸出對賬結果,能夠快速定位和發現問題,定位時長從天級別下降到分鐘級別。
為了準確識別數據異常波動,我們結合業務特征,建設出了多種完整性校驗方法,并構建多功能交叉驗證體系,應用于數據校驗,主要有以下幾種校驗方案:
- 短周期內的同比和環比
- 基于歷史趨勢的算法校驗
- 基于數據時延的偶發漂移
- 基于節假日的數據起伏等
- 基于時間段的操作特征等
將這些驗證方案,交叉疊加應用到,不同的表和Topic,可以明顯提升異常發現的準確率,實際從85%提升到99%,如果出現異常告警,也會自動阻斷下游任務,這樣會大大降低對下游用戶的影響。
三、vivo 基礎數據架構總結展望
3.1 架構實踐總結
基礎數據架構應用諸多實踐,沒有全部詳細描述,有關業務痛點,用戶訴求,研發幸福感經過長期的建設,也取得了一些進步。
- 基礎數據架構,從單鏈路升級到流批存算分離雙活架構,多機房/集群/組件容災,基礎數據鏈路高可用。
- 實時計算,避免重復消費,數據按需分揀,構建低延時的計算架構,滿足數百萬并發處理請求。
- 離線計算,任務化整為零,數據分拆減量,計算降低過程開銷,存儲換性能,整體性能提升60%。
- 數據及時性,整體架構升級改造,數據處理量級從百億級到數萬億級,SLA及時率穩定保持在99.9%。
- 數據完整性,三層級實時對賬,多功能數據校驗,準確的監控告警,SLA完整性穩定99.9995%。
- 值班運維,得益于高可用架構和鏈路,高性能計算,起夜值班天數從月均20+下降到月均5天以內。
而數據壓縮,數據安全,數據易用性,便捷性,在過程中都有涉及,只是沒有詳細講述。
3.2 架構迭代規劃
打造更敏捷高效,低成本的湖倉一體大數據計算架構。
- 離線采集,重點解決源端宕機數據丟失問題,因為當前部分數據離線采集,端側服務器宕機,可能會有數據丟失風險。
- 離線計算,重點解決Shuffle問題,從ESS切到RSS,實現Shuffle數據的存儲和計算分離,解決ESS服務的性能問題。
- 實時運維,提升異常發現和處理的智能化水平,重點是實時元數據的捕獲與歸因分析,解決實時運維中定位難,處理時間要求短的問題。
- 實時計算,將聯合相關團隊,構建更敏捷高效,低成本的,湖倉一體化大數據計算架構。