天天看點

基于 Flink + ClickHouse 打造輕量級點選流實時數倉

作者:LittleMagic

Flink 和 ClickHouse 分别是實時計算和(近實時)OLAP 領域的翹楚,也是近些年非常火爆的開源架構,很多大廠都在将兩者結合使用來建構各種用途的實時平台,效果很好。關于兩者的優點就不再贅述,本文來簡單介紹筆者團隊在點選流實時數倉方面的一點實踐經驗。

點選流及其次元模組化

所謂點選流(click stream),就是指使用者通路網站、App 等 Web 前端時在後端留下的軌迹資料,也是流量分析(traffic analysis)和使用者行為分析(user behavior analysis)的基礎。點選流資料一般以通路日志和埋點日志的形式存儲,其特點是量大、次元豐富。以我們一個中等體量的普通電商平台為例,每天産生約 200GB 左右、數十億條的原始日志,埋點事件 100+ 個,涉及 50+ 個次元。

按照 Kimball 的次元模組化理論,點選流數倉遵循典型的星形模型,簡圖如下。

基于 Flink + ClickHouse 打造輕量級點選流實時數倉

點選流數倉分層設計

點選流實時數倉的分層設計仍然可以借鑒傳統數倉的方案,以扁平為上策,盡量減少資料傳輸中途的延遲。簡圖如下。

基于 Flink + ClickHouse 打造輕量級點選流實時數倉
  • DIM 層:次元層,MySQL 鏡像庫,存儲所有次元資料。
  • ODS 層:貼源層,原始資料由 Flume 直接進入 Kafka 的對應 topic。
  • DWD 層:明細層,通過 Flink 将 Kafka 中資料進行必要的 ETL 與實時次元 join 操作,形成規範的明細資料,并寫回 Kafka 以便下遊與其他業務使用。再通過 Flink 将明細資料分别寫入 ClickHouse 和 Hive 打成大寬表,前者作為查詢與分析的核心,後者作為備份和資料品質保證(對數、補數等)。
  • DWS 層:服務層,部分名額通過 Flink 實時彙總至 Redis,供大屏類業務使用。更多的名額則通過 ClickHouse 物化視圖等機制周期性彙總,形成報表與頁面熱力圖。特别地,部分明細資料也在此層開放,友善進階 BI 人員進行漏鬥、留存、使用者路徑等靈活的 ad-hoc 查詢,這些也是 ClickHouse 遠超過其他 OLAP 引擎的強大之處。

要點與注意事項

Flink 實時次元關聯

Flink 架構的異步 I/O 機制為使用者在流式作業中通路外部存儲提供了很大的便利。針對我們的情況,有以下三點需要注意:

  • 使用異步 MySQL 用戶端,如 Vert.x MySQL Client。
  • AsyncFunction 内添加記憶體緩存(如 Guava Cache、Caffeine 等),并設定合理的緩存驅逐機制,避免頻繁請求 MySQL 庫。
  • 實時次元關聯僅适用于緩慢變化次元,如地理位置資訊、商品及分類資訊等。快速變化次元(如使用者資訊)則不太适合打進寬表,我們采用 MySQL 表引擎将快變次元表直接映射到 ClickHouse 中,而 ClickHouse 支援異構查詢,也能夠支撐規模較小的維表 join 場景。未來則考慮使用 MaterializedMySQL 引擎(目前仍未正式釋出)将部分次元表通過 binlog 鏡像到 ClickHouse。

Flink-ClickHouse Sink 設計

可以通過 JDBC(flink-connector-jdbc)方式來直接寫入 ClickHouse,但靈活性欠佳。好在 clickhouse-jdbc 項目提供了适配 ClickHouse 叢集的 BalancedClickhouseDataSource 元件,我們基于它設計了 Flink-ClickHouse Sink,要點有三:

  • 寫入本地表,而非分布式表,老生常談了。
  • 按資料批次大小以及批次間隔兩個條件控制寫入頻率,在 part merge 壓力和資料實時性兩方面取得平衡。目前我們采用 10000 條的批次大小與 15 秒的間隔,隻要滿足其一則觸發寫入。
  • BalancedClickhouseDataSource 通過随機路由保證了各 ClickHouse 執行個體的負載均衡,但是隻是通過周期性 ping 來探活,并屏蔽掉目前不能通路的執行個體,而沒有故障轉移——亦即一旦試圖寫入已經失敗的節點,就會丢失資料。為此我們設計了重試機制,重試次數和間隔均可配置,如果當重試機會耗盡後仍然無法成功寫入,就将該批次資料轉存至配置好的路徑下,并報警要求及時檢查與回填。

目前我們僅實作了 DataStream API 風格的 Flink-ClickHouse Sink,随着 Flink 作業 SQL 化的大潮,在未來還計劃實作 SQL 風格的 ClickHouse Sink,打磨健壯後會适時回饋給社群。另外,除了随機路由,我們也計劃加入輪詢和 sharding key hash 等更靈活的路由方式。

還有一點就是,ClickHouse 并不支援事務,是以也不必費心考慮 2PC Sink 等保證 exactly once 語義的操作。如果 Flink 到 ClickHouse 的鍊路出現問題導緻作業重新開機,作業會直接從最新的位點(即 Kafka 的 latest offset)開始消費,丢失的資料再經由 Hive 進行回填即可。

ClickHouse 資料重平衡

ClickHouse 叢集擴容之後,資料的重平衡(reshard)是一件麻煩事,因為不存在類似 HDFS Balancer 這種開箱即用的工具。一種比較簡單粗暴的思路是修改 ClickHouse 配置檔案中的 shard weight,使新加入的 shard 多寫入資料,直到所有節點近似平衡之後再調整回來。但是這會造成明顯的熱點問題,并且僅對直接寫入分布式表才有效,并不可取。

是以,我們采用了一種比較曲折的方法:将原表重命名,在所有節點上建立與原表 schema 相同的新表,将實時資料寫入新表,同時用 clickhouse-copier 工具将曆史資料整體遷移到新表上來,再删除原表。當然在遷移期間,被重平衡的表是無法提供服務的,仍然不那麼優雅。如果大佬們有更好的方案,歡迎交流。

結語

關于 Flink 和 ClickHouse 等元件的配置、調優、延遲監控、權限管理等知識,筆者在之前的部落格中多少講到過,更多詳情請見作者原文連結:

https://www.jianshu.com/p/bedead165403

來源: Flink 中文社群 微信公衆号

原文連結:

https://mp.weixin.qq.com/s/rn9qWvvhY3KxKKwUCgQ4HQ