天天看點

阿裡CCO:基于Hologres的億級明細BI探索分析實踐

作者:張乃剛(花名:隽馳),CCO資料開發

CCO是Chief Customer Officer的縮寫,也是阿裡巴巴集團客戶體驗事業部的簡稱。随着業務的多元化發展以及行業競争的深入,使用者體驗問題越來越受到關注。CCO體驗業務營運小二日常會大量投入在體驗洞察分析中,旨在通過使用者的聲音資料結合交易、物流、退款等業務資料,洞察發現消費者/商家體驗鍊路上的卡點問題并推進優化,帶給消費者和商家更好服務體驗。

以今年3月為例,通過統計日志資料發現,共有80+業務同學送出了22000+個Query,都是圍繞着使用者心聲和業務資料的多元度交叉分析,如果按照每個Query小二平均投入10分鐘進行編寫、執行、檢查等操作來計算的話,共計投入458工作日,也就意味着這80+業務同學人均每個月至少有1周的時間全部投入在資料處理、運作上。業務側大量的洞察分析訴求也使得體驗洞察的數字化和智能化能力建設勢在必行,我們需要有能支援到業務複雜場景Ad-hoc查詢的資料能力和産品能力。

通過對資料産品的不斷疊代,我們采用Hologres+FBI支撐CCO體驗小二所有資料探索需求, 月均50億+明細資料聚合查詢秒級傳回,支援100+業務小二大促、日常的體驗營運洞察分析,助力業務小二單次洞察分析提效10倍以上, 解放業務同學的生産力。在文本中,我們也将會介紹CCO資料洞察産品基于Hologres在BI查詢場景的最佳實踐。

體驗洞察各階段方案演變

結合業務,我們梳理了目前CCO體驗洞察資料應用的幾個特點:

  • 資料覆寫場景廣。 覆寫了從使用者浏覽、下單、支付、發貨物流到售後退款等全鍊路的業務場景,資料涉及範圍廣。
  • 資料量較大。如交易類資料(億級/日)、退款類資料(千萬級/日)。
  • 實時時效以及多時間視窗對比訴求。如大促活動期間實時對使用者Top求助場景是否異常的判斷,涉及多種視窗(環比、同比、曆史同時段、活動期同時段等)對比,來進行影響面評估和預警布防。
  • 資料監控周期長。如大促期間的售後情況洞察,因為售後期較長,往往會鎖定大促周期的訂單,觀察後續N天的退款、糾紛資料變化。資料需重新整理的周期長。
  • 大量的快照類特征訴求。如分析使用者咨詢時刻的交易狀态、物流狀态等特征分布,用以分析使用者求助的真實訴求。

是以在整體資料方案落地的過程中,如何快速響應業務不斷變化的需求,同時考慮業務上的資料特點,選擇相對穩定且高可用的方案是我們需要面對的問題。這裡主要經曆了三個階段。

階段一:預計算聚合Cube( MOLAP )+ADB加速查詢

這個階段還未支援實時的洞察能力,采用的方式是比較正常的預計算聚合Cube結果集,即在MaxCompute側将所需要的交叉次元名額預計算好,形成一個ADS層的聚合名額結果寬表,通過外表或者DataX工具将聚合結果寫入到OLAP引擎加速查詢。此階段CCO較為主流的OLAP引擎選型主要是ADB、MySQL等。這種方案在應對較少且相對穩定的次元和名額組合時較為适用,因為結果已經預計算好,隻需要針對結果表進行簡單聚合計算,ADB也提供了穩定的查詢加速能力。以下為整體資料鍊路結構的簡單示意圖:

阿裡CCO:基于Hologres的億級明細BI探索分析實踐

但是随着業務場景的更加複雜化,存在的問題也極為明顯:

  • 靈活度差,擴充成本高。當業務上要增加新次元或名額時,需要在MaxCompute應用層多層添加邏輯、修改表結構并且需要回刷資料,資料的擴充成本十分高。
  • 資料量易爆炸。因為預計算的結果集最細粒度是所有次元的枚舉值交叉,隻要某幾個次元枚舉值比較多的話,交叉後的資料量就會存在大幅膨脹的可能,甚至膨脹到交叉後遠大于明細資料量級的情況。
  • 行業回刷成本高。因為次元特征預計算好的原因,類似淘系行業調整等較為常見的因素帶來的回刷無法避免。每一次行業調整,為了保證行業的準确性,都會需要一次全量的回刷。
  • UV類去重名額無法精确計算。遇到UV等需要去重計算的名額,因為預計算按照次元最細組合計算,再次聚合的時候不可避免會出現結果膨脹,無法精确的實作去重計算。
  • 資料回流時間長。離線資料通過Shell腳本操作外表或者DataX同步任務方式回流ADB,在資料量較大的時候同步時間長,并且在回流高峰的時候,因為槽位資源打滿,容易頻繁出現任務逾時、出錯,甚至庫抖動等問題,維護成本較高。

階段二:實體ID輕度彙總事實表+次元表關聯查詢

這個階段實時化洞察已經在很多場景有較強的訴求,故需要同時結合實時鍊路來考慮方案。方案一不适合實時鍊路的建設,主要在于預計算的多元彙總寬表難以确定PK,一旦次元組合發生變化,PK需要重新定義,無法穩定的支援upsert/update操作。

是以在這個階段主要針對擴充性靈活性等問題重新設計了方案。主要的思路是不做次元的預計算,而是抽取洞察場景内事實表的實體對象ID,建構基于這些實體對象ID的輕度彙總DWS名額層,然後将DWS名額事實表和實體對象的DIM表直接寫入到OLAP引擎,在資料服務或者FBI資料集這一層直接join查詢。

以共享零售為例,業務的本質是買家下單,貨從賣家流轉到買方。這裡的參與的對象有商品、商家、買家、騎手等,我們建構以商品ID+商家ID+買家ID+騎手ID的聯合主鍵,計算在這個主鍵下的各業務子產品的名額彙總事實表,然後利用OLAP引擎的強大的互動分析能力直接關聯事實表和維表做多元分析查詢。資料鍊路結構的簡單示意圖如下:

阿裡CCO:基于Hologres的億級明細BI探索分析實踐

這種方案對比方案一解決了擴充性問題,提升了靈活度,次元的擴充隻需要簡單調整維表即可,遇上行業的調整甚至無需做任何處理;同時PK穩定,也能支援到實時upsert。但也因為資料展現端關聯查詢邏輯複雜,性能上對OLAP引擎要求較高。存在的問題可以總結為以下幾點:

  • 大資料量下性能較差。資料應用端大量的join操作,尤其PK不相同無法走Local Join,在資料量較大的場景如淘系業務裡,性能難以支援。
  • UV類去重名額無法精确計算。本質上名額值依然是預計算,是以次元上再聚合時仍然會出現膨脹,不能精确計算去重值。
  • 部分特征次元無法支援。業務的洞察訴求越來越精細全面,交易特征、物流特征等一些屬性以及快照類資料,在這個方案中難以支援,如訂單的預售的類型、是否直播訂單等。
  • 實時離線對比視窗難實作。實時名額有較強的多時段不同點位的視窗對比訴求,當遇到當天XX小時同環比曆史同時段這類需求時,目前方案難以實作,預計算各種時長打點的曆史資料也不現實。

階段三:基于Hologres明細寬表的即席查詢

為了能支援到更加豐富的場景以及支援到實時離線聯邦查詢下靈活的視窗應用,我們方案的考慮方向轉向為不再做名額的預計算,直接将明細資料寫入到OLAP引擎,在資料集/資料服務等服務層直接關聯DIM表即席查詢。同樣這對OLAP引擎的性能要求極高,CCO在去年實時架構更新之後,參見CCO x Hologres:實時數倉高可用架構再次更新,雙11大規模落地,借助Hologres列存強大的OLAP能力及實時離線聯邦查詢能力使該方案落地變為可能。

沒有最好的方案,隻有在對應場景下做出取舍後相對适用的方案。在這個階段,我們犧牲了一定的查詢性能,選擇了對場景支援更豐富、實時離線聯邦查詢以及擴充靈活度更支援更佳的方案。當然在淘系這類較大資料量的業務場景中,我們也做了一定的優化和取舍。如在實際進行中,對于相對穩定的次元我們在MaxCompute/Flink處理寫入了明細,隻對于行業類目等這類易調整且相對敏感的次元直接在資料集/資料服務關聯查詢。

三種方案對比:

場景 方案一:預聚合 方案二:輕度彙總 方案三:明細即席查詢
查詢性能(較大資料量) 較好 一般 一般
次元支援 支援豐富但資料量易爆炸 支援範圍固定 次元支援豐富
擴充性 較差 較好
去重計算 存在膨脹 存在膨脹 可精确計算
實時離線聯邦查詢視窗對比 不支援 不支援 靈活支援
行業回刷 需要回刷 無需回刷 無需回刷

Hologres+FBI一體化體驗洞察資料實踐

結合CCO體驗業務在資料洞察應用場景中資料量大、周期長、鍊路範圍廣、次元特征多、實時離線對比視窗及快照特征訴求多等需求特點,我們利用Hologres+FBI的各種特性不斷在實踐中設計優化整體的解決方案。從資料應用訴求來說,使用者可以接受一定時間的傳回延遲,涉及較大資料量讀寫但同時查詢QPS較低,因而我們選擇犧牲一定的查詢RT,選擇使用基于Hologres明細的即席查詢的方案,整體流批兩條鍊路結構如下:

阿裡CCO:基于Hologres的億級明細BI探索分析實踐

如上所示,整體的方案是相對典型的Lambda結構:

  • 在實時的鍊路中,我們讀取各主題的實時公共層Holo Binlog或者TT/MQ消息,利用Flink的流處理能力,通過查詢持久化存儲的Hologres維表補齊模型所需的字段,同時通過事件觸發的消息,查詢維表/HSF接口完成狀态快照的采集,建構成ADS/MDS明細寬表,寫入到Hologres分區表的當日實時分區。
  • 在離線的鍊路中,我們讀取各主題的公共層及維表,以及T日實時采集的快照資訊,在T+1日建構離線的ADS/MDS明細寬表,通過MaxCompute外表方式Batch寫入到Hologres表的各曆史分區。為了保證T日分區在T+1日的無感切換,我們會通過中間表rename的方式保證瞬間切換。
  • 在上遊應用時通過搭建FBI資料集或資料服務,提供查詢Hologres明細表的即席查詢能力,支援多元交叉分析、大資料量下的去重計算、實時離線聯邦查詢等OLAP場景。

以下為我們針對上面提到的前階段資料使用存在的各種問題,在實踐應用中的一些詳細的技術方案。

表設計、 Table Group 及索引選擇

  • 表設計

主要查詢場景是基于明細按時間範圍的OLAP查詢,資料規模單日分區超數十億,同時也需要按天更新回刷資料,是以Hologres表的屬性選擇上,是列存+業務主鍵PK+日期分區表。

  • Table Group設定

Table Group的設定一般根據使用場景、資料量大小、Join頻次綜合考慮。需要關聯的表放入同一個Table Group,通過Local Join減少資料的Shuffle,可極大提升查詢效率。

Shard Count根據資料量選擇合适的大小。Shard數過小資料的讀寫會存在瓶頸,而Shard數過大會導緻日常固定的開銷以及查詢啟動的開銷增大造成浪費,大量的Shard數過大的表同時啟動查詢也容易給叢集的負載造成壓力,影響使用性能。目前體驗洞察實踐中,日增量億級的交易類明細結果Shard Count設定為128,退款、咨詢求助等日增量千萬左右的明細表Shard Count設定為32。

  • 索引設定

Hologres提供了Distribution Key、Clustering Key、Segment Key、Bitmap Columns等一系列的索引方式對表進行優化,合理的使用各類索引,可以大幅提升使用性能。分布建Distribution Key隻能是PK或PK的部分字段,選擇基于PK來設定;對于商家、類目、行業等經常用在Filter和Range場景的字段,我們對應的設定了聚簇索引Clustering Key。而對于大量的二分類的次元特征以及枚舉較少的字段,如是否直播訂單、商家分層等,我們對應設定了位圖索引Bitmap Columns等。

BEGIN;
CREATE TABLE "public"."ads_case_di" 
(
 "date_id" TEXT NOT NULL,
 "case_id" INT8 NOT NULL,
 "industry_name"  TEXT NOT NULL, 
 "seller_id"    INT8 NOT NULL,
 "seller_nick"  INT8 NOT NULL,
 "is_presale_order" TEXT,
 "is_live_order"    TEXT,
  XXX ,
 PRIMARY KEY ("date_id","case_id")
)
PARTITION BY LIST (date_id);
CALL SET_TABLE_PROPERTY('"public"."ads_case_di"', 'orientation', 'column');
CALL SET_TABLE_PROPERTY('"public"."ads_case_di"', 'segment_key', '"date_id"');
CALL SET_TABLE_PROPERTY('"public"."ads_case_di"', 'clustering_key', '"industry_name","seller_nick"');
CALL SET_TABLE_PROPERTY('"public"."ads_case_di"', 'bitmap_columns','"is_presale_order","is_live_order"');
CALL SET_TABLE_PROPERTY('"public"."ads_case_di"', 'dictionary_encoding_columns', '"industry_name","seller_nick","is_presale_order","is_live_order"');
CALL SET_TABLE_PROPERTY('"public"."ads_case_di"', 'time_to_live_in_seconds', '17280000');
COMMIT;
           

T+1分區覆寫方案

在Flink作業定義Hologres Sink表時,需要配置

partitionRouter

createPartTable

參數來保證流作業資料Sink到實時的分區以及在路由不到分區時自動建立分區。

partitionRouter = 'true' 
createPartTable = 'true'
           

Holo的分區表是子母表結構,子表的當日分區作為流作業的Sink表,T+1及之前的分區為離線任務Batch寫入,在每天上午離線任務排程結束資料生成後覆寫實時作業寫入的資料。而在T+1的離線資料寫入的時候,如何避免寫入時出現空分區或者查詢抖動,目前的方案是批寫入臨時子表然後rename并挂載到母表,可以瞬間完成T+1分區的資料切換,避免影響應用端使用體驗。以下以某個表示例。

BEGIN;

--線上表分區子表,如果不存在分區,就建立該分區
create table if not exists ads_tb_di_${bizdate} partition of ads_tb_di
  for values in ('${bizdate}');
--批資料寫入的中間表子表
create table if not exists ads_tb_di_batch_${bizdate} partition of ads_tb_di_batch
  for values in ('${bizdate}');
  
--解除線上表依賴關系
ALTER TABLE ads_tb_di DETACH PARTITION ads_tb_di_${bizdate};
--解除中間表依賴關系
ALTER TABLE ads_tb_di_batch DETACH PARTITION ads_tb_di_batch_${bizdate};
--名稱互換
ALTER TABLE ads_tb_di_${bizdate} RENAME to ads_tb_di_temp_${bizdate};
ALTER TABLE ads_tb_di_batch_${bizdate} RENAME to ads_tb_di_${bizdate};
--挂依賴
ALTER TABLE ads_tb_di ATTACH PARTITION ads_tb_di_${bizdate} FOR VALUES in ('${bizdate}');
--删除臨時批表
drop TABLE ads_tb_di_temp_${bizdate};

commit;
           

FBI的Velocity文法和Fax函數裁剪SQL優化查詢

在BI的使用上,我們選擇FBI(阿裡集團内部的一款BI分析産品)。目前FBI一個元件隻支援一個資料集,為了支援多元交叉分析應用,我們比較常見的方案是在資料集SQL中将所有可能用到的表拼接起來以備查詢。但實際的即席查詢場景中,使用者選擇的名額和次元可能隻使用到了資料集中的部分表,如果全量查詢資料集,會造成浪費同時也會影響查詢性能。

結合FBI的 Velocity文法和Fax函數等特性配置動态查詢可以實作根據使用者的選擇動态路由裁剪,在資料集中如下使用Velocity文法添加判斷語句,在擴充名額中配置動态查詢的參數。這裡的${tableindexorder} == ‘order’ 代表交易明細表,資料量較大。

阿裡CCO:基于Hologres的億級明細BI探索分析實踐
阿裡CCO:基于Hologres的億級明細BI探索分析實踐

在實際的即席查詢場景中,如使用者隻選擇了“糾紛介入率”這類名額和次元,和交易資料沒有關系,那麼最終執行的query将不會命中${tableindexorder} == ‘order’ 這個分支下的SQL,借此實作對資料集SQL的裁剪,進而避免了每次查詢都全量執行整體資料集,可以根據實際使用場景按照“不使用則不查詢”的原則提升查詢效率。

實時離線聯邦查詢靈活視窗對比

大促場景下實時離線聯邦查詢的訴求十分常見,尤其目前時間點位同環比曆史同期時段點位這類對比需求,目前基于明細寬表的即席查詢架構更加靈活高效。首先離線部分無需再進行預計算,尤其如果對比點位比較細的話,如5分鐘、10分鐘這類視窗點位的對比,那離線需要預計算準備的資料較為複雜,資料量也十分大。另外對于活動當天退款量、退款金額的累計趨勢這類很正常的訴求的實作,也不再需要通過Flink計算每個點位的數值,再通過視窗函數進行聚合。直接對關鍵時間字段增加打點字段,一個簡單的視窗函數即可完成累計趨勢圖的繪制。比如以下為一個10分鐘視窗累計趨勢的示例:

select  date_id
        ,create_time_10min ---10分鐘向後打點
        ,rfd_cnt --目前時間視窗退款量
        ,rfd_amt --目前時間視窗退款金額
        ,sum(rfd_cnt) over(partition by date_id order by create_time_10min asc) as total_rfd_cnt --累計退款量
        ,sum(rfd_amt) over(partition by date_id order by create_time_10min asc) as total_rfd_amt---累計退款金額
from    (
            select  date_id
                    ,create_time_10min
                    ,count(*) rfd_cnt
                    ,sum(refund_real_amt) as rfd_amt
            from    ads_tb_di
            where   date_id in ('20201111','20211111') --大促當天和曆史同比
            group by date_id
                     ,create_time_10min
        ) t
;
--create_time_10min 這裡是對退款發起時間的打點字段,等同于replace(substr(FROM_UNIXTIME(UNIX_TIMESTAMP(case_create_time) - (UNIX_TIMESTAMP(case_create_time)% (10 * 60)) + (10 * 60)),12,5),':','')
           

Hologres動态分區回刷

由于采用了Hologres分區表的設計方式,當遇到需要同時回刷多個曆史分區的情況時,由于Hologres分區是子母表結構且不支援向母表Insert資料,這裡實作動态回刷多分區這類場景相對麻煩一些,Hologres目前不支援程式塊腳本,一般需要通過python/perl等腳本來進行對分區子表的循環操作。在這裡我們采用DataWorks的控制節點配置用以相對簡單的實作對Hologres分區表的動态回刷。

UV類去重計算優化

在體驗洞察的場景裡,有着大量的去重計算的訴求,比如咨詢萬筆訂單求助量等這類名額,咨詢場景中會話量的計算大多是基于非主鍵列的計算,在目前這種基于明細的查詢下,雖然避免了預計算結果集上聚合資料值膨脹的情況,但大量的distinct操作極其影響性能。因而應對去重計算,在不同場景下我們做了些不同的優化方案選擇。

  • 重要場景精确計算&長緩存周期

在首屏核心名額塊這類重要的呈現場景,比如萬單求助量、小蜜發起量等重要觀測名額的大數概覽統計,因為名額的精确性要求,我們會使用distinct去重計算,這類名額數量不多,也因為不涉及下鑽分析隻是概覽統計,對于離線場景可以在FBI等展示端設定較長的緩存周期,查詢命中緩存的機率較高,可以一定程度的減少distinct帶來的性能影響。

  • 高頻次元場景使用RoaringBitmap高效去重

對于行業、類目等這一類重要并且高頻被使用到的的次元場景,并且這些次元對計算的精度也有着較高的訴求,為了保證去重計數查詢的性能,我們利用Hologres的RoaringBitmap的資料壓縮和去重特性在較大資料量下進行計算。因為RoaringBitmap本質上還是做了一層預聚合計算,如果次元太多粒度太細資料量也會膨脹的比較厲害,為了保證優化的效果,這裡我們選取部分重要次元,結合前文提到的FBI Velocity文法判斷,當查詢的次元命中在RoaringBitmap基礎聚合的次元範圍時,通過RoaringBitmap快速傳回結果。RoaringBitmap去重示例如下:

CREATE EXTENSION IF NOT EXISTS roaringbitmap; --建立roaringbitmap extention

-----建立映射表,用以映射去重字段serv_id到32位int類型
    BEGIN;
 CREATE TABLE public.serv_id_mapping (
     serv_id text NOT NULL,
     serv_id_int32 serial,
     PRIMARY KEY (serv_id) 
 );
CALL set_table_property('public.serv_id_mapping', 'clustering_key', 'serv_id');
CALL set_table_property('public.serv_id_mapping', 'distribution_key', 'serv_id');
CALL set_table_property('public.serv_id_mapping', 'orientation', 'column');
COMMIT;

-----建立基礎聚合結果表
BEGIN;
CREATE TABLE ads_tb_roaringbitmap_agg (
    date_id text NOT NULL,  --日期字段
    bu_type text,
    industry_name text,
    cate_level1_name text,
    cate_level2_name text, 
    cate_level3_name text, 
    uid32_bitmap roaringbitmap, -- 去重計算結果計算
  primary key(bu_type, industry_name,cate_level1_name,cate_level2_name, cate_level3_name, date_id)--查詢次元和時間作為主鍵,防止重複插入資料
);
CALL set_table_property('public.ads_tb_roaringbitmap_agg', 'orientation', 'column');
CALL set_table_property('public.ads_tb_roaringbitmap_agg', 'clustering_key', 'date_id');
CALL set_table_property('public.ads_tb_roaringbitmap_agg', 'event_time_column', 'date_id');
CALL set_table_property('public.ads_tb_roaringbitmap_agg', 'distribution_key', 'bu_type,industry_name,cate_level1_name,cate_level2_name,cate_level3_name');
end;

--------将映射表裡沒有的serv_id寫入進去
WITH
     serv_ids AS ( SELECT serv_id  FROM ads_xxx_crm_serv_total_chl_di WHERE date_id = '${bizdate}' GROUP BY serv_id )
    ,new_serv_ids AS ( SELECT a.serv_id  FROM serv_ids a LEFT JOIN serv_id_mapping b ON (a.serv_id = b.serv_id) WHERE b.serv_id IS NULL )
INSERT INTO serv_id_mapping SELECT  serv_id
FROM    new_serv_ids
;

------按照聚合條件聚合後插入roaringbitmap聚合結果表
WITH
    aggregation_src AS( SELECT date_id,bu_type, industry_name,cate_level1_name,cate_level2_name, cate_level3_name, serv_id_int32 FROM ads_xxx_crm_serv_total_chl_di a INNER JOIN serv_id_mapping b ON a.serv_id = b.serv_id WHERE a.date_id = '${bizdate}' )
INSERT INTO ads_tb_roaringbitmap_agg 
SELECT   date_id
        ,bu_type
        , industry_name
        ,cate_level1_name
        ,cate_level2_name
        ,cate_level3_name
        ,RB_BUILD_AGG(serv_id_int32)
FROM    aggregation_src
where cate_level3_name is not null 
and   bu_type is not null 
GROUP BY date_id 
        ,bu_type
        , industry_name
        ,cate_level1_name
        ,cate_level2_name
        ,cate_level3_name
;

-------執行查詢,RB_CARDINALITY 和 RB_OR_AGG 聚合計算
SELECT  bu_type
        , industry_name
        ,cate_level1_name
        ,cate_level2_name
        ,cate_level3_name
        ,RB_CARDINALITY(RB_OR_AGG(serv_id32_bitmap)) AS serv_cnt ---去重計算結果字段
FROM    ads_tb_roaringbitmap_agg
WHERE   date_id = '${bizdate}'
GROUP BY bu_type
        , industry_name
        ,cate_level1_name
        ,cate_level2_name
        ,cate_level3_name;
           
  • 多元交叉分析使用近似計算

而對于大多數次元場景,對去重并不是要求100%精确,使用Hologres自身的APPROX_COUNT_DISTINCT近似計算,去重精度誤差可達1%以内,在可接受範圍内且不會大幅影響查詢性能。同時可如下通過調整精度參數來控制計算的精确度,但也會相應的增加計算開銷,實測預設參數值17就可以達到較好的去重精度。

set hg_experimental_approx_count_distinct_precision = 20;
           

同時Hologres 1.3版本也支援了UNIQ函數,跟count distinct是一樣的語義,但是計算效率更高,更節省記憶體,後續我們将會使用。

快照采集及持久化離線存儲

前文提到了CCO側體驗洞察分析存在大量的快照類特征訴求,比如使用者咨詢時刻的貨物狀态、物流節點等,這類快照對分析使用者求助、退款時候的真實的境況和訴求及其重要。而這類快照在各類系統中不太可能都有業務埋點,是以需要資料側去加工得到對應的資料。這類快照資料如果通過批任務處理存在的主要問題是無法精準的擷取快照狀态,比如咨詢時的物流節點,通過離線ETL處理需要比對咨詢時間和物流各節點的時間卡先後順序得出當時的節點狀态,對節點的枚舉是否全面要求極高,并且處理複雜程度也較高。

阿裡CCO:基于Hologres的億級明細BI探索分析實踐

是以,通過實時的消息結合實時更新的持久化存儲的維表或線上接口來生成快照類資料是較為合适的方案,以咨詢時訂單狀态的實作為例,我們接入咨詢建立的TT/MQ,發生咨詢之後去查詢對應訂單維表或者TC接口,傳回的資料寫入當天的實時分區,在T+1日我們通過Hologres的外表導出的功能,将T日實時寫入的這類快照狀态字段從Hologres導出到MaxCompute做持久化離線存儲,在批任務的鍊路裡離線分區的快照類字段可JOIN這份資料産出,同時也可以用以後續的資料回刷、業務洞察分析。

--回寫至MaxCompute
INSERT INTO ads_holo_imp_di_foreign --外表,映射ODPS表ads_xxx_holo_imp_di
        ( 
           date_id               
          ,serv_id 
          ,xxx
        )
SELECT   date_id               
         ,serv_id   
         ,xxx
FROM ads_total_chl_di
WHERE date_id= '${bizdate}';
           

業務效果

一體化體驗洞察于本年初上線,目前主要支援在淘系退款、咨詢萬求等場景的實時多元交叉分析、智能異常檢測,月均50億+資料量級下的聚合查詢基本均能在秒級傳回,支援到100+業務小二大促、日常的體驗營運洞察分析,助力業務小二單次洞察分析提效10倍以上。

雙11大促期間(11.1-11.20),一體化洞察送出執行的Query數為66w+,假設50%的Query為有效查詢,同樣按照每個Query小二過去平均需要投入10分鐘進行編寫、執行、檢查等操作來計算,共計節省了6875人日,當然如果沒有對應的資料/産品能力,小二受限于SQL技能以及開發成本也不會産生這麼多查詢,但也側面反映了一體化洞察對小二們工作效率的有力提升。

阿裡CCO:基于Hologres的億級明細BI探索分析實踐

未來方向和思考

流批一體化

由于目前上遊依賴的中間層離線和實時模型還不能完全統一,整體的資料架構還是比較傳統的Lambda架構,需要維護離線、實時兩套任務,開發、任務運維的成本較高,并且實時、離線資料存在一定的差異。當然從一套代碼實作原先流批兩條鍊路的的角度來說,目前基于Hologres的架構下存儲統一、計算統一的前提都是具備的,後續我們主要推進DWD中間層的模型統一,完成一體化體驗洞察整體資料架構流批一體。

資料集服務管理

為了整體快速上線,目前仍有大量的FBI資料集直連Hologres庫而非托管在資料服務平台。因而資料集的監控、壓測、慢查詢的預警優化等沒法依托資料服務平台的能力納入統一管理,為了保障資料的穩定性、高可用性,後續需要将體驗洞察的所有資料集依托服務平台集中管控。