Kylin 在 58 集團的實踐和應用

2019-12-10     sandag

01

平台優化

目前在 58,用戶可以通過兩種方式來接入 Kylin 平台。一種是通過我們數據產品部開發的 「 魔方 」 接入,「魔方」是一個多維分析的 BI 平台。另一種是直接通過域名連到 Kylin 平台,來進行 Cube 查詢和構建。

Kylin 依賴的 Yarn 和 HBase 集群,在 58 都是多租戶集群,所以我們對 Kylin 做了一些多租戶的優化,後面會講到。另外,針對 Cube 的調度,我們還開發了一套調度系統,還有其他的一系列的管理工具。

先說一下我們的 Yarn 集群、HDFS 集群和 HBase 集群的現狀。在 Yarn 方面,不同用戶提交的作業會跑在對應的隊列上。在 HDFS 方面,我們對用戶權限控制比較嚴,用戶目錄權限設置為 500,其他用戶是沒法訪問的。在 HBase 方面,我們將 Hadoop 帳號和 HBase 帳號進行了打通,同時使用 HBase 的 Namespace 機制來做權限隔離,即不同的用戶使用不同的 Namespace 來隔離表。由於以上多方面的現狀,我們在引入 Kylin 提供給用戶使用時,不得不面對 Kylin 需要支持多租戶的問題。

以下是我們 在多租戶方面做的優化

我們說一下 Kylin 的多租戶現狀,它其實是支持多用戶登錄的。

針對用戶和角色,Cube 有不同的訪問權限。但是它在使用底層集群資源的時候,比如說 Yarn、HBase 或者 HDFS 的時候,用的是 Kylin 啟動的帳號。而使用我們 Kylin 的用戶,來自於公司各個不同的部門,他們對應的 Yarn 有不同的隊列,HDFS 有不同的目錄,HBase 對應了不同的 Namespace。我們需要做到對不同的登錄用戶,在使用 Yarn、HDFS、HBase 的時候,能夠用對應的登錄用戶去訪問不同的集群資源。

下圖是我們做多租戶優化的目標:

根據前面的目標,我們做了一些開發工作,以下是我們實現的步驟。由於我們的 Hadoop 集群使用的是自研的一套權限認證,簡單但是很適用,一定程度上減輕了 Kylin 多租戶功能開發工作。

修改 Kylin 的 security profile 為 testing,在 testing 模式下,針對用戶管理就可以實現自定義功能了。我們自定義了一個用戶配置文件,叫做 kylin-user.properties 文件。我們重新實現了用戶的詳細接口,會動態、定時地去刷新文件到內存里去,這樣的話在內存裡邊就有用戶信息了,用戶在登錄的時候,就可以拿到登錄信息。

當 Kylin 的構建任務使用 Yarn 時,Kylin 支持在 Cube 這一級去配置隊列參數。如果說 Cube 上沒有配置,就使用 project 上的隊列配置。如果 project 上沒有配置,就會按登錄用戶,按默認算法生成隊列。

HDFS 這一塊也是一樣的,當需要面臨 HDFS 上數據的訪問,我們會用登錄用戶生成 Hadoop UGI,然後在 Hadoop UGI 上執行 doAs(),這樣的話就會把登錄用戶的信息傳遞給 HDFS。我們用到的 Hive 模式就是客戶端模式,會在本地提交一個 Hive 腳本,我們會根據登錄用戶設置環境變量 HADOOP_PROXY_USER 來實現多租戶功能。

對於 HBase,Kylin 會用來進行數據存儲和查詢。就像之前說的,我們會創建不同的 Namespace 來隔離不同用戶的表,同時 Namespace 是和 Hadoop 帳戶一一對應的。在創建 Kylin 表時,我們使用登錄用戶作為表的 Namespace。查詢的時候,用登錄用戶生成 Hadoop UGI 去構造 HBase 的 connection 去查詢,這樣就簡單實現了 Kylin 使用 HBase 的多租戶。

以上就是我們多租戶的優化。

下面講一下我們 在 Kylin 上做的一些優化

第一個是 維度字典上傳優化 。現象是用戶在使用 Kylin 過程中,出現了部分 Cube 的 Build 任務執行延遲較大,甚至無法啟動的情況,而且根據統計對比發現整個集群任務構建時間逐漸增加。

原因是 Cube 構建過程中,有多個步驟需要運行 MR 作業,同時需要將包括維度字典文件(維度編碼設置為了字典)以及其他的元信息文件作為分布式緩存上傳 HDFS,並下載到計算節點本地。隨著時間的推移,字典文件會越來越多(Segment增多),導致總的上傳時間越來越長。當文件總大小太大時,出現分布式緩存文件上傳超時,最終任務無法啟動。

以下是 Cube 構建中,單個 MR 作業進行分布式緩存文件上傳下載流程:

Cube 構建 MR 作業分布式緩存上傳下載文件默認包括元信息文件以及字典文件:元信息包括 Cube 信息、Segment 信息、Fact 表信息、Model 信息以及配置信息等;字典文件就是維度字典文件,默認會包括所有 Segment 的維度字典文件,隨著時間推移,Segment 會越來越多,維度字典文件的數據量會越來越大。

以下是 Cube 構建的整體流程圖:

整個構建過程包括多個 MR 作業,其中分布式緩存上傳和下載元信息文件和字典文件的 MR 作業包括、、、、、,分別對應:

、對維度欄位進行去重的 MR 作業;

、計算 Base Cuboid 的 MR 作業;

-、計算 N-1 至 0 維 Cuboid 的 MR 作業,可能有很多個 MR 作業,由維度個數決定;

、根據前面 至 生成的 Sequence File 最終聚合生成 HFile 的 MR 任務。

默認情況下以上所有 MR 作業都會通過分布式緩存上傳和下載元信息文件和 Cube 對應所有 Segment 的維度字典文件。通過仔細分析發現,我們可以進行以下兩種優化:

第一種:有的步驟並不需要 Segment 維度字典文件,比如、、、、。

第二種:有的步驟只需要部分維度字典,比如的構建 Base Cubeid 的 MR 作業,只需要當前構建 Segment 的維度字典。在 Cube 的 Segment 合併時,也只需要參與合併的 Segment 的維度字典文件,可以類似進行優化。

我們對上傳的 Segment 維度字典文件的流程進行了優化後,在生產環境取得了很好的效果,使得 Cube 的構建過程整體減少了 20% 的時間,同時很少出現作業無法啟動的情況。

第二個優化就是數據量預估,之前我們遇到一個問題,就是 Kylin 生成的表比較多。Cube 構建後需要對數據量預估,根據預估的結果來決定需要創建的 HBase 表的分區數,但是發現有時最終數據量並不大的情況下,創建的表分區數還比較多,使得 HBase 集群分區管理壓力增大,浪費大量資源;而有時最終數量很大,但是創建的 HBase 表分區過少,導致 Kylin 查詢緩慢。這是由於默認 Cube 數據量預估算法預估出來的數據量和實際的數據量存在較大偏差,導致 Kylin 創建的 HBase 表分區數大部分情況下不合理。

在估算總數據量時,總條目數的估算誤差較小,單是對單條長度的估算偏差較大。對於維度值的長度和普通數據類型的度量值長度值都可以根據數據類型確定,但是對於特殊數據類型的度量,比如度量類型為 BitMap 和 HyperLogLog,估算其長度時就會有一些問題了:

BitMap:用於對度量基數(count distinct)的精確計算,其長度大小由度量的基數決定,由於度量基數無法提前確定,導致無法獲取 BitMap 的實際長度值。Kylin 採取折中辦法,估算時使用一個固定值 8 k,如果對應度量基數很高,其大小很容易超過 8 k,就會導致單行預估的長度偏低。

HyperLogLog:用於對度量基數(count distinct)非精確計算,其長度是由用戶選擇的精度來決定的。如果誤差率控制在1.22%以內,那麼HyperLogLog會使用64k的空間來存儲數據,在支持壓縮的情況下,實際的長度會小於64k,而且如果度量基數較小,HyperLogLog存儲的數據會比較稀疏,壓縮效果會更好,這就導致單行預估的長度偏高。

我們解決的辦法是使用已有 Segment 數據,預估新建的 Segment 數據量,算法如下圖所示。基本思路是同一個 Cube 用最近一個 Segment 的統計數據來預估當前 Segment 的總數據量,統計數據包括最近一個 Segment 對應 Hive 表分區的輸入記錄數(InputRowsCounts),最終存儲到 HBase 的實際大小 (HtableSize),然後計算出每行輸入記錄對應的數據大小,將這個大小作為新 Segment 的每行數據大小,並乘以新 Segment 的 Hive 表分區輸入記錄數,將這個數作為新 Segment 最終的數據量大小。

通過使用新的預估算法,能有效將 HBase 表分區個數誤差由 >50 降至 <=1,從而避免了創建過多或者過少的分區,使得 Kylin 查詢性能更加穩定,同時減小了 HBase 集群的分區管理壓力。

在我們的舊版本里也做了其他的優化,比如說全局字典頻繁換進換出,在 Kylin v2.5 裡面也解決了。

02

版本升級

前面講到我們典型的優化,前面的優化是 v1.5.3 的。我們最近在遷移一些項目,從另外一個部門把一些Cube 遷移到我們這裡,發現 v1.5.3 存在一些問題:有些語法或者說函數不支持,全局字典構建時容易損壞,不支持用戶留存分析,一個 Cube 不能並行構建多個 Segments 數據。我們就調研了 v2.6,v2.6 的新功能或特性如下圖,基本解決我們在 v1.5.3 上遇到的問題。

我們上線 v2.6 後,目前已經遷移或者說正在遷移的有 20 個 Cube,穩定運行 1 個月。我們在引入 v2.6 的時候,進行了一些優化,比如說版本兼容修改、讀寫分離等,Spark 構建和自動剪枝我們也都在嘗試之中。

目前已運行了將近 1 個月,還是很穩定的,如果大家能夠升級的話,最好升級到新版本。

03

案例分享

我來分享一個案例。項目背景是我們有一個 推薦系統 ,在 APP、PC、M 三端上做推薦位的推薦,這個推薦會涉及一些疊代,或者說涉及到樣式的變更和不斷的優化,這些優化的效果要進行對比。在很早以前我們用的是 Hive+MySQL 這樣的方式去實現對比,分析的效果不是很好,後面就改成 Kylin,並重構了這套效果評價系統,效果非常好,大大節約了人力,開發效率也提高了。

這個是系統數據流程圖,分 2 個數據,1 個是曝光,1 個是點擊。這 2 個數據,我們這邊是有 2 條線,1 條是通過 Kafka 來做實時計算,下面做一些可視化和監控,這兩部分數據有一部分是實時的,有一部分是離線的。離線的,主要是通過 Hive 來做 ETL,最終到 Kylin 裡面去做一些預計算,把數據存在 HBase 裡邊,我們很多頁面或者說文件報表可視化的部分,就從 Kylin 裡面去看推薦效果。

這裡的 2 個數據,曝光的話,和點擊在維度和度量上,其實很相似的。我們就把曝光和點擊做了一個抽象,抽象出 15 個維度,5 個度量,比如說日期、平台、業務分類,還有推薦的場景和推薦的位置、排序算法號和召回策略號。度量有 5 個,主要算 PV 和 UV。

我們在 Kylin 裡邊,針對點擊和曝光數據去構建了 Cube。然後就是對 Cube 的優化,在 Kylin 裡面有一個很重要的就是減枝優化。如果不減枝優化,15 個維度組合數會達到 32768 個。我們根據查詢樣式和查詢的特點做了一些優化,比如說把分區日期作為一個必要維度。然後還做了層級優化,一級路徑、二級路徑,這個涉及到層級關係。第三個是場景,也是做了層級優化。最後是做了組合的優化,我們後面有5個維度,在 SQL 里要麼出現,要麼不出現,就把它們配置成一個 aggregation group,這樣 cuboid 數就少了很多。

通過 Kylin 的使用,就解決了我們推薦效果評估的難題,通過我們的優化發現我們的組合數會少很多。目前曝光 Cube 和點擊 Cube 的數據量分別為 3 T 和 2 T,各有 110 億+ 和 70 億+ 的記錄數。

這個就是我們的推薦效果評估的前瞻頁面,前面有很多的選擇,最後出現的是曝光 PV 的曲線圖。

目前其實在 58 主要有 2 個版本的 Kylin,一個是 v1.5.3,一個是 v2.6。我們在 v1.5.3做了很多的修改和優化,整個 Cube 的規模有 400 多個,Cube 的數據量就 500+ T。我們這邊的 Kylin 主要是用於離線,這邊每天新增的數據有 450 G,將近有 120 億條數據記錄,生成 900 G 的數據到 HBase 裡邊。我們這邊的查詢量不是很大,主要是做內部的報表分析,不會用到很頻繁的場景。我們這邊基於 Kylin的查詢,95% 的延遲小於 0.5 s,99% 的延遲小於 3 s,覆蓋的業務線很廣的,包括搜索、推薦、招聘、房產等 20 多個業務線。v2.6 正在遷的或者說已經遷的有將近 20 個,運行時間將近 1 個月。

04

提問 :總 Cube 不是 400 個嘛?遷到 v2.6 之後是 20 個?

回答:20 多個 Cube 是從其他部門維護的 Kylin 上遷移過來的,不是我們舊版本 v1.5.3 遷移過來的。

提問:400個 Cube,數據量大的話,你們這邊一天構建的時間是多少?

回答:單個Cube總數據量有 84 T 的,這個 Cube 一天構建時間稍微長一點,大概要 4-5 個小時。

提問:這麼快,你們用的是 MR?

回答:用的是 MR。我們新版本在測試 Spark 構建。

提問:更新是增量更新還是全量更新?

回答:我們是增量更新,不是全量更新。

提問:我想問一下流量分析是漏斗分析嗎?

回答:對,是漏斗分析。

文章來源: https://twgreatdaily.com/zh-tw/JWU58G4BMH2_cNUgCMsM.html