Flink在快手實時多維分析場景的應用


分享嘉賓:董亭亭、徐明 快手

編輯整理:王洪達

內容來源:Flink Forward Asia

出品平臺:Flink中文社區、DataFunTalk

導讀:作爲短視頻分享跟直播的平臺,快手有諸多業務場景應用了 Flink,包括短視頻、直播的質量監控、用戶增長分析、實時數據處理、直播 CDN 調度等。此次主要介紹在快手使用 Flink 在實時多維分析場景的應用與優化。

主要內容包括:

  • Flink 在快手應用場景及規模

  • 快手實時多維分析平臺

  • SlimBase-更省 IO、嵌入式共享 state 存儲

01

Flink 在快手應用場景及規模

首先看 Flink 在快手的應用場景和規模。

1. 快手應用場景


快手計算鏈路是從 DB/Binlog 以及 WebService Log 實時入到 Kafka 中,然後接入 Flink 做實時計算,其中包括實時數倉、實時分析以及實時訓練,最後的結果存到 Druid、Kudu、HBase 或者 ClickHouse 裏面;同時 Kafka 數據實時 Dump 一份到 Hadoop 集羣,然後通過 Hive、MapReduce 或者 Spark 來做離線計算;最終實時計算和離線計算的結果數據會用內部自研 BI 工具 KwaiBI 來展現出來。

Flink 在快手典型的應用場景主要分爲三大類:

  • 80% 統計監控:實時統計,包括各項數據的指標,監控項報警,用於輔助業務進行實時分析和監控;

  • 15% 數據處理:對數據的清洗、拆分、Join 等邏輯處理,例如大 Topic 的數據拆分、清洗;

  • 5% 數據處理:實時業務處理,針對特定業務邏輯的實時處理,例如實時調度。

Flink 在快手應用的典型場景案例包括:

  • 快手是分享短視頻跟直播的平臺,快手短視頻、直播的質量監控是通過 Flink 進行實時統計,比如直播觀衆端、主播端的播放量、卡頓率、開播失敗率等跟直播質量相關的多種監控指標;

  • 用戶增長分析,實時統計各投放渠道拉新情況,根據效果實時調整各渠道的投放量;

  • 實時數據處理,廣告展現流、點擊流實時 Join,客戶端日誌的拆分等;

  • 直播 CDN 調度,實時監控各 CDN 廠商質量,通過 Flink 實時訓練調整各個 CDN 廠商流量配比。

2. Flink 集羣規模

快手目前集羣規模有 1500 臺左右,日處理條目數總共有3萬億,峯值處理條目數大約是 3億/s 左右。集羣部署都是 On Yarn 模式,實時集羣和離線集羣混合部署,通過 Yarn 標籤進行物理隔離,實時集羣是 Flink 專用集羣,針對隔離性、穩定性要求極高的業務部署。注:本文所涉及數據僅代表嘉賓分享時的數據。

02

快手實時多維分析平臺

此處重點和大家分享下快手的實時多維分析平臺。

1. 快手實時多維分析場景

快手內部有這樣的應用場景,每天的數據量在百億級別,業務方需要在數據中任選五個以內的維度組合進行全維的建模進而計算累計的 PV ( Page View 訪問量 )、UV ( Unique Visitor 獨立訪客 )、新增或者留存等這樣的指標,然後指標的計算結果要實時進行圖形化報表展示供給業務分析人員進行分析。

2. 方案選型

現在社區已經有一些 OLAP 實時分析的工具,像 Druid 和 ClickHouse;目前快手採用的是 Flink+Kudu 的方案,在前期調研階段對這三種方案從計算能力、分組聚合能力、查詢併發以及查詢延遲四個方面結合實時多維查詢業務場景進行對比分析:

  • 計算能力方面:多維查詢這種業務場景需要支持 Sum、Count 和 count distinct 等能力,而 Druid 社區版本不支持 count distinct,快手內部版本支持數值類型、但不支持字符類型的 count distinct;ClickHouse 本身全都支持這些計算能力;Flink 是一個實時計算引擎,這些能力也都具備。

  • 分組聚合能力方面:Druid 的分組聚合能力一般,ClickHouse 和 Flink 都支持較強的分組聚合能力。

  • 查詢併發方面:ClickHouse 的索引比較弱,不能支持較高的查詢併發,Druid 和 Flink 都支持較高的併發度,存儲系統 Kudu,它也支持強索引以及很高的併發。

  • 查詢延遲方面:Druid 和 ClickHouse 都是在查詢時進行現計算,而 Flink+Kudu 方案,通過 Flink 實時計算後將指標結果直接存儲到 Kudu 中,查詢直接從 Kudu 中查詢結果而不需要進行計算,所以查詢延遲比較低。

採用 Flink+Kudu 的方案主要思想是借鑑了 Kylin 的思路,Kylin 可以指定很多維度和指標進行離線的預計算然後將預計算結果存儲到 HBase 中;快手的方案是通過 Flink 實時計算指標,再實時地寫到 Kudu 裏面。

3. 方案設計

實時多維分析的整體的流程爲:用戶在快手自研的 BI 分析工具 KwaiBI 上配置 Cube 數據立方體模型,指定維度列和指標列以及基於指標做什麼樣的計算;配置過程中選擇的數據表是經過處理過後存儲在實時數倉平臺中的數據表;然後根據配置的計算規則通過 Flink 任務進行建模指標的預計算,結果存儲到 Kudu 中;最後 KwaiBI 從 Kudu 中查詢數據進行實時看板展示。

接下來詳細介紹一下實時多維分析的主要模塊。

① 數據預處理

KwaiBI 配置維度建模時選擇的數據表,是經過提前預處理的:

  • 首先內部有一個元信息系統,在元信息系統中提供統一的 schema 服務,所有的信息都被抽象爲邏輯表;

  • 例如 Kafka 的 topic、Redis、HBase 表等元數據信息都抽取成 schema 存儲起來;

  • 快手 Kafka 的物理數據格式大部分是 Protobuf 和 Json 格式,schema 服務平臺也支持將其映射爲邏輯表;

  • 用戶只需要將邏輯表建好之後,就可以在實時數倉對數據進行清洗和過濾。

② 建模計算指標

數據預處理完成後,最重要的步驟是進行建模指標計算,此處支持 Cube、GroupingSet 方式維度組合來計算小時或者天累計的 UV ( Unique Visitor )、新增和留存等指標,可以根據用戶配置按固定時間間隔定期輸出結果;維度聚合邏輯中,通過逐層降維計算的方式會讓 DAG 作業圖十分複雜,如上圖右上角模型所示;因此快手設計了兩層降維計算模型,分全維度層和剩餘維度層,這樣既利用了全維度層的聚合結果又簡化了 DAG 作業圖。

以 UV 類指標計算舉例,兩個黃色虛線框分別對應兩層計算模塊:全維計算和降維計算。

  • 全維計算分爲兩個步驟,爲避免數據傾斜問題,首先是維度打散預聚合,將相同的維度值先哈希打散一下。因爲 UV 指標需要做到精確去重,所以採用 Bitmap 進行去重操作,每分鐘一個窗口計算出增量窗口內數據的 Bitmap 發送給第二步按維度全量聚合;在全量聚合中,將增量的 Bitmap 合併到全量 Bitmap 中最終得出準確的 UV 值。然而有人會有問題,針對用戶 id 這種的數值類型的可以採用此種方案,但是對於 deviceid 這種字符類型的數據應該如何處理?實際上在源頭,數據進行維度聚合之前,會通過字典服務將字符類型的變量轉換爲唯一的 Long 類型值,進而通過 Bitmap 進行去重計算 UV。

  • 降維計算中,通過全維計算得出的結果進行預聚合然後進行全量聚合,最終將結果進行輸出。

再重點介紹下,建模指標計算中的幾個關鍵點。在建模指標計算中,爲了避免維度數據傾斜問題,通過預聚合 ( 相同維度 hash 打散 ) 和全量聚合 ( 相同維度打散後聚合 ) 兩種方式來解決;爲了解決 UV 精確去重問題,前文有提到,使用 Bitmap 進行精確去重,通過字典服務將 String 類型數據轉換成 Long 類型數據進而便於存儲到 Bitmap 中,因爲統計 UV 要統計歷史的數據,比如說按天累計,隨着時間的推移,Bitmap 會越來越大,在 Rocksdb 狀態存儲下,讀寫過大的 KV 會比較耗性能,所以內部自定義了一個 BitmapState,將 Bitmap 進行分塊存儲,一個 blockid 對應一個局部的 bitmap,這樣在 RocksDB 中存儲時,一個 KV 會比較小,更新的時候也只需要根據 blockid 更新局部的 bitmap 就可以而不需要全量更新。

接下來,看新增類的指標計算,和剛剛 UV 的不同點是需要判斷是否爲新增用戶,通過異步地訪問外部的歷史用戶服務進行新增用戶判斷,再根據新增用戶流計算新增 UV,這塊計算邏輯和 UV 計算一致。

然後,再來看留存類指標計算,與 UV 計算不同的時候,不僅需要當天的數據還需要前一天的歷史數據,這樣才能計算出留存率,內部實現的時候是採用雙 buffer state 存儲,在計算的時候將雙 buffer 數據相除就可以計算出留存率。

③ Kudu 存儲

最後經過上面的計算邏輯後,會將結果存儲到 Kudu 裏面,其本身具有低延遲隨機讀寫以及快速列掃描等特點,很適合實時交互分析場景;在存儲方式上,首先對維度進行編碼,然後按時間+維度組合+維度值組合作爲主鍵,最終按維度組合、維度值組合、時間進行分區,這樣有利於提高查詢的效率快速獲取到數據。

4. KwaiBI 展示

界面爲配置 Cube 模型的截圖,配置一些列並指定類型,再通過一個 SQL 語句來描述指標計算的邏輯,最終結果也會通過 KwaiBI 展示出來。

03

SlimBase

更省 IO、嵌入式共享 state 存儲

接下來介紹一種比 RocksDB 更省 IO、嵌入式的共享 state 存儲引擎:SlimBase。

1. 面臨的挑戰

首先看一下 Flink 使用 RocksDB 遇到的問題,先闡述一下快手的應用場景、廣告展現點擊流實時 Join 場景:打開快手 App 可能會收到廣告服務推薦的廣告視頻,用戶可能會點擊展現的廣告視頻。這樣的行爲在後端會形成兩份數據流,一份是廣告展現日誌,一份是客戶端點擊日誌。這兩份數據進行實時 Join,並將 Join 結果作爲樣本數據用於模型訓練,訓練出的模型會被推送到線上的廣告服務。該場景下展現以後20分鐘的點擊被認爲是有效點擊,實時 Join 邏輯則是點擊數據 Join 過去20分鐘內的展現。其中,展現流的數據量相對比較大,20分鐘數據在 1TB 以上。檢查點設置爲五分鐘,Backend 選擇 RocksDB。

在這樣的場景下,面臨着磁盤 IO 開銷70%,其中50%開銷來自於 Compaction;在 Checkpoint 期間,磁盤 IO 開銷達到了100%,耗時在1~5分鐘,甚至會長於 Checkpoint 間隔,業務能明顯感覺到反壓。經過分析找出問題:

  • 首先,在 Checkpoint 期間會產生四倍的大規模數據拷貝,即:從 RocksDB 中全量讀取出來然後以三副本形式寫入到 HDFS 中;

  • 其次,對於大規模數據寫入,RocksDB 的默認 Level Compaction 會有嚴重的 IO 放大開銷。

2. 解決方案

由於出現上文闡述的問題,開始尋找解決方案,整體思路是在數據寫入時直接落地到共享存儲中,避免 Checkpoint 帶來的數據拷貝問題。手段是嘗試使用更省 IO 的 Compaction,例如使用 SizeTieredCompation 方式,或者利用時序數據的特點使用並改造 FIFOCompaction。綜合比較共享存儲、SizeTieredCompation、基於事件時間的 FIFOCompaction 以及技術棧四個方面得出共識:HBase 代替 RocksDB 方案。

  • 共享存儲方面,HBase 支持, RocksDB 不支持

  • SizeTieredCompation 方面,RocksDB 默認不支持,但 HBase 默認支持,開發起來比較簡單

  • 基於事件時間下推的 FIFOCompaction 方面,RocksDB 不支持,但 HBase 開發起來比較簡單

  • 技術棧方面,RocksDB 使用 C++,HBase 使用 java,HBase 改造起來更方便

但是 HBase 有些方面相比 RocksDB 較差:

  • HBase 是一個依賴 zookeeper、包含 Master 和 RegionServer 的重量級分佈式系統;而 RocksDB 僅是一個嵌入式的 Lib 庫,很輕量級。

  • 在資源隔離方面,HBase 比較困難,內存和 cpu 被多個 Container 共享;而 RocksDB 比較容易,內存和 cpu 伴隨 Container 天生隔離。

  • 網絡開銷方面,因爲 HBase 是分佈式的,所有比嵌入式的 RocksDB 開銷要大很多。

綜合上面幾點原因,快手達成了第二個共識,將 HBase 瘦身,改造爲嵌入式共享存儲系統。

3. 實現方案

接下來介紹一下將 HBase 改造成 SlimBase 的實現方案,主要是分爲兩層:

  • 一層是 SlimBase 本身,包含三層結構:Slim HBase、適配器以及接口層;

  • 另一層是 SlimBaseStateBackend,主要包含 ListState、MapState、ValueState 和 ReduceState。

後面將從 HBase 瘦身、適配並實現操作接口以及實現 SlimBaseStateBackend 三個步驟分別進行詳細介紹。

① HBase 瘦身

先講 HBase 瘦身,主要從減肥和增瘦兩個步驟,在減肥方面:

  • 先對 HBase 進行減裁,去除 client、zookeeper 和 master,僅保留 RegionServer

  • 再對 RegionServer 進行剪裁,去除 ZK Listener、Master Tracker、Rpc、WAL 和 MetaTable

  • 僅保留 RegionServer 中的 Cache、Memstore、Compaction、Fluster 和 Fs

在增瘦方面:

  • 將原來 Master 上用於清理 Hfile 的 HFileCleaner 遷移到 RegionServer 上

  • RocksDB 支持讀放大寫的 merge 接口,但是 SlimBase 是不支持的,所以要實現 merge 的接口

接口層主要有以下三點實現:

  • 仿照 RocksDB,邏輯視圖分爲兩級:DB 和 ColumnFamily

  • 支持一些基本的接口:put/get/delete/merge 和 snapshot

  • 額外支持了 restore 接口,用於從 snapshot 中恢復

適配層主要有以下兩個概念:

  • 一個 SlimBase 適配爲 Hbase 的 namespace

  • 一個 SlimBase 的 ColumnFamily 適配爲 HBase 的 table

SlimBaseStateBackend 實現上主要體現在兩個方面:

  • 一是多種 States 實現,支持多種數據結構,ListState、MapState、ValueState 和 ReduceState

  • 二是改造 Snapshot 和 Restore 的流程,從下面的兩幅圖可以看出,SlimBase 在磁盤 IO 上節省了大量的資源,避免了多次的 IO 的問題。

4. 測試結論

上線對比測試後,得出測試結論:

  • Checkpoint 和 Restore 的時延從分鐘級別降到秒級。

  • 磁盤 IO 下降了66%

  • 磁盤寫吞吐下降50%

  • CPU 開銷下降了33%

5. 後期優化

目前用的 Compaction 策略是 SizeTieredCompaction,後期要實現基於 OldestUnexpiredTime 的 FiFOCompaction 策略,目標是做到無磁盤 IO 開銷。

FiFOCompaction 是一種基於 TTL 的無 IO 的 Compaction 策略;OldestUnexpiredTime 是指例如設置 OldestUnexpiredTime=t2,表示 t2 時刻前的數據全部過期,可以被 Compaction 清理,基於時間點的 FIFOCompaction 理論上可以做到無磁盤 IO 開銷。

後續還有四點優化,前三點是基於 HBase 的優化,最後是針對 HDFS 做的優化:

  • SlimBase 使用 InMemoryCompaction,降低內存 Flush 和 Compaction 開銷

  • SlimBase 支持 prefixBloomFilter,提高 Scan 性能

  • SlimBase 支持短路讀

  • HDFS 副本落盤改造:非本地副本使用 DirectIO 直接落盤,提高本地讀 pagecache 命中率;此條主要是在測試使用時發現單副本比多副本讀寫效率高這一問題

6. 未來規劃

從語言、存儲、壓縮策略、事件事件下推、垃圾回收、檢查點時間、重加載時間七個方面來看,SlimBase 都比 RocksDB 更適合快手實時計算任務的開發,未來的規劃是對 SlimBase 的性能做進一步優化,願景是將快手 Flink 上的所有業務場景全部用 SlimBase 替代掉 RocksDB。

分享嘉賓:

董亭亭,快手實時計算引擎團隊負責人。

徐明,快手大數據架構研發工程師。

今天的分享就到這裏,謝謝大家。


如果您喜歡本文,歡迎點擊右上角,把文章分享到朋友圈~~

猜你喜歡

1、剛剛晉升爲 Apache 頂級項目的 Hudi 如何在數據湖上玩轉增量處理

2、Apache Spark 在eBay 的優化

3、Elasticsearch如何做到億級數據查詢毫秒級返回?

4、大數據平臺架構設計沒思路?來看這篇就知道了!

過往記憶大數據微信羣,請添加微信:fangzhen0219,備註【進羣】

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章