ClickHouse BSI與字典服務(wù)在B站商業(yè)化DMP中的應(yīng)用實(shí)踐
1.業(yè)務(wù)背景
DMP(數(shù)據(jù)管理平臺(tái))為廣告部門提供B站用戶數(shù)據(jù)的管理。主要功能包括用戶標(biāo)簽收集存儲(chǔ),標(biāo)簽市場(chǎng)建設(shè),人群包圈選,人群畫(huà)像分析,人群/特征定向幾大功能模塊。
其中人群包圈選和人群畫(huà)像分析是兩大核心功能。對(duì)設(shè)計(jì),性能,擴(kuò)展性,可維護(hù)性都有比較高的要求。也是本文中要討論的ClickHouse技術(shù)的應(yīng)用場(chǎng)景。在實(shí)踐中,我們利用ClickHouse的bitmap相關(guān)功能,實(shí)現(xiàn)了人群包的實(shí)時(shí)預(yù)估和計(jì)算,也實(shí)現(xiàn)了人群包畫(huà)像的分鐘級(jí)計(jì)算。
下面先簡(jiǎn)單介紹下人群包圈選和人群畫(huà)像兩個(gè)功能。
1.1 人群圈選
所謂人群圈選,就是由用戶根據(jù)標(biāo)簽指定一系列規(guī)則,然后通過(guò)這個(gè)規(guī)則把滿足條件的人群圈選出來(lái)。假設(shè)我們用戶有“性別”,“年齡”,“地域”三個(gè)維度的標(biāo)簽,那么圈選規(guī)則就可以是“性別男,年齡>30,北京地區(qū)”。該系統(tǒng)需要根據(jù)圈選規(guī)則實(shí)時(shí)輸出滿足條件的人數(shù)和人群包。
圖片
如上圖所示,用戶使用了性別,年齡,地域三個(gè)標(biāo)簽取了交集,在下方實(shí)時(shí)顯示了對(duì)應(yīng)的覆蓋人數(shù)。
這里的技術(shù)難點(diǎn)在于
- 用戶的圈選的規(guī)則非常靈活,可能涉及數(shù)十種標(biāo)簽或人群包的交并運(yùn)算,并且要求實(shí)時(shí)顯示計(jì)算結(jié)果。商業(yè)DMP中現(xiàn)有大約數(shù)百種標(biāo)簽,hive表中原始數(shù)據(jù)量PB級(jí),如果采用直接查hive表的方式,顯然是無(wú)法滿足性能要求的。
- 人群包數(shù)量多,目前日新增數(shù)百個(gè)人群包,加上需要刷新的舊人群包,每天需要計(jì)算上萬(wàn)個(gè)人群包。
因此基于以上需求,需要設(shè)計(jì)一種高效靈活,可擴(kuò)展的人群圈選手段。
1.2 人群畫(huà)像
用戶打好人群包之后,可以對(duì)人群包中的用戶特征分析,如查看用戶的年齡,性別,地域分布,興趣愛(ài)好,up主關(guān)注,互動(dòng)等等。例如下圖所示:
圖片
圖片
圖片
計(jì)算用戶畫(huà)像的基本原理是需要用人群包中的用戶id與每一個(gè)需要洞察的標(biāo)簽值所對(duì)應(yīng)的用戶id取交集,求出交集的人數(shù)后,計(jì)算該標(biāo)簽值在人群包中的百分比或TGI。例如:標(biāo)簽值"男"占比XX%, 標(biāo)簽值"女"占比XX% 。人群畫(huà)像的技術(shù)難點(diǎn)有:
- 人群包人數(shù)多,從數(shù)萬(wàn)到億。
- 計(jì)算量大,目前畫(huà)像包含數(shù)十個(gè)維度,每日按人群包X維度計(jì)算百分比和tgi排名,涉及數(shù)億次bitmap交并運(yùn)算。
最早的DMP使用離線hive sql進(jìn)行畫(huà)像計(jì)算,平均一個(gè)包畫(huà)像要等待2個(gè)小時(shí),引入ClickHouse Bitmap技術(shù)后,畫(huà)像時(shí)間降到了分鐘級(jí)。
2.基于bitmap的人群圈選
2.1 bitmap基本原理及其在
人群圈選中的應(yīng)用
bitmap是一種數(shù)據(jù)結(jié)構(gòu),可以用來(lái)表示一系列正整數(shù)的集合。底層是一系列連續(xù)的二進(jìn)制bit位,每個(gè)bit位有一個(gè)索引序號(hào),依次用1,2,3,4,5...自然數(shù)編號(hào)。每個(gè)bit位有兩種狀態(tài),0或1。如果bit位為0表示這一位對(duì)應(yīng)的索引序號(hào)的數(shù)字不在集合里,相反,如果bit位為1,表示對(duì)應(yīng)的索引序號(hào)的數(shù)字在集合中。例如bitmap內(nèi)容是01101,其中第2,3,5位(從左到右)是1,則該bitmap代表整數(shù)集合{2,3,5}。
B站用戶id是一個(gè)64位正整數(shù),從1開(kāi)始編號(hào),無(wú)限增加。根據(jù)前面的描述,可以用bitmap來(lái)代表一系列id的集合。也就是說(shuō)每個(gè)人群包的id集合都可以用一個(gè)bitmap來(lái)表示。
我們可以在邏輯上給每個(gè)標(biāo)簽值創(chuàng)建一個(gè)bitmap,表示所有具有該標(biāo)簽屬性的人群。這樣人群包的圈選就等價(jià)于多個(gè)標(biāo)簽bitmap的交并差運(yùn)算。以前面提到的規(guī)則”性別男,年齡>30,北京地區(qū)”為例,人群圈選過(guò)程如下:
圖片
如圖所示,系統(tǒng)預(yù)先分別給男,>30歲,北京地區(qū)建立三個(gè)bitmap索引,如果相應(yīng)索引位的id在集合中,則把對(duì)應(yīng)位置的bit位設(shè)置為1。根據(jù)人群圈選規(guī)則,對(duì)三個(gè)bitmap進(jìn)行AND位運(yùn)算,得到最終bitmap結(jié)果,也就是最終的人群包中包含{2,5,7,9}四個(gè)id。
以上就是基于bitmap圈選人群包的基本原理,在具體應(yīng)用中,還解決了很多工程上的問(wèn)題,例如:
- 支持可擴(kuò)展的,任意維度的標(biāo)簽圈選。目前支持標(biāo)簽數(shù)量>300種,總數(shù)據(jù)量>1PB
- 打通離線數(shù)倉(cāng)與ClickHouse之間的數(shù)據(jù)流,實(shí)現(xiàn)數(shù)倉(cāng)到ClickHouse和ClickHouse到數(shù)倉(cāng)的雙向數(shù)據(jù)格式轉(zhuǎn)換和傳輸,以及標(biāo)簽元數(shù)據(jù)管理機(jī)制。
- 一個(gè)包含億級(jí)別的bitmap大小有數(shù)百M(fèi)B,如果只存儲(chǔ)在單個(gè)bitmap中會(huì)導(dǎo)致計(jì)算效率下降,因此需要對(duì)bitmap的存儲(chǔ)方式進(jìn)行優(yōu)化。
- 開(kāi)發(fā)相比原始ClickHouse sql更易于使用的DSL,通過(guò)DSL提高系統(tǒng)的易用性,擴(kuò)展性和執(zhí)行效率。
2.2 實(shí)踐中遇到的bitmap相關(guān)問(wèn)題
在具體實(shí)踐中,我們發(fā)現(xiàn)bitmap可以很好的解決離散標(biāo)簽值的計(jì)算,對(duì)于億級(jí)的人群計(jì)算通??梢栽?秒內(nèi)完成。可以滿足大多數(shù)人群計(jì)算需求。但是仍然存在一些明顯的問(wèn)題。
id不連續(xù)導(dǎo)致的性能問(wèn)題
ClickHouse中使用Roaring Bitmap存儲(chǔ)bitmap數(shù)據(jù),而在Roaring Bitmap內(nèi)部,數(shù)據(jù)存儲(chǔ)在不同類型的container中,不同類型的container具有不同的空間成本和計(jì)算時(shí)間復(fù)雜度。Roaring Bitmap內(nèi)的數(shù)據(jù)存儲(chǔ)為哪種類型的container是由數(shù)據(jù)特性決定的,其中一個(gè)重要特性就是數(shù)據(jù)的連續(xù)性。分布稀疏的數(shù)據(jù)連續(xù)性低,在Roaring Bitmap中消耗的空間成本和計(jì)算時(shí)間復(fù)雜度都會(huì)更高(有關(guān)Roaring Bitmap的內(nèi)部存儲(chǔ)結(jié)構(gòu)及其對(duì)計(jì)算存儲(chǔ)性能的影響在此不做詳細(xì)論述,有興趣的讀者可參見(jiàn)文章基于改進(jìn)字典的大數(shù)據(jù)多維分析加速實(shí)踐中的第4章節(jié))。
B站用戶的id是整型數(shù)據(jù),我們?cè)趯?shí)踐中發(fā)現(xiàn),id的分布非常稀疏,連續(xù)性低,這就造成bitmap體積膨脹,無(wú)法達(dá)到最佳性能,尤其是在計(jì)算畫(huà)像時(shí),需要對(duì)數(shù)百萬(wàn)的bitmap進(jìn)行交并運(yùn)算,bitmap體積過(guò)大,對(duì)磁盤IO和CPU都有很大的壓力。因此如何采用合適的方法讓bitmap中的id盡量連續(xù)分布,是我們的一個(gè)主要優(yōu)化方向。
對(duì)于非離散標(biāo)簽圈選支持受限
DMP的標(biāo)簽中大部分都是離散標(biāo)簽查詢,每個(gè)標(biāo)簽值對(duì)應(yīng)一個(gè)bitmap。所謂離散標(biāo)簽值是指枚舉類的標(biāo)簽值,例如性別,年齡,地域,關(guān)注的up主都屬于此類。對(duì)于這種標(biāo)簽,每個(gè)標(biāo)簽值對(duì)應(yīng)的id聚合成bitmap后寫(xiě)入ClickHouse是比較自然的選擇,ClickHouse對(duì)此類標(biāo)簽的交并查詢支持也很好。
但是在業(yè)務(wù)需求中,還存在一些非離散的指標(biāo)查詢,例如:“找出最近一個(gè)月某個(gè)廣告單元曝光次數(shù)大于N次的人”,“找出最近一個(gè)月某稿件播放時(shí)長(zhǎng)大于N分鐘的人”。這些查詢的特點(diǎn)是需要在一定時(shí)間范圍內(nèi)對(duì)某個(gè)實(shí)體的相關(guān)指標(biāo)進(jìn)行聚合,以廣告曝光次數(shù)為例,對(duì)應(yīng)的hive sql大概如下所示:
SELECT
id
FROM (SELECT id, unit_id FROM ad_event_table WHERE
event='show' -- 曝光
AND unit_id IN (11111, 22222) -- 單元id列表
AND log_date >= '${yyyyMMdd, -360d}' -- 近一年
GROUP BY unit_id, id -- 按id + unit_id聚合
HAVING COUNT(1) > N -- 找出每個(gè)單元曝光次數(shù)大于N次的id ) t0
GROUP BY id -- 所有單元曝光次數(shù)>N的id進(jìn)行去重
如果直接執(zhí)行一個(gè)這樣一個(gè)hive sql,涉及的廣告曝光底表近一年的數(shù)據(jù)可能有數(shù)百G之多,至少要幾分鐘才會(huì)獲得結(jié)果,顯然是無(wú)法滿足dmp人數(shù)實(shí)時(shí)預(yù)估的要求的。
如果把一年的明細(xì)數(shù)據(jù)導(dǎo)入ClickHouse,在ClickHouse中做類似的查詢并把id實(shí)時(shí)聚合成bitmap,同樣面臨數(shù)據(jù)量大,無(wú)法滿足秒級(jí)人數(shù)預(yù)估的要求。作為一個(gè)折中的辦法,DMP中對(duì)于類似的查詢規(guī)定了一系列固定的時(shí)間窗口,如近30天,60天,90天,180天等等,事先通過(guò)離線任務(wù)按照固定的時(shí)間窗口對(duì)每個(gè)指標(biāo)進(jìn)行預(yù)聚合,把每個(gè)固定時(shí)間窗口內(nèi)滿足某個(gè)指標(biāo)的人事先聚合成bitmap寫(xiě)入ClickHouse,用戶圈人的時(shí)候只能對(duì)固定的幾個(gè)時(shí)間窗口內(nèi)的指標(biāo)進(jìn)行圈選。還是以上面單元近一年曝光為例,ClickHouse中的查詢?nèi)缦拢?/p>
SELECT groupBitmapOr(uid_index) AS `uid_index` -- id bitmap
FROM tag_index_table
WHERE (tag_name='ad_show') -- 廣告曝光
AND (log_date='${yyyyMMdd}') -- 每天更新全量數(shù)據(jù)
AND (tag_value IN ('360D-11111','360D-22222')) -- 事先聚合好360天的單元曝光,把范圍查詢變成幾個(gè)固定時(shí)間區(qū)間的點(diǎn)查
AND (metric>=N) -- 曝光指標(biāo) > N
上述查詢是把采用預(yù)聚合的方法把標(biāo)簽值(單元id)+時(shí)間(天數(shù))+指標(biāo)值(metric)進(jìn)行聚合,可以把范圍查詢近似成點(diǎn)查,滿足實(shí)時(shí)計(jì)算的需求,通常也可以在秒級(jí)返回結(jié)果。但是這種方案仍然有以下問(wèn)題:
- 預(yù)聚合數(shù)據(jù)量大,多個(gè)時(shí)間窗口存在數(shù)據(jù)冗余,某些標(biāo)簽要處理每天都要處理近一年的數(shù)據(jù),有數(shù)百G到TB級(jí),并且30,60,90等不同時(shí)間窗口存在重疊,有數(shù)據(jù)冗余。
- 標(biāo)簽值x指標(biāo)值造成標(biāo)簽數(shù)據(jù)膨脹。指標(biāo)值(metric)為非離散數(shù)據(jù), 如曝光次數(shù),播放時(shí)長(zhǎng),指標(biāo)值可能在0到數(shù)千之間分布,假設(shè)某個(gè)廣告單元有1000個(gè)指標(biāo)值,那僅這一個(gè)廣告單元就會(huì)有1000個(gè)bitmap(每個(gè)bitmap對(duì)應(yīng)一個(gè)指標(biāo)值),這就造成表中的數(shù)據(jù)行數(shù)很多,索引變大,增加了內(nèi)存和緩存的開(kāi)銷。
- 圈選方式不靈活。預(yù)處理的時(shí)間窗口只能處理一些典型的查詢,還有很多客戶就是要求實(shí)時(shí)圈選任意日期范圍內(nèi)的指標(biāo),對(duì)于這部分需求ClickHouse無(wú)法滿足,只能采用spark離線計(jì)算。系統(tǒng)就分成了ClickHouse實(shí)時(shí)計(jì)算和spark離線計(jì)算兩個(gè)部分,增加了系統(tǒng)的復(fù)雜度和開(kāi)發(fā)成本。
基于以上原因,我們也需要尋找一種更高效,更靈活的非離散指標(biāo)標(biāo)簽圈選方案。
3.ClickHouse字典服務(wù)
ClickHouse字典服務(wù)是B站ClickHouse團(tuán)隊(duì)針對(duì)多個(gè)需要在ClickHouse中用Roaring Bitmap做交并補(bǔ)計(jì)算的場(chǎng)景而設(shè)計(jì)開(kāi)發(fā)的一套字典映射服務(wù)。關(guān)于ClickHouse字典服務(wù)的架構(gòu)及實(shí)現(xiàn),本文不做詳細(xì)介紹,感興趣的讀者可參見(jiàn)文章基于改進(jìn)字典的大數(shù)據(jù)多維分析加速實(shí)踐中的4.3章節(jié),本文下一章節(jié)主要闡述該服務(wù)在DMP場(chǎng)景下的應(yīng)用姿勢(shì)及效果。
4.ClickHouse字典服務(wù)在DMP中的應(yīng)用
4.1 應(yīng)用姿勢(shì)
首先,使用ClickHouse字典服務(wù)對(duì)于DMP場(chǎng)景有以下兩個(gè)好處:
- 字典服務(wù)的id是按順序分配的,可以讓id集中到更小的空間里,對(duì)于bitmap來(lái)說(shuō),id越集中,所生成的bitmap體積越小,運(yùn)算效率越高。
- 標(biāo)簽圈選不再局限于整數(shù)類型的id,通過(guò)字典服務(wù)把任意字符串映射成一個(gè)整數(shù),比如設(shè)備號(hào),buvid等等,為將來(lái)的產(chǎn)品功能擴(kuò)充提供了更大的可能性。
加入字典服務(wù)后,整個(gè)數(shù)據(jù)流程如下:
圖片
如圖所示,在原始的id明細(xì)表調(diào)用字典服務(wù)做一次id映射,然后把映射后的id聚合成bitmap。具體還做了以下優(yōu)化:
- 為了提高效率,減少線上壓力,字典服務(wù)每天導(dǎo)出一張離線hive表,業(yè)務(wù)方先關(guān)聯(lián)hive表獲取映射id,如果離線hive表中不存在,則通過(guò)RPC實(shí)時(shí)調(diào)用字典服務(wù)。字典初始化之后,離線表的映射率通常在90%以上,可以極大的減少線上服務(wù)的實(shí)時(shí)壓力。
- 優(yōu)化了ClickHouse中不同shard中id的分片算法,每個(gè)id是一個(gè)64位整數(shù),給定N個(gè)分片,則取個(gè)id的高48位(17~64位)對(duì)N取模,模數(shù)相同的id屬于通一個(gè)bitmap分片。之所以采用這種方法分片,是考慮到ClickHouse bitmap存儲(chǔ)的特點(diǎn),讓低16位連續(xù)的id盡量處于同一個(gè)分片中,因?yàn)閎itmap中連續(xù)的bit位越多,可以采用壓縮算法減少體積,提高計(jì)算效率。經(jīng)過(guò)測(cè)試,在同等條件下,這種優(yōu)化的分片方式比id直接對(duì)分片數(shù)N取模,要節(jié)省30%的存儲(chǔ),計(jì)算速度快一倍以上。
4.2 優(yōu)化效果
引入ClickHouse字典服務(wù)后,我們?cè)诖鎯?chǔ)成本、寫(xiě)入性能、查詢性能等方面均取得了顯著收益,具體如下文所述。
存儲(chǔ)成本收益
存儲(chǔ)空間上,對(duì)于千萬(wàn)到上億級(jí)別的bitmap,體積減少了約4.5倍,對(duì)于萬(wàn)級(jí)別的小bitmap減少約1.4倍,平均減少3倍左右。bitmap越大,收益越大。
整體存儲(chǔ)空間收益如下圖所示:
圖片
查詢性能收益
對(duì)于查詢延遲較高的人群畫(huà)像計(jì)算,引入ClickHouse字典服務(wù)后查詢性能大幅提升,end2end查詢延遲由之前的20分鐘提升到3分鐘,提升了6.7倍。
從ClickHouse引擎?zhèn)扔^察,DMP場(chǎng)景整體查詢P50,P90延遲優(yōu)化效果如下圖所示:
圖片
寫(xiě)入性能收益
在寫(xiě)入方面,p90寫(xiě)入延遲降低了2x+,p50寫(xiě)入延遲降低了1.5x。
整體寫(xiě)入P50,P90延遲優(yōu)化效果如下圖所示:
圖片
5 BSI原理簡(jiǎn)介及其在ClickHouse中的功能實(shí)現(xiàn)
5.1 BSI原理簡(jiǎn)介
BSI(Bit-slice index)的數(shù)據(jù)結(jié)構(gòu)由一組bitmap組成,其中每個(gè)bitmap用于表示二進(jìn)制整型metric在對(duì)應(yīng)比特位上取值為1的實(shí)體id集合。
下圖展示了將5個(gè)實(shí)體id及其對(duì)應(yīng)的整型metric value轉(zhuǎn)換成BSI表示形式后的效果:
圖片
從上圖的轉(zhuǎn)換中,我們可以總結(jié)出BSI數(shù)據(jù)結(jié)構(gòu)的以下特征:
- BSI的slice個(gè)數(shù)由最大整型值的二進(jìn)制位數(shù)決定
- 每個(gè)slice都是一個(gè)bitmap
- 每個(gè)slice對(duì)應(yīng)一個(gè)比特位:slice_i 存儲(chǔ)第i個(gè)比特位上取值為1的metric value對(duì)應(yīng)的所有實(shí)體id的集合
如上文所述,bitmap適用于離散值標(biāo)簽的人群圈選計(jì)算場(chǎng)景,而B(niǎo)SI則更適合針對(duì)連續(xù)值指標(biāo)的人群圈選計(jì)算場(chǎng)景。除此之外,BSI也適合用于人群圈選完成之后的人群效果指標(biāo)分析場(chǎng)景(比如,計(jì)算某個(gè)指定人群包的平均曝光次數(shù))。
5.2 BSI在ClickHouse中的功能實(shí)現(xiàn)
BSI數(shù)據(jù)類型
在ClickHouse中,我們將BSI封裝成一個(gè)新的數(shù)據(jù)類型,用戶可以根據(jù)自己的需求定義BSI類型字段并配合ClickHouse中的aggregating mergetree引擎建表,建表示例如下:
CREATE TABLE test.bsi
(
`log_date` Date,
...
`ck_bucket` UInt32,
`bsi_agg` AggregateFunction(bsi_merge_agg, BSI)
)
ENGINE = AggregatingMergeTree
PARTITION BY log_date
ORDER BY ck_bucket
TTL ...
具體實(shí)現(xiàn)上,BSI本質(zhì)上就是Bitmap Array,所以我們并沒(méi)有重新實(shí)現(xiàn)一個(gè)獨(dú)立的數(shù)據(jù)類型,而是基于ClickHouse內(nèi)部的自定義數(shù)據(jù)類型注冊(cè)機(jī)制,將Bitmap Array類型注冊(cè)為一個(gè)新的BSI數(shù)據(jù)類型。
除了各個(gè)比特位對(duì)應(yīng)的slice bitmaps之外,BSI類型數(shù)據(jù)中還存儲(chǔ)了一個(gè)existence bitmap(EBM),用于表示所有metric取值非空(not null)的實(shí)體id集合。EBM可用于加速某些BSI計(jì)算,并且對(duì)于某些BSI functions而言EBM是必需的。
BSI Functions
我們?cè)贑lickHouse中實(shí)現(xiàn)了許多BSI Functions,包括:
- 用于從明細(xì)數(shù)據(jù)構(gòu)建BSI的bsi_build
- 用于對(duì)單個(gè)BSI進(jìn)行過(guò)濾,求和等操作的bsi_filter, bsi_sum, bsi_range, bsi_lt, bsi_gt, bsi_topk, etc
- 用于對(duì)BSI數(shù)據(jù)列做聚合的bsi_add_agg, bsi_merge_agg, etc
關(guān)于各個(gè)BSI Function的功能細(xì)節(jié)這里不做詳細(xì)闡述,有興趣的讀者可參見(jiàn)引用[2]。
由于BSI Functions的底層實(shí)現(xiàn)上依賴于Roaring Bitmap的交并補(bǔ)計(jì)算,所以對(duì)組成BSI的Roaring Bitmap做ClickHouse字典服務(wù)映射也能夠大幅提升BSI Functions的計(jì)算性能。
6.BSI+字典服務(wù)方案在DMP場(chǎng)景的落地及效果
6.1 落地姿勢(shì)
針對(duì)DMP場(chǎng)景下連續(xù)值指標(biāo)圈選困難的問(wèn)題,我們基于連續(xù)值指標(biāo)的明細(xì)數(shù)據(jù)構(gòu)建出連續(xù)值指標(biāo)的BSI數(shù)據(jù),然后導(dǎo)入到ClickHouse中通過(guò)BSI Functions即可對(duì)連續(xù)值指標(biāo)進(jìn)行任意時(shí)間范圍內(nèi)的圈選,解決了原來(lái)只能預(yù)聚合固定時(shí)間窗口的查詢限制。
下圖是寫(xiě)入與查詢BSI數(shù)據(jù)的整體流程:
圖片
BSI數(shù)據(jù)寫(xiě)入
我們的明細(xì)數(shù)據(jù)存儲(chǔ)在離線數(shù)倉(cāng)Hive表中,利用Spark程序?qū)ive上的明細(xì)數(shù)據(jù)轉(zhuǎn)換成BSI(bitmap array)結(jié)構(gòu)后寫(xiě)入到ClickHouse表中。其中,Spark數(shù)據(jù)同步程序會(huì)調(diào)用生成BSI數(shù)據(jù)的UDAF將明細(xì)數(shù)據(jù)組裝成為BSI,同時(shí)會(huì)調(diào)用ClickHouse字典服務(wù)進(jìn)行字典映射轉(zhuǎn)換,從而降低BSI的存儲(chǔ)成本和查詢延遲。
以上文提及的廣告曝光查詢?yōu)槔?,使用BSI后,數(shù)倉(cāng)開(kāi)發(fā)在進(jìn)行數(shù)據(jù)處理時(shí)不再需要按照標(biāo)簽值(單元id)+時(shí)間(時(shí)間窗口天數(shù))+指標(biāo)值(metric)進(jìn)行聚合,每天只需要處理當(dāng)天的增量日志即可,把當(dāng)天增量的單元曝光聚合成一個(gè)BSI即可。
BSI數(shù)據(jù)查詢
上述BSI寫(xiě)入ClickHouse后,業(yè)務(wù)方就可以通過(guò)bsi相關(guān)的函數(shù)在ClickHouse中實(shí)時(shí)查詢,以廣告曝光為例,一個(gè)典型的表結(jié)構(gòu)和查詢語(yǔ)句如下所示:
CREATE TABLE tag_bitmap_bsi
(
`tag_name` String,
`tag_value` String,
`log_date` Date,
`sp_bucket` UInt32,
`sk_bucket` UInt32,
`ck_bucket` UInt32,
`bsi_agg` AggregateFunction(bsi_merge_agg, BSI)
)
ENGINE = ReplicatedAggregatingMergeTree(...)
PARTITION BY (toYYYYMMDD(log_date), tag_name)
ORDER BY (sp_bucket, tag_value, ck_bucket)
TTL ...
SELECT groupBitmapOr(bsi_ge(bsi_agg, N)) AS `uid_index` -- 180天內(nèi)曝光次數(shù)>N次的id組成的bitmap
FROM
(
SELECT bsi_add_agg(bsi_agg) AS `bsi_agg`
FROM
(
SELECT tag_value, bsi_merge_aggMerge(bsi_agg) AS `bsi_agg` -- 一天之內(nèi)的指標(biāo)合并(去重)
FROM
tag_bitmap_index_mapped_bsi
WHERE (tag_name = 'ad_show') AND (log_date > '${yyyyMMdd}' - INTERVAL 180 DAY -- 近180天 ) AND (tag_value IN ('11111', '22222'))
GROUP BY tag_value, log_date
)
GROUP BY
tag_value -- 最終累加出180天內(nèi)所有的指標(biāo)
)
6.2 落地過(guò)程遇到的問(wèn)題及其解決方案
在將BSI落地到,我們遇到了以下問(wèn)題:
- 在Spark數(shù)據(jù)同步程序中生成的單個(gè)BSI過(guò)大,導(dǎo)致spark中的一個(gè)row對(duì)象過(guò)大,在Kryo Serializer做序列化的過(guò)程中出現(xiàn)buffer overflow的問(wèn)題。
- 寫(xiě)入到ClickHouse各個(gè)分片的BSI里的bitmap數(shù)據(jù)分布稀疏,影響B(tài)SI查詢性能。
- 寫(xiě)入到ClickHouse單個(gè)分片的BSI的基數(shù)過(guò)大(即包含的實(shí)體id過(guò)多),導(dǎo)致單分片BSI的查詢性能較低。
- ClickHouse中由于分批寫(xiě)入導(dǎo)致存儲(chǔ)的BSI個(gè)數(shù)過(guò)大,影響B(tài)SI的查詢性能。
為了解決上述問(wèn)題,我們做了以下設(shè)計(jì)與優(yōu)化:
圖片
- 在Spark數(shù)據(jù)同步程序中對(duì)明細(xì)數(shù)據(jù)做分桶處理,以避免單條BSI記錄過(guò)大導(dǎo)致Kryo Serializer的buffer overflow問(wèn)題。
- 在Spark數(shù)據(jù)同步程序中引入ClickHouse字典服務(wù),對(duì)分布稀疏的實(shí)體id做字典映射,提高BSI內(nèi)數(shù)據(jù)的連續(xù)性,從而提升BSI查詢性能。
- 使用實(shí)體id的高48位做sharding,讓實(shí)體id高48位相同的數(shù)據(jù)都寫(xiě)入到相同的ClickHouse分片中,降低單個(gè)分片中BSI的基數(shù),同時(shí)進(jìn)一步提高BSI內(nèi)數(shù)據(jù)的連續(xù)性,從而提升BSI查詢性能。
- 使用AggregatingMergeTree作為表引擎,分批寫(xiě)入的小BSI數(shù)據(jù)異步聚合成更大的BSI數(shù)據(jù),減少ClickHouse中的BSI記錄個(gè)數(shù),從而提升BSI查詢性能。
6.3 落地效果與收益
產(chǎn)品功能增強(qiáng)
引入BSI后,DMP在產(chǎn)品功能上得到以下增強(qiáng)與優(yōu)化:
- 實(shí)現(xiàn)了任意日期的指標(biāo)人群圈選,不再局限于幾個(gè)固定的時(shí)間窗口,擴(kuò)展了業(yè)務(wù)的應(yīng)用場(chǎng)景。
- 去除了部分通過(guò)spark sql離線計(jì)算流程,把所有人群包相關(guān)的計(jì)算統(tǒng)一到ClickHouse里,簡(jiǎn)化了系統(tǒng)設(shè)計(jì)。
- 對(duì)于廣告曝光,稿件播放這種數(shù)據(jù)量大標(biāo)簽時(shí)間范圍從30天提升到一年,提升了產(chǎn)品的能力。
整體場(chǎng)景查詢性能
圖片
受益于BSI和字典服務(wù)對(duì)查詢性能和存儲(chǔ)成本的優(yōu)化,生產(chǎn)業(yè)務(wù)在使用BSI+字典服務(wù)的方案后,將之前30天~90天的時(shí)間范圍圈選擴(kuò)大到了一年,目前整體的p50查詢延遲可以保證在500ms左右,p90查詢延遲可以保證在5s左右。
存儲(chǔ)成本收益
相較于通過(guò)預(yù)聚合不同時(shí)間范圍的bitmap數(shù)據(jù)來(lái)支持任意日期范圍的人群圈選,BSI+字典服務(wù)的方案在存儲(chǔ)成本上具有顯著優(yōu)勢(shì),以下是一個(gè)支持5天內(nèi)任意日期范圍圈選場(chǎng)景下,預(yù)聚合bitmap方案和BSI方案的存儲(chǔ)成本對(duì)比:
方案 | 行數(shù) | 大小(壓縮前) | 大小(壓縮后) |
預(yù)聚合bitmap | 663 | 40732860 | 38043990 |
BSI+字典服務(wù) | 5 | 1790465 | 1753776 |
可以看到,BSI+字典服務(wù)的方案與預(yù)聚合Bitmap方案的存儲(chǔ)比約為1:21。
查詢性能收益
相較于原Bitmap方案,BSI+字典服務(wù)的方案在查詢性能方面也有明顯優(yōu)勢(shì)。下圖為一個(gè)90天范圍內(nèi)圈選場(chǎng)景,原Bitmap方案和BSI方案的查詢延遲對(duì)比:
圖片
7.總結(jié)與展望
本文重點(diǎn)介紹了DMP場(chǎng)景的業(yè)務(wù)需求及實(shí)踐過(guò)程中遇到的問(wèn)題,并詳細(xì)闡述了我們?nèi)绾卫肅lickHouse字典服務(wù)和BSI技術(shù)優(yōu)化增強(qiáng)DMP產(chǎn)品功能,提升整體查詢性能,降低資源成本。
目前BSI+字典服務(wù)方案已經(jīng)在B站商業(yè)化DMP場(chǎng)景完成落地上線,未來(lái)我們將重點(diǎn)在以下方向完善增強(qiáng)我們的產(chǎn)品功能:
- 工程化BSI+字典服務(wù)方案的數(shù)據(jù)接入流程,為用戶提供更為便利的接入體驗(yàn),讓BSI+字典服務(wù)方案賦能更多商業(yè)化業(yè)務(wù)場(chǎng)景。
- 探索BSI+字典服務(wù)的實(shí)時(shí)鏈路建設(shè),在低成本低查詢延遲的前提下,為用戶提供更高的end2end數(shù)據(jù)時(shí)效性。
- 得益于字典對(duì)人群圈選性能的提升,商業(yè)化業(yè)務(wù)正在嘗試擴(kuò)展人群圈選的業(yè)務(wù)范圍,例如投放端定向人數(shù)預(yù)估,預(yù)計(jì)24年Q4可以落地。
- 商業(yè)化DMP中嘗試BSI的更多應(yīng)用場(chǎng)景,例如用于多維度廣告相關(guān)指標(biāo)人群的畫(huà)像分析。
引用
- BSI Introduction From Hologres(https://www.alibabacloud.com/help/en/hologres/use-cases/profile-analysis-bsi-optimization-beta)
- BSI Function Introduction From Hologres(https://www.alibabacloud.com/help/en/hologres/user-guide/bsi-functions)