蘇寧6億會員是如何做到精確快速分析的?

隨着蘇寧業務的高速發展,大數據平臺對海量的業務數據分析越來越具有挑戰,尤其是在精確去重、複雜 JOIN 場景下,如用戶畫像、UV、新老買家、留存、流失用戶等。

圖片來自 Pexels

隨着蘇寧業務的高速發展,大數據平臺對海量的業務數據分析越來越具有挑戰,尤其是在精確去重、複雜 JOIN 場景下,如用戶畫像、UV、新老買家、留存、流失用戶等。

蘇寧大數據平臺目前 OLAP 分析的總體架構是將時序化的數據採用 Druid+ClickHouse、非時序化採用 PostGreSQL、固化場景採用 Hbase+phoenix、明細數據採用 Elasticsearch 分析。

基於 Druid 我們有 HyperLogLog 非精確去重算法,具有非常優異的空間複雜度 O(m log2log2N),空間的佔用隨着基數的增長變化不大,但統計存在一定的偏差。

基於其他引擎我們常用的精確去重算法一般是 GROUP BY 後 count distinct 操作,GROUP BY 會帶來大量的 shuffle 操作,佔用大量的磁盤和 IO,其性能較爲低下。

下面將爲大家揭開蘇寧如何整合 RoaringBitmap 進行高效精確去重架構方案的神祕面紗。

RoaringBitmap 在蘇寧的應用實踐

爲何選擇 RoaringBitmap

首先簡單爲大家介紹下 RoaringBitmap,32 位的 RoaringBitmap 的是由高 16 位的 Key 和低 16 位的 Value 組成,Key 和 Value 通過下標一一對應。

Key 數組保持有序存儲在 roaring_array_t 中,方便二分查找。低 16 位的 Value 存儲在 Container 中,Container 共有三種。

RoaringBitmap 對創建何種 Container 有自己的優化策略,在默認創建或元素個數小於 4096 的時候創建的是 Array Container。

它是動態擴容的數組,適合存放稀疏數據,超過最大容量 4096 時,會自動轉換爲 Bitmap Container。

當元素超過 4096 時 Array Container 的大小佔用是會線性增長,但是 Bitmap Container 的內存空間並不會增長,始終還是佔用 8 K。

還有一種是 Run Container,只有在調用 runOptimize() 方法纔會觸發,會和 ArrayContainer、BitmapContainer 比較空間佔用大小,然後選擇是否轉換。

Run Container 佔用的存儲大小看數據的連續性,上下限範圍 [4 Bytes, 128 KB]。

近年來,大數據技術得到了快速的發展,各種開源技術給大數據開發人員帶來了很大的便利,在衆多的技術中之所以選擇 RoaringBitmap,是因爲它的存儲空間低和運算效率高。

RoaringBitmap 的存儲是通過 bit 來標識狀態,經過壓縮後存儲,據估算蘇寧 6 億會員如果是常規的數組來存儲佔用空間約爲 2.2G,而 RoaringBitmap 存儲僅需要 66MB,大大降低的存儲的空間,降低企業的成本。

RoaringBitmap 是通過位運算(如 AND、OR、ANDNOT 等)進行的,在計算能力上也相當驚人。

我們在基於 PostGresql+Citus 做過與 count distinct 的對比測試,發現 RoaringBitmap 的統計耗時是 count distinct 的近 1/50。

原生的 RoaringBitmap 只存儲整形數據,32 位的 RoaringBitmap 最大的數據存儲量是 2147483647。

對於會員之類的可以採用,像訂單、流量這樣的數據量可以採用 64 位的 RoaringBitmap,在性能上 32 位的效率在同等條件下要優於 64 位。

蘇寧擁有海量的業務數據,每天都有大量的離線和實時計算任務,採用 RoaringBitmap 技術不僅大大節約了存儲的成本,計算的效率也得到了顯著的改善。

應用場景

①會員相關指標計算

RoaringBitmap 在會員相關指標的分析中有着許多重要的應用場景,比如會員的新、老買家、留存、復購、活躍這些指標均要用到精確去重的統計方式。

蘇寧目前有 6 億會員,像新、老買家這樣的指標計算都是拿當前的買家與全量的歷史買家進行比對,如何快速的精確的分析出計算結果,在沒有引入 RoaringBitmap 之前是一個較大的挑戰。

②精確營銷

給目標用戶羣推送優惠的商品提高公司的銷售額已經是電商公司採用普遍的精準營銷手段。

但是如何在海量的用戶行爲日誌中第一時間進行人羣構建、客羣洞察、再到精準地廣告投放是有一定難度的。

如果採用離線計算方案其時效性不能保障,可能在這期間就丟失了目標客戶,在此場景下,高效、精確的計算出目標人羣尤爲重要。

在引入 RoaringBitmap 後,在海量的數據中對受衆人羣進行全面深入的畫像,精準投放廣告,最終幫助企業構建了完整的數字化營銷閉環。

基於 PostgreSQL 實現的 RoaringBitmap

蘇寧在對非時序化的海量數據進行分析的場景,採用的是分佈式 HTAP 數據庫 PostgreSQL+Citus 的架構方案。

我們將 RoaringBitmap 與 Citus 做了整合,將 RoaringBitmap 融合進了 Citus 集羣,而具體的體現就是表中的一個 bitmap 列,如下圖所示:

下面簡單介紹下以 PostgreSQL+Citus +RoaringBitmap 的技術架構方案來實現會員新、老買家的場景。

數據字典

在進行 RoaringBitmap 的存儲和計算的之前,我們首先要構建一個全局字典表,此表就是將要轉化的維度維值跟 int 或 long 進行一個映射關係。

將這個映射關係存儲在全局字典表中,RoaringBitmap 的 32 位和 64 位選擇根據實際的數據量進行抉擇。

流程設計

整體的設計流程可分爲三步:

  • 模型創建

  • 數據攝入

  • 數據分析

數據模型創建流程圖

模型創建流程如上圖:

模型的創建、數據初始化、以及查詢我們採用的基於 Citus 的存儲過程實現方式,經測試基於存儲過程的方式比常用的 SQL 方式在性能方面有所提升。

分片表設計:模型中的元素是有維度、指標、bitmap 組成,Citus 目前支持三種類型的表,分別爲本地表、參考表以及分片表,分別應用在不同的場景。

Citus 支持 Hash 和 Append 的方式進行分片,以新老買家爲例,我們以會員的 member_id 進行 Hash 分片。

分片表設計的不僅解決了 T 級別的數據存儲問題,也可以根據分片進行並行計算最後再彙總,提高計算效率。

Cube_bitmap 表的創建是基於模型的,在後臺我們有收集用戶的查詢方式,根據採集的樣本數據我們會根據 Cost 自動的創建 Cube 用於加速。

數據分析的數據源我們會根據 Cost 計算從預計算結果、Cube_bitmap 或模型 bitmap 表中獲取。

 數據攝入流程圖

數據攝入流程如上圖:

數據字典同步:全量和增量的模型攝入時候需要同步更新全局字典表。

模型 bitmap 表邏輯處理(以會員爲例):

第一步:模型表和字典表通過設置的業務主鍵 Key 進行關聯。

第二步:獲取模型增量維度對應的會員 bitmap 數據信息,可根據 rb_or_agg(rb_build(ARRAY [b.id :: INT])) 獲取 。

第三步:將模型 bitmap 表裏當天的 (flag=1) 和前一天 (flag=2) 統計的 bitmap 數據進行 rb_or_agg(bitmap) 操作,數據整合後作爲當天的 flag=2 數據插入到 bitmap 表中。

第四步:日全量統計表只有 flag+statis_date+bitmap 字段,主要統計當天的用戶和歷史用戶 bitmap 情況,統計 flag=1 的當天 bitmap 數據。

模型 bitmap 表與會員表進行關聯 bitmap 取 rb_or_agg(rb_build(ARRAY[b.id :: INT]))。

第五步:日全量統計表統計 flag=2 的當天 bitmap 數據,從自身表中獲取當天 flag=1 和昨天統計的 flag=2 的數據然後做 rb_or_agg(bitmap)。

Cube_bitmap、預聚合結果表的源來自於數據模型表,在此基礎上做加速處理。

數據查詢流程圖

數據分析如上圖:

根據要查詢的維度進行 Cost 分析判斷,最終路由到預計算結果表、Cube_bitmap 表、模型表進行數據分析。

從模型 bitmap 表或 cube_bitmap 表獲取 bitmap_cur 和 bitmap_sum,從全量 bitmap 表中獲取 bitmap_all 數據(flag=2 並且日期是查詢日期的前一天)。

後續的 bitmap 位運算可在 bitmap_cur、bitmap_sum 和 bitmap_all 中進行。

應用舉例

①業務場景

業務場景如下圖:

②設計方案

第一步:將買家的 ID 作爲數據字典的信息,與對應的 int 或 long 形成關係映射存入全局字典表。

第二步:統計每天的線上、線下的新老買家,統計維度根據渠道(線上和線下)+tag(1 當天 2 歷史)+日期。

每天有兩條統計信息,一個是當天的用戶買家 bitmap 集合,一個是歷史的用戶買家 bitmap 集合。

第二天統計基於第一天統計的集合和當天的集合做 rb_or_agg,形成一個新的當天曆史 bitmap 集合(結果存儲在 Bitmap_Table_A)。

第三步:基於統計維度(品類+渠道)+tag+日期來統計新老買家情況,每天也會有兩條統計信息,一個是當天的一個是歷史的,當天統計的是所有的品類和渠道做的 group by 統計,統計 bitmap 集合打上標籤爲 flag=1,歷史 flag=2 是基於前一天曆史加上當天統計的集合做 rb_or_agg,形成一個新的當天曆史 bitmap 集合(結果存儲在 Bitmap_Table_B)。

③場景分析

場景一:0428 線上新買家

統計 0428 線上新買家實則就是 bitmap 集合 {A,D} 和 bitmap 集合 {A,C} 進行 rb_andnot_cardinality 位運算,結果爲 {D},新買家的數量爲 1。

場景二:0428 線上空調新買家

統計 0428 線上空調新買家則就是 bitmap 集合 {C ,A} 和 bitmap 集合 {C} 進行 rb_andnot_cardinality 位運算,結果爲 {A},新買家的數量爲 1。

0428 線上冰洗新買家則是 bitmap 集合 {D} 和 bitmap 空集合做 rb_andnot_cardinality 位運算,結果爲 {D},數量爲 1。

場景三:0428 線上空調新買家中有多少是線上新買家

統計則根據和 Bitmap_Table_A 和 Bitmap_Table_B 做 rb_and_cardinality 操作,則拿 bitmap 集合 {A} 和 bitmap 集合 {{A,C}} 進行 rb_andnot_cardinality 位運算,結果爲空集,數量爲 0。

0428 線上冰洗新買家則根據 bitmap 集合 {D} 和 bitmap 集合 {A,C} 進行 rb_andnot_cardinality 位運算,運算結果 bitmap 集合爲 {D},數量爲 1。

0428 線上新買家品類分佈即爲:基於 Bitmap_Table_B 表,0428 線上品類有冰洗 {D} 和空調 {A},基於 Bitmap_Table_A 表統計線上歷史買家爲 {A,C}。

線上新買家冰洗則拿 {D} 和 {A,C} 做 rb_andnot_cardinality 後的集合爲 {D},數量爲 1。

線上新買家空調則是拿 {A} 和 {A,C} 做 rb_andnot_cardinality 後的集合爲空集,數量爲 0。

不足與挑戰

基於 PostgreSQL+Citus 的 RoaringBitmap 技術方案,bitmap 集合之間的位運算性能表現的較爲卓越,但在很多業務場景需要高基數的 bitmap 集合進行位運算。

基於 Citus 我們分析發現,在位運算的時候 CPU 利用率處於低位,後期我們也針對基於 Citus 做了優化。

如 bitmap 下壓到 Work 運算降低 CN 運算量,創建 cube 降低基數,在一定的程度了提高了效率,然在 Ctius 下的 CPU 始終沒有得到充分利用。

ClickHouse 的併發 MPP+SMP 這種執行方式可以很充分地利用機器的集成資源,但當時看了 ClickHouse 還沒有提供 bitmap 相關的接口,不能直接加以應用,如何將 RoaringBitmap 融合到 ClickHouse 是一個挑戰。

RoaringBitmap 與 ClickHouse 的整合

在計算引擎中 ClickHouse 算是後起之秀,是一個列導向數據庫,原生的向量化執行引擎,其存儲是採用 Wired Tiger 的 LSM 引擎。

目前蘇寧的大數據已將 ClickHouse 引入並改造,開發了相關的 RoaringBitmap 接口, 用來支撐業務交互式查詢。

基於 ClickHouse 的 RoaringBitmap 方案計算過程大幅簡化,查詢時候的 IO、CPU、MEM、網絡資源都顯著降低,並且不隨着數據規模而現行增加。

基於 ClickHouse 我們開發了 RoaringBitmap 相關的接口,其支持的 Function 函數有:

  • bitmapBuild

  • bitmapToArray

  • bitmapMax

  • bitmapMin

  • bitmapAnd

  • bitmapOr

  • bitmapXor

  • bitmapAndnot

  • bitmapCardinality

  • bitmapAndCardinality

  • bitmapOrCardinality

  • bitmapAndnotCardinality 

它們用於支撐各種場景的運算,其相關的接口開發還在不斷的完善中。

未來展望

爲了將基於 ClickHouse 的 RoaringBitmap 方案推廣到公司的更多業務和場景中,我們在做不斷優化和完善。

目前正着手於以下的嘗試:

  • ClickHouse 目前不支持 64 位的 bitmap,正在嘗試按 hash 值進行分區,每個分區單獨計算,可輕易將分區進行橫向疊加支持到 long 長度。

  • 全局字典表在高基數下構建成本較大,佔用較多資源也耗時較大,後續可根據業務場景將數據字典表最大程度複用,同時考慮在無需跨 segment 聚合時候,適用這個列的 segment 字典替代。

  • 全鏈路監控的完善,可根據 query_id 進行各個環節的耗時分析,便於優化和問題的定位。

作者:範東

簡介:蘇寧科技集團大數據中心架構師,在 OLAP、OLTP 領域有着深刻的技術積累。目前主要負責數據中臺和數據工具平臺的架構及性能調優工作,在數據中臺、數據集成開發工具、數據資產、數據質量和數據治理等方面擁有豐富的實戰經驗。

編輯:陶家龍

原文首發:51CTO技術棧

精彩文章推薦:

 

爲什麼我不推薦你盲目追求微服務?遲早要喫虧!

 

首席架構師李佐輝:浙江移動SRE轉型實踐

 

DevOps是微服務的祕方

 

波波老師大解密:如何成爲優秀的架構師?


福利贈送,中生代技術社區提供內推服務,直接內推到技術大廠用人部門,

有需求請添加社區社區專屬服務小姐姐Elsa的微信

申請備註(姓名+公司+技術方向)通過後溝通!

   END     
#接力技術,鏈接價值#

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