導(dǎo)讀:過去 3 年時(shí)間里鸵赫,Apache Doris 已經(jīng)在小米內(nèi)部得到了廣泛的應(yīng)用,支持了集團(tuán)數(shù)據(jù)看板宵蕉、廣告投放/廣告 BI酝静、新零售、用戶行為分析羡玛、A/B 實(shí)驗(yàn)平臺(tái)别智、天星數(shù)科、小米有品稼稿、用戶畫像薄榛、小米造車等小米內(nèi)部數(shù)十個(gè)業(yè)務(wù)讳窟,并且在小米內(nèi)部形成了一套以 Apache Doris 為核心的數(shù)據(jù)生態(tài) 。本文將為大家分享小米用戶行為分析平臺(tái)基于 Apache Doris 向量化版本的改造實(shí)踐敞恋,包括數(shù)據(jù)存儲(chǔ)架構(gòu)和查詢服務(wù)架構(gòu)的演進(jìn)與改造經(jīng)驗(yàn)分享丽啡。
作者|小米數(shù)據(jù)智能部開發(fā)工程師 湯佳樹
小米用戶行為分析統(tǒng)一平臺(tái)是基于海量數(shù)據(jù)的一站式、全場(chǎng)景硬猫、多模型补箍、多維度、自助式大數(shù)據(jù)智能洞察分析服務(wù)平臺(tái)啸蜜,對(duì)接各類數(shù)據(jù)源坑雅,進(jìn)行加工處理、分析挖掘和可視化展現(xiàn)盔性,滿足各類用戶在用戶洞察場(chǎng)景下的數(shù)據(jù)分析應(yīng)用需求霞丧,提供高效極致的分析體驗(yàn)呢岗。
業(yè)務(wù)需求
平臺(tái)可以基于數(shù)據(jù)進(jìn)行時(shí)間分析冕香,留存分析,分布分析后豫,漏斗分析等悉尾,業(yè)務(wù)方主要基于事件進(jìn)行分析,事件是追蹤或記錄的用戶行為或業(yè)務(wù)過程挫酿,可以是單個(gè)事件也可以是多個(gè)事件組合的虛擬事件构眯。
數(shù)據(jù)來源于各業(yè)務(wù)的打點(diǎn)數(shù)據(jù),且基于事件模型進(jìn)行建模早龟,用戶在產(chǎn)品中的各種操作都可以抽象成 Event 實(shí)體惫霸,并且里面都會(huì)包含五要素:
Who:即參與這個(gè)事件的用戶是誰,例如用戶的唯一 ID
When:即這個(gè)事件發(fā)生的實(shí)際時(shí)間葱弟,例如time字段壹店,記錄精確到毫秒的事件發(fā)生時(shí)間
Where:即事件發(fā)生的地點(diǎn),例如根據(jù) IP 解析出的省份和城市
How:即用戶從事這個(gè)事件的方式芝加,例如用戶的設(shè)備硅卢,使用的瀏覽器,使用的 App 版本等等
What:描述用戶所做的這件事件的具體內(nèi)容藏杖,例如點(diǎn)擊類型的事件将塑,需要記錄的字段有點(diǎn)擊 URL,點(diǎn)擊 Title蝌麸,點(diǎn)擊位置等
數(shù)據(jù)基于 OLAP 引擎 Doris 進(jìn)行存儲(chǔ)点寥,隨著接入業(yè)務(wù)不斷增多,且接入的業(yè)務(wù)量不斷膨脹来吩,Top 級(jí)應(yīng)用可以達(dá)到 100 億條/天敢辩,查詢壓力和時(shí)間相繼增大汉柒,用戶對(duì)查詢時(shí)延的吐槽愈來愈多,我們急切的需要提升查詢性能來提升用戶的體驗(yàn)责鳍。
痛點(diǎn)問題
針對(duì)于業(yè)務(wù)需求碾褂,我們總結(jié)了以下痛點(diǎn)問題:
為了實(shí)現(xiàn)復(fù)雜的業(yè)務(wù)需求,OLAP 分析引擎需要留存历葛、漏斗等分析函數(shù)支撐正塌。
增量數(shù)據(jù)?100億/天,導(dǎo)入壓力大恤溶,部分業(yè)務(wù)要求數(shù)據(jù)導(dǎo)入不丟不重乓诽。
業(yè)務(wù)接入不斷增多,數(shù)據(jù)量膨脹咒程,需要 PB 級(jí)的數(shù)據(jù)下的交互式分析查詢達(dá)到秒級(jí)響應(yīng)鸠天。
為了解決以上的痛點(diǎn)問題,我們對(duì)比了多款 OLAP 分析引擎帐姻,最終選擇了 Apache Doris稠集。Doris 提供了留存、漏斗分析等函數(shù)饥瓷,極大程度的簡(jiǎn)化了開發(fā)的成本剥纷。在數(shù)據(jù)導(dǎo)入的過程中,我們嘗試 Doris 剛推出的?Merge On Write Unique Key?導(dǎo)入模型呢铆,可以抗住?100 億/天的增量數(shù)據(jù)壓力晦鞋。針對(duì)于向量化查詢引擎的改造也是的性能較之前的版本有?3-5 倍的提升。
架構(gòu)演進(jìn)
一個(gè)優(yōu)秀的系統(tǒng)離不開持續(xù)迭代與演進(jìn)棺克。為了更好的滿足業(yè)務(wù)需求悠垛,我們?cè)诖鎯?chǔ)架構(gòu)與查詢引擎兩個(gè)層面上不斷進(jìn)行嘗試,小米用戶行為分析系統(tǒng)在上線后娜谊,目前已完成 3 次改造确买,以下將為大家介紹改造歷程。
數(shù)據(jù)存儲(chǔ)結(jié)構(gòu):數(shù)據(jù)架構(gòu)的演進(jìn)
在小米的用戶行為分析平臺(tái)中因俐,原始數(shù)據(jù)通過小米自研的消息隊(duì)列 Talos拇惋,在 Flink 中清洗與建模后,被下游的 Doris 與 Hive 消費(fèi)抹剩。全量的數(shù)據(jù)會(huì)存儲(chǔ)在 Hive 中撑帖,進(jìn)行批量 ETL 或歷史數(shù)據(jù)召回的查詢。實(shí)時(shí)增量數(shù)據(jù)被存儲(chǔ)在 Doris 中澳眷,用來做熱數(shù)據(jù)的查詢操作胡嘿。基于冷熱數(shù)據(jù)分離的架構(gòu),我們進(jìn)行了 3 次架構(gòu)的演進(jìn)钳踊。
第一階段:基于明細(xì)寬表的查詢
在最初的階段我們使用了基于明細(xì)的寬表查詢模式衷敌。為了處理靈活多樣的分析請(qǐng)求勿侯,在系統(tǒng)中,我們配合統(tǒng)一埋點(diǎn)平臺(tái)處理數(shù)據(jù)缴罗,接入的 OLAP 的數(shù)據(jù)是直接埋點(diǎn)的全字段展平助琐。在入庫之前,我們?cè)?Flink 中將數(shù)據(jù)打平面氓,以寬表的模式存儲(chǔ)在 Doris 明細(xì)表中兵钮。根據(jù)查詢的需求,我們將經(jīng)常使用的列作為建表的維度列舌界,利用前綴索引的特性進(jìn)行查詢加速掘譬。但某些頭部大數(shù)據(jù)量業(yè)務(wù)容易查詢多天數(shù)據(jù),一個(gè)大查詢可能就會(huì)將集群資源占滿甚至導(dǎo)致集群不可用呻拌,且查詢耗時(shí)相當(dāng)之久葱轩。
第二階段:基于聚合模型的查詢加速
在改造的第二階段,我們使用了聚合模型對(duì)業(yè)務(wù)查詢進(jìn)行加速藐握。?我們對(duì)接入行為分析的應(yīng)用進(jìn)行統(tǒng)計(jì)分析靴拱,絕大多數(shù)接入行為分析的應(yīng)用數(shù)據(jù)量在 1 億/天數(shù)據(jù)量以內(nèi)。對(duì)于部分使用頻率較高的表趾娃,我們采用聚合表完成查詢加速缭嫡,對(duì)單天數(shù)據(jù)量超 10 億且高頻的頭部應(yīng)用做聚合表加速缔御。具體流程為根據(jù)數(shù)據(jù)量挑選出頭部應(yīng)用抬闷,對(duì)其進(jìn)行字段解析,并挑選出常用指標(biāo)及維度耕突,由 Hive 表數(shù)據(jù)進(jìn)行聚合 T-1 產(chǎn)出數(shù)據(jù)笤成,最后寫入到 Doris 中,進(jìn)行查詢加速眷茁。該階段的改造解決了集群頭部業(yè)務(wù)大查詢的問題炕泳,此時(shí)雖然獨(dú)立集群存儲(chǔ)沒問題,但由于其他業(yè)務(wù)接入后還會(huì)持續(xù)增加數(shù)據(jù)量和?埋點(diǎn)字段 上祈,這樣會(huì)導(dǎo)致元數(shù)據(jù)最先進(jìn)入瓶頸培遵。
第三階段(當(dāng)前階段):業(yè)務(wù)適配的建表改造
當(dāng)前階段,我們對(duì)業(yè)務(wù)需求進(jìn)行深度解析后重新規(guī)劃了建表結(jié)構(gòu)登刺。我們對(duì)某些應(yīng)用的埋點(diǎn)字段進(jìn)行分析籽腕,發(fā)現(xiàn)有些用戶埋點(diǎn)字段多達(dá) 500+,但在行為分析里實(shí)際用到的可能只有 100+纸俭,這顯然有所浪費(fèi)皇耗。所以我們與用戶溝通調(diào)研需求,配合行為分析平臺(tái)側(cè)的能力揍很,用戶可在平臺(tái)對(duì)有用事件和屬性進(jìn)行篩選郎楼,同時(shí)設(shè)置字段映射和過濾邏輯万伤,然后再進(jìn)行建表。
查詢服務(wù)架構(gòu):查詢引擎的改造與演進(jìn)
我們基于業(yè)務(wù)深度改造了查詢的服務(wù)架構(gòu)呜袁,構(gòu)建了新的查詢引擎架構(gòu)敌买,實(shí)現(xiàn) SQL 的權(quán)重、路由阶界、緩存和資源調(diào)度操作放妈。根據(jù)查詢條件,路由引擎會(huì)將 SQL 拆分成多條子查詢荐操,在 Doris 或 Hive 中執(zhí)行后芜抒,將子查詢的結(jié)果匯總,得到最終的結(jié)果托启。針對(duì)查詢引擎宅倒,我們也進(jìn)行了 3 次技術(shù)架構(gòu)的改造。
第一階段:基于集群粒度的查詢資源管理
我們對(duì)集群粒度進(jìn)行查詢資源管理屯耸,在資源調(diào)度中拐迁,我們會(huì)給每一個(gè) Doris 集群設(shè)置一個(gè)總的資源池大小(根據(jù)集群能力和測(cè)試進(jìn)行量化)疗绣,根據(jù)數(shù)據(jù)量大小和查詢天數(shù)對(duì)每個(gè) SQL 進(jìn)行加權(quán)线召,并對(duì)資源池的最大最小并行 SQL 數(shù)進(jìn)行限制,如果計(jì)算的 SQL 超過限制則進(jìn)行排隊(duì)多矮。其次缓淹,還會(huì)利用 Redis 對(duì)數(shù)據(jù)進(jìn)行 SQL 級(jí)別緩存。
第二階段:基于 SQL 路由的改造
為適配聚合表加速做了路由層塔逃,提升緩存命中率和利用率讯壶,此階段拆分原始提交 SQL,基于指標(biāo)進(jìn)行緩存湾盗,粒度更細(xì)伏蚊,服務(wù)端可根據(jù)指標(biāo)進(jìn)行適當(dāng)計(jì)算更易于緩存命中。值得一提的是排隊(duì)時(shí)間往往會(huì)比較長格粪,有些場(chǎng)景下可能會(huì)進(jìn)行重復(fù)提交或拆分成同樣的 SQL躏吊,為了提高效率會(huì)在 SQL 排隊(duì)前和排隊(duì)后各進(jìn)行一次緩存校驗(yàn)。
第三階段(當(dāng)前階段):基于 SQL 權(quán)重的改造
整體架構(gòu)方面帐萎,由于采取了篩選埋點(diǎn)字段而非全量字段導(dǎo)入 Doris比伏,針對(duì)頭部問題用戶,我們會(huì)基于查詢歷史統(tǒng)計(jì)指標(biāo)及維度吓肋,根據(jù)指定的某些規(guī)則進(jìn)行默認(rèn)初始化操作凳怨,并以此溝通用戶并進(jìn)行引導(dǎo)升級(jí)。此外為了更精細(xì)的控制資源調(diào)度,本階段對(duì)對(duì) SQL 內(nèi)容進(jìn)行加權(quán)肤舞,如含有DISTINCT紫新,LIKE,VARIANCE_SAMP等字樣再加權(quán)李剖。對(duì)于資源消耗較大的操作芒率,如 DISTINCT,會(huì)給予更高的權(quán)重篙顺,調(diào)度引擎在執(zhí)行時(shí)會(huì)分配更多的資源偶芍。
實(shí)踐應(yīng)用
數(shù)據(jù)建模
對(duì)業(yè)務(wù)來講,分析查詢需要較高的靈活度德玫,且是對(duì)用戶粒度進(jìn)行分析匪蟀,所以需要保留較多的維度和指標(biāo),我們選用 Doris 作為存儲(chǔ)查詢引擎宰僧,且采用明細(xì)表建模材彪,這樣可以保證用戶能夠根據(jù)分析需求查出數(shù)據(jù)。另一方面琴儿,由于查詢分析是一個(gè)延時(shí)要求較高的產(chǎn)品段化,對(duì)于數(shù)據(jù)量大、查詢天數(shù)多造成、語句復(fù)雜的情況显熏,查詢延時(shí)會(huì)很高,所以對(duì)于頭部應(yīng)用晒屎,我們根據(jù)高頻指標(biāo)維度進(jìn)行了聚合表模型建模喘蟆。
CREATETABLE`doris_XXX_event`(`olap_date`bigint(20)NOTNULLCOMMENT"",`event_name`varchar(256)NOTNULLCOMMENT"",`uniq_id`varchar(256)NOTNULLCOMMENT"",`dim1`varchar(256)REPLACENULLCOMMENT"",`dim2`varchar(256)REPLACENULLCOMMENT"",? ...`cnt`bigint(20)REPLACENULLCOMMENT"",`index1`doubleREPLACENULLCOMMENT"",`index2`doubleREPLACENULLCOMMENT"",? ...) ENGINE=OLAPAGGREGATEKEY(`olap_date`,`event_name`,`uniq_id`)COMMENT"OLAP"PARTITIONBYRANGE(`olap_date`)
數(shù)據(jù)導(dǎo)入
明細(xì)表部分,我們接入 Json 格式 TalosTopic夷磕,動(dòng)態(tài)獲取 Doris 表的 Schema 信息履肃,通過雙緩沖區(qū)循環(huán)攢批的方式,利用 StreamLoad 向 Doris 中寫數(shù)據(jù)坐桩,如果在導(dǎo)入 Doris 時(shí)有出現(xiàn)失敗的批次,重試 10 次仍然失敗封锉,會(huì)將數(shù)據(jù)按照應(yīng)用粒度存入 HDFS绵跷,并在凌晨定時(shí)調(diào)度任務(wù)重新寫入 T-1 未寫入的數(shù)據(jù)。聚合表部分成福,我們由 Talos 落盤的 Iceberg 表碾局,每日進(jìn)行 T-1 數(shù)據(jù)的聚合,根據(jù)服務(wù)端選取的維度和指標(biāo)奴艾,以及聚合類型(count?,count distinct?,?sum?,max?,min )净当,進(jìn)行聚合存入中間 Hive 表,再由統(tǒng)一導(dǎo)入 Doris 程序進(jìn)行導(dǎo)入。
數(shù)據(jù)管理
明細(xì)數(shù)據(jù)和應(yīng)用聚合表分庫存儲(chǔ)像啼,TTL 均為 33 天俘闯。數(shù)據(jù)表會(huì)有數(shù)據(jù)質(zhì)量監(jiān)控,如果總行數(shù)或者設(shè)置指標(biāo)環(huán)比波動(dòng)太大忽冻,會(huì)進(jìn)行告警人工介入確認(rèn)數(shù)據(jù)是否有誤真朗,視緊急程度進(jìn)行回補(bǔ)處理。
數(shù)據(jù)查詢及應(yīng)用
絕大多數(shù)用戶會(huì)錨定事件僧诚,進(jìn)行含指標(biāo)聚合遮婶,去重用戶數(shù)(幾乎占總查詢的 50%)的事件行為分析检疫,同時(shí)還會(huì)有留存分析蟀俊,漏斗分析,分布分析等分析類型曼库。
建表模型的維護(hù)
為了適配業(yè)務(wù)的變更慈省,上游的埋點(diǎn)信息會(huì)周期性的更新肩豁。原有的表結(jié)構(gòu)需要進(jìn)行變更以適配埋點(diǎn)的增加。在過去的 Doris 版本中辫呻,Schema Change 是一項(xiàng)相對(duì)消耗較大的工作清钥,需要對(duì)文件進(jìn)行修改。在新版本中開啟 Light Schema Change 功能后?放闺,?對(duì)于增減列的操作不需要修改文件祟昭,只需要修改 FE 中的元數(shù)據(jù),從而實(shí)現(xiàn)毫秒級(jí)的 Schame Change 操作怖侦。
應(yīng)用現(xiàn)狀
小米目前在?300?多個(gè)業(yè)務(wù)線上線了 Doris 集群篡悟,超過?1.5PB?的業(yè)務(wù)數(shù)據(jù)。在初期我們選擇了兩個(gè)使用較為頻繁的集群進(jìn)行向量化升級(jí)匾寝。
現(xiàn)遷移 Doris 向量化集群的行為分析業(yè)務(wù)有 2 個(gè)搬葬,7 天增量數(shù)據(jù)的平均值在百億左右,存儲(chǔ)空間占用?7T/天左右艳悔。在升級(jí)到向量化的版本后急凰,存儲(chǔ)資源有較大的節(jié)省,只需要原有集群約 2/3 的存儲(chǔ)空間猜年。
性能提升
請(qǐng)求粒度
升級(jí) Doris 向量化版本后抡锈,行為分析平臺(tái)以請(qǐng)求粒度統(tǒng)計(jì)查詢耗時(shí) P80 和均值,P80 耗時(shí)下降 43%?乔外,平均耗時(shí)下降 27%?床三;統(tǒng)計(jì)口徑:匯總 12.07-12.11 期間,行為分析請(qǐng)求粒度查詢執(zhí)行時(shí)間杨幼。
SQL 粒度
升級(jí) Doris 向量化版本后撇簿,行為分析平臺(tái)以?SQL 粒度來統(tǒng)計(jì)查詢耗時(shí) P80 和均值聂渊,耗時(shí) P80?下降 70%?,平均耗時(shí)下降 54%?四瘫。統(tǒng)計(jì)口徑:匯總 12.04-12.11 期間汉嗽,行為分析 SQL 粒度查詢執(zhí)行時(shí)間(未含排隊(duì))
升級(jí) Doris 向量化版本后,行為分析平臺(tái)以?SQL 粒度統(tǒng)計(jì)查詢耗時(shí) P80 和均值莲组,耗時(shí) P80?下降 56%?诊胞,平均耗時(shí)下降 44%?;
統(tǒng)計(jì)口徑:匯總 12.02-12.11锹杈,行為分析 SQL 粒度查詢總時(shí)間?(含排隊(duì))
去重優(yōu)化
在 ID-Mapping 的時(shí)候撵孤,通常需要針對(duì) ID 進(jìn)行去重操作。在最初我們使用了COUNT DISTINCT來完成去重竭望。
SELECTa.`olap_date`AS`time`,count(distincta.`distinct_id`)ASdistinct_idFROManalysis.doris_XXX_event aWHERE`a`.`olap_date`BETWEEN20221218AND20221220ANDa.`event_name`IN(XXXX, XXX, XXX, XXX)AND... ...GROUPBY1ORDERBY2DESCLIMIT10000
在經(jīng)過優(yōu)化后邪码,我們使用子查詢+ GROUP BY來替代COUNT DISTINCT的功能
SELECTz.`time`,count(distinct_id) var1FROM(SELECTa.`olap_date`AS`time`,? ? ? ? ? ? ? ? ? ? ? ?? a.`distinct_id`ASdistinct_idFROManalysis.doris_XXX_event aWHERE`a`.`olap_date`BETWEEN20221218AND20221220ANDa.`event_name`(XXXX, XXX, XXX, XXX)AND... ...GROUPBY1,2) zGROUPBY1ORDERBY2DESCLIMIT10000
相較于原有的COUNT DISTINCT,使用子查詢+ GROUP BY?的模式性能有?1/3 的提升咬清。
未來規(guī)劃
在過去的三年時(shí)間里闭专,Apache Doris 已經(jīng)在小米內(nèi)部得到了廣泛的應(yīng)用,支持了集團(tuán)數(shù)據(jù)看板旧烧、廣告投放/廣告 BI影钉、新零售、用戶行為分析掘剪、A/B 實(shí)驗(yàn)平臺(tái)平委、天星數(shù)科、小米有品夺谁、用戶畫像廉赔、小米造車等小米內(nèi)部數(shù)十個(gè)業(yè)務(wù),并且在小米內(nèi)部形成了一套以 Apache Doris 為核心的數(shù)據(jù)生態(tài) 匾鸥。隨著業(yè)務(wù)的持續(xù)增長蜡塌,未來我們會(huì)進(jìn)一步推動(dòng)小米的其他業(yè)務(wù)上線向量化版本。
非常感謝 Apache Doris 社區(qū)與 SelectDB 公司的鼎力支持勿负,小米集團(tuán)作為 Apache Doris 最早期的用戶之一馏艾,一直深度參與社區(qū)建設(shè),參與 Apache Doris 的穩(wěn)定性打磨笆环,未來我們也會(huì)密切聯(lián)系社區(qū)攒至,為社區(qū)貢獻(xiàn)更多的力量。