畫像系統人羣服務數據存儲架構的演進與創新| 京東雲技術團隊

一、畫像系統命中接口相關簡介

什麼是畫像系統

標籤畫像系統是一種數據管理和分析工具,它通過整合和分析用戶的行爲數據、交易數據、社交數據等多維度信息,構建出用戶的詳細畫像,幫助咱們運營人員更好地理解目標用戶羣體,從而實現精準營銷和精細化運營。

提供了那些能力:標籤註冊,標籤沉澱,標籤取值;羣體圈選;羣體服務(羣體命中,羣體下載和訂閱等核心能力

怎麼實現精準營銷和精細化運營

命中接口:它作爲連接用戶數據和營銷活動的橋樑,確保了營銷信息能夠準確地傳遞給最合適的用戶羣體。

業務場景

場景一:商城收銀臺頁面,優惠券展示與否,以及優惠金額多少。
場景二:金融APP端資源位,展示哪種營銷活動。



 

 

……

在支付、消金、財富等核心業務中發揮着至關重要的作用,影響着用戶拉新交易轉化促活等關鍵環節。



命中接口實現邏輯



 

 

挑戰

如何保證三高:高性能(50ms以下),高併發(百萬級TPS),高可用。
數據量大:羣體數量多,而且大量的羣體的pin數量都是千萬級別以上,甚至有的羣體pin數量達到了數十億。





 

 





 

 

二、畫像系統1.0和2.0版本的命中接口

存儲方式(物理機內存)

將人羣數據從OSS拉取並存儲在物理機(32C256G)中,由於羣體數量過多,256G不足以將所有的羣體的OSS文件都保存下來,所以採用分片的邏輯,每個分片只存儲羣體OSS文件的四分之一。



 

 

方案優缺點

優點:

1、性能達標:基於內存取值,減少中間件依賴,單機壓測到30000TPS,TP999最高40ms;

2、存儲成本較低:在當時,和直接使用緩存相比,成本較低;

3、緩解了CK的壓力:從OSS拉取文件,減少了CK查詢次數。

缺點:

1、初始化羣體非常慢:由於數據是存在機器內存中,每次啓動機器總要全量加載所有羣體,但隨着業務發展,羣體數量的增加重啓也會越來越慢;

2、擴容成本高:雖然分組內可以水平擴容,但是固定分組後,單機器的內存有限,一旦達到上限需要擴容分組時,必須成倍的擴容,導致擴容分組困難;

3、排查問題效率低:由於是自研的依賴於機器內存的存儲方案,整體結構複雜,在運維的能力方面偏弱,運維的相關工具少。



三、畫像系統3.0版本的命中接口

背景

遷移到了JDOS,JDOS沒有256G內存的物理機,所以我們採用的是192G內存的物理機
羣體數量由8000+羣體膨脹到25000+羣體,由於1.0和2.0版本的四分片物理機存儲的數據越來越多,快到物理機內存的極限了。
從OSS拉取羣體的時候,會由於網絡抖動,導致拉取人羣信息有不完整就斷掉的情況,會造成重複拉取,導致物理機堆內存抖動,不穩定,影響TP999,影響業務正常進行



 

 



存儲方式(物理機內存)

依舊將人羣數據存儲在物理機中,但使用了拆分前置的操作,並且將原先的物理機四份片改爲了八分片。先將羣體的OSS文件拆分成8分,然後物理機對應的分片只需要去拉取自己分片對應的文件即可。



 

 

數據分層方案(緩存)

爲什麼需要使用緩存做數據分層

提高系統的可用性和可靠性:應對不可預測的故障,網絡問題,服務器故障等,數據分層策略可以幫助系統應對這些不可預測的故障,提高系統的可用性和可靠性

存儲方式

因爲set集合的特徵,元素小於512個會自動壓縮,所以我們使用set集合來存用戶的offset的。



 

 



四、畫像系統4.0版本的命中接口

背景



 

 



由於在3.0的時候,offset的編碼已經超過了2的32次方。我們使用的ck版本加工羣體位圖的時候不支持大於2的32次方位圖計算,升級版本不兼容。對ck計算層架構升級:小於32位的offset計算到現有的bitmap中,大於32位的offset計算時,所有offset - 2^32,計算到高32位bitmap。基於這點想到了如果低成本使用R2M。也可以通過開發達到RoaringBitmap的壓縮效果。

爲什麼要壓縮

我們知道創建Bitmap的時候,長度必須是最大的offset的長度。再結合我們的場景,我們現在的pin數量已經超過了數十億,但是每個人羣不可能都是數十億之多,所以我們位圖存儲的數據不是連續的,而是稀疏的。



假設我們現在只有64個用戶,然後有一個人羣包,只有1個offset,63。

按照正常我們需要創建一個64位的Bitmap

1 2 3 …… 63 64
0 0 0 …… 1 0

這時候我們就把數組拆分成2組,1到32的用戶存儲到第1組,把33到64的用戶存儲到第二組。此時我們發現第一組的數組裏全是0,那第一組是不是可以不創建?這樣我們就用一個32位大小的數組存儲了64位的數據。

接下來更進一步,把64位的數組拆成每16個一組,那麼我們只需要創建最後一個分組的數組,也就是16位的數組來達到進一步壓縮的目的。

49 50 51 …… 63 64
0 0 0 …… 1 0



 

 

壓縮流程

根據我們的業務場景,每個位圖大小是65536壓縮效果最好。



 

 

存儲方式(緩存)

部署多個R2M集羣(或分組),將羣體bitmap進行拆分,並根據一定的路由策略存儲到不同的集羣上,通過不同的集羣提供查詢能力,如下圖



 

 

在新方案中,增加了一整套的羣體推送服務,包括數據的新增,更新,刪除,檢測,重試等全部可視化到頁面,大大增強了羣體加載的可監測性及有效性,而在之前的方案中,非常缺少這些有效的運維手段



 

 



流程對比



 

 

採用集中緩存替換自研分佈式存儲優缺點對比

 自研分佈式存儲 R2M存儲(新方案)
 劣勢 優勢
穩定性 ·突然新增的大量人羣信息新增或變更,堆內存變化比較劇烈,容易達到服務器上限 ·恢復週期長:服務器出現宕機後,恢復週期較長 ·單分片比較大,單臺命中存儲服務的流量佔比比較大,出現故障時,影響比較大 ·R2M具有自動擴容的能力,當達到了一定的使用比例,分片會自動擴容 ·分片出現宕機,會主從切換,瞬間恢復,並且支持異地機房備份 ·單分片比較小,影響範圍更小
維護成本 ·啓動慢:單臺存儲服務啓動比較慢,啓動最長達到30分鐘 ·上線難:總共有103臺服務器,65個分組(8個預發分組,57個生產分組),分組管理比較複雜,配置文件比較難以管理,啓動要注意的事項比較多 ·擴容難:由於各分組是有狀態的,並且要求均是特殊的物理機,擴容相對複雜 ·沒有這個節點了,不存在啓動慢,上線難問題 ·擴容簡單:自動擴容或者提擴容工單即可 ·緩存集羣由運維團隊在維護,他們有專業的團隊和工具維護
硬件成本 ·總共103臺物理機服務器,其中預發服務器 8臺,命中服務器48臺,下載服務器8臺,其他39臺(待下線)--32C192G服務器 ·R2M是科技集羣,碎片會更小有的管理和使用,可以更有效的使用緩存空間 ·不存在預發的服務器一直在在浪費 ·40億集羣大概500M,如果是13000個平均是10個億的人羣,大概是1.5T,主從結構大概就是3T,換算成成192G的物理,大概就是15臺物理機,如果保持水位是60%的話,大概物理機是25臺物理機
其他  ·只在初始化時拉取一次OSS文件即可,減少帶寬佔用

性能對比

接口整體TP999耗時從40ms下降到10ms以內



 

 



 

 

五、命中接口的後續探索

一、逆向存儲

背景

我們對一些耗時長的請求進行分析時發現,有些業務方傳的羣體編碼,一次可能傳幾十個,這種情況我們可能需要判定幾十次,然後把結果返回給用戶,性能肯定比一次只傳一個羣體會差。所以我們想使用用戶的pin當作key,然後value是用戶所在的羣體數據。這樣不管用戶一次傳多少個羣體,我們只用取一次緩存就可以。

存儲方式

key:用戶的pin的offset爲key

value:用戶所在的所有羣體集合(以位圖的方式存儲)



 

 

優勢

性能高:用戶傳多個羣體編碼的時候,我們只需要取一次緩存就可以,性能大大提高了。

二、規則判定

背景

發現有些用戶在創建羣體的時候,只用到了標籤,然後對這些標籤做邏輯與或非的操作。

舉個例子:如果用戶選擇了兩個標籤(標籤1:男性,標籤2:三十歲以上,而且是且的關係)創建了一個人羣,現在想判斷一個pin是否在這個羣體裏面,我們可以怎麼操作?我們只需要先判定用戶是否是男性,然後判斷用戶是否三十歲以上,然後在內存中做邏輯且的操作就可以了。

優勢

存儲空間:不用存儲整個羣體位圖文件,而且標籤位圖可重複使用,大大節省了存儲空間

六、相關技術附錄

CDP系統中目前存在大量由pin集合組成的標籤和羣體,截止當前共有標籤4000+,有效羣體17000+。而且大量的羣體都是pin數量都是千萬級別以上,甚至有的羣體pin數量達到了40億+。如此大量的pin集合,對我們存儲結構提出較高的要求。



這裏拿羣體舉例,如果某羣體包含1000W個pin,通過文本文件存儲,大概需要150M,40億的羣體就達到了驚人的150*40*10=60000M,大約60G,而我們的羣體數量已經達到了17000+,再加上標籤數據,所需要的存儲空間將不可接受。



並且,數據的存儲只是其中一個方面,後續針對標籤和羣體的組合計算,創建出更細粒度的pin包也是一個挑戰。

面對以上問題,CDP採用了Bitmap的思路來解決,不但解決了存儲空間問題,而且Bitmap本身的交併差運算,能夠很好的支持用戶對不同標籤和羣體的組合計算,詳細方案如下。

一、bitmap簡介

它的基本思想是用bit位來唯一標記某個數值,這樣可以用它來記錄一個數值沒有重複的數據元組。並且每一條數據只使用一個bit來標識,能夠大大的節省存儲空間。

比如,如果想存儲一個數值數組[2,4,6,8]。

Java中如果用byte類型來存儲,不考慮其他開銷,需要4個字節的空間,一個字節8位,也就是4*8=32bit。

倘若使用更大的數據類型,存儲空間也會相應增大,如使用Integer(4字節),則需要4*4*8=128bit。

而如果採用bitmap的思想,只需要構建一個8bit空間,也就是一個字節的空間來存儲,如下圖。





 

 

二、pin池編碼

通過上文的例子,可以看到,使用Bitmap思想來存儲,實際上每一個數據是一個bit,而且不能重複,這一點用戶pin是符合的,沒有重複的pin。

由於bitmap裏只能存0或者1來標識當前位是否有值,而用戶pin確是一個字符串,這就需要將數十億的用戶pin進行唯一性編碼,這個編碼也就是我們常說的offset偏移量。

每一個pin對應一個唯一的offset,目前已到46億+,也就是說當前最大的偏移量是45億+,這部分由數據同學幫我們加工一張pin池表,其中包含了pin和offset的對應關係。這樣,新註冊的pin,只要順序增加offset值即可。

下邊是一個簡單示意圖,假設我有8個pin,pin1~pin8,對應的offset編號爲1~8。

我要建一個只包含雙數pin的標籤或羣體,則我只需要將offset爲2,4,6,8的位設爲1即可。



 

 

三、ClickHouse簡介

有了位圖之後,存在哪裏,以及怎麼進行位圖之間的交併差的運算。基於這些問題,我們使用了ClickHouse(以下簡稱CK),一個由俄羅斯Yandex在2016年年開源的⾼性能分析型SQL數據庫,是一個用於聯機分析處理(OLAP)的列式數據庫管理系統(columnar DBMS)



它具有以下特點:

1、完備的數據庫管理功能,包括DML(數據操作語言)、DDL(數據定義語言)、權限控制、數據備份與恢復、分佈式計算和管理。

2、列式存儲與數據壓縮: 數據按列存儲,在按列聚合的場景下,可有效減少查詢時所需掃描的數據量。同時,按列存儲數據對數據壓縮有天然的友好性(列數據的同類性),降低網絡傳輸和磁盤 IO 的壓力。

3、關係模型與SQL: ClickHouse使用關係模型描述數據並提供了傳統數據庫的概念(數據庫、表、視圖和函數等)。與此同時,使用標準SQL作爲查詢語言,使得它更容易理解和學習,並輕鬆與第三方系統集成。

4、數據分片與分佈式查詢: 將數據橫向切分,分佈到集羣內各個服務器節點進行存儲。與此同時,可將數據的查詢計算下推至各個節點並行執行,提高查詢速度。



更多特性可查看官方文檔:https://clickhouse.com/docs/zh/introduction/distinctive-features

還可以查看同事的這篇文章:如何使用Clickhouse搭建數十億級用戶畫像平臺看這一篇就夠了



除了上文CK的特性之外,它還具有分析數據高性能,開發流程簡便,開源社區活躍度高,並且支持壓縮位圖等優勢。

四、羣體加工鏈路

基於上面對bitmap以及clickhouse的介紹,我們採用的是ClickHouse+Bitmap實現標籤羣體組合計算和羣體的存儲



 

 

上圖可以看到除了CK中的數據外,我們在OSS對象存儲中也放了一份羣體數據。

五、RoaringBitmap壓縮

我們最終使用的是RoaringBitmap,一種高效的壓縮位圖實現,簡稱RBM。於2016年由S. Chambi、D. Lemire、O. Kaser等人在論文《Better bitmap performance with Roaring bitmaps》 《Consistently faster and smaller compressed bitmaps with Roaring》中提出。



基本實現思路如下:

以整型int(32位)爲例,將數據分成高16位和低16位兩部分,低16位不變,作爲數據位Container,高16位作爲桶的編號Container,可以理解爲高位的Container中,存放了很多個低位Container。



比如,我要存放65538這個值,則高位爲65538>>>16=1,低位爲65538-65536*1=2,即存儲在1號桶的2號位置,存儲位置如下圖:



 

 

我們當前使用的RoaringBitmap版本爲0.8.13,Container包含了三種實現:ArrayContainer(數組容器),

作者:京東科技 王京星

來源:京東雲開發者社區

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