天天看點

卓越産品計劃丨神策分析性能優化詳解:批量導入優化

卓越産品計劃丨神策分析性能優化詳解:批量導入優化

追求卓越

打造極緻文化與産品研發結合的最佳實踐

神策已啟動「卓越産品計劃」

産品功能、性能、穩定性不斷邁向新台階

在為客戶提供服務時,我們通常會根據導入資料量、使用者資源以及使用者對于延時的要求來決定資料導入方案。接下來,本文将重點圍繞批量導入性能優化,從“避免資料傾斜”和“提高并行度”兩個次元,詳細講述神策分析性能優化之批量導入性能優化的進化曆程。

資料倉庫常采用分區的方式進行資料組織。神策将資料分區分為三層:第一層為 Project_id,代表使用者項目;第二層是 Day_id,代表日期;第三層為 EventBucket(預設為 10 個,可自主配置),代表資料對應事件的分桶。批量導入會涉及多個項目、多個日期的多個事件,同一個項目、同一天的同一個事件桶資料應該輸出到同一個檔案,在保證檔案品質(檔案大小以及壓縮比)的基礎上,導入性能優化核心要解決兩個問題:第一,避免資料傾斜;第二,盡可能提高并行度。

三層分區作為 PartitionKey 導入方案

PartitionKey 導入方案跟三層分區保持一緻,使用(Project_id, Day_id, EventBucket)三元組作為 MapReduce 任務的 PartitionKey,直接對 PartitionKey.hashCode()%reduceNum 進行資料 shuffle。

資料 shuffle 擁有更優的檔案品質,可以保證一個分區下的資料檔案數最少,但卻不能避免資料傾斜問題,如果相同的(Project_id, Day_id, EventBucket)一次性導入大量資料,那麼便會導緻導入性能急劇下降。

slice 導入方案

為了解決(Project_id, Day_id, EventBucket)三元組作為 PartitionKey 可能引起的資料傾斜問題,我們在優化方案中引入了遞增的 slice 補充到 PartitionKey 中。也就是說,如果相同的(Project_id, Day_id, EventBucket)一次性導入大量資料,則會将原來的一個 PartitionKey 變成 n 個 slice,如(Project_id, Day_id, EventBucket, slice_id=0),(Project_id, Day_id, EventBucket, slice_id=1)……該 shuffle 方案可以很好地避免資料傾斜問題。

如何切分 slice?在優化過程中,我們會按照資料量切分 slice。slice_capacity 表示一個切分slice的資料條數門檻值,比如 slice_capacity=10 萬,那麼第一個 10 萬對應的 slice_id=0,第二個 10 萬對應的 slice_id=1,以此類推。

但是,按照固定數量進行 slice 切分可能會面臨以下兩個問題:

  • 相同(Project_id, Day_id, EventBucket)下 slice_id=0 的資料較多,可能會導緻資料傾斜
  • 切分 slice 的 slice_capacity 門檻值參數設定難度較大,門檻值太大容易引起資料傾斜,門檻值過小會導緻資料被切分得太碎,檔案品質無法保障

對此,我們做了進一步優化:第一,slice_id 依然從 0 開始,但第二個 slice_id 則從 100-10000 之間随機生成初始值,然後依次遞增;第二,slice_capacity 不設定固定門檻值,隻設定最大/最小值,初始化為最小值,然後按照 2 的次幂遞增到最大值。

舉個例子,對于相同的(Project_id, Day_id, EventBucket)資料,假設slice_capacity 初始值是 5 萬,最大值為 50 萬,則第一個 5 萬對應的 slice_id=0;第二個 10 萬對應的 slice_id=rand(100-10000),若 slice_id=3000,那麼第三個 40 萬的 slice_id=3001,第四個 50 萬的 slice_id=3002 ,以此類推。

slice_id=0 的資料量變少,可以在保證檔案品質的前提下減少資料傾斜的機率。與此同時,非 slice_id=0 的資料采用随機方式可以有效打散之後的大資料量分區,進一步提升導入并行度。

資料分布預估導入方案

引入 slice 後,雖然可以一定程度上提升導入的性能,但依舊很難 100% 精準地避免資料傾斜。是以,我們進一步優化,提出了資料分布預估的導入政策。

1、後置預估

後置預估假設:使用者導入的資料分布在一定時間範圍内是一緻的。比如,使用者在 10 點導入了 100 萬 key=(Project_id=2, Day_id=19902, EventBucket=3),那麼使用者在 11 點也會繼續導入 100 萬左右的 key=(Project_id=2, Day_id=19902, EventBucket=3)。

于是我們設計了後置預估方式的導入優化政策。

首次導入使用 slice 導入,假設導入後的 key 分布如下:

(Project_id=2, Day_id=19902, EventBucket=3)100 萬 3 個檔案 1G

(Project_id=2, Day_id=19902, EventBucket=0)10 萬 1 個檔案 100M

(Project_id=2, Day_id=19902, EventBucket=1)20 萬 1 個檔案 100M

(Project_id=2, Day_id=19903, EventBucket=1)20 萬 1 個檔案 100M

(Project_id=3, Day_id=19903, EventBucket=1)20 萬 1 個檔案 100M

……

據此,我們可以預估下一次批量導入的分布。在送出 MapReduce 之前計算好每一個 key 對應的 reduce 分布,假設一個 reduce 配置設定 50 萬資料,那麼 10 個 reduce(Project_id=2, Day_id=19902, EventBucket=3)将分布在 reduce = (0,1)上,(Project_id=2,Day_id=19902,EventBucket=0)(Project_id=2,Day_id=19902,EventBucket=1)(Project_id=2, Day_id=19903, EventBucket=1)将分布在 reduce=2 上,(Project_id=3, Day_id=19903, EventBucket=1)分布在 reduce=3 上, 其餘未知 key 配置設定到剩下的 reduce。

我們可以看到,該導入政策不僅可以保證檔案品質,還可以提高資料導入的并行度。但我們仍需要關注這兩個問題:第一,每日 0 點前後,資料分布會發生質的改變,因為 Day_id 變了,是以在 0 點左右關閉導入政策可能會導緻資料導入速度驟降;第二,當導入曆史資料時,會造成資料分布發生根本性改變進而導緻政策失效,是以一旦有較大延遲時可關閉此導入政策。

2、前置預估

前置預估是指針對本次導入的資料計算資料分布,然後精确控制每一個 key 對應的 reduce。這種政策除了會帶來一定的前置計算額外開銷,近乎完美。在客戶環境的單個任務具體應用中,對于導入資料量大的客戶,優化效果明顯;對于正常資料量的客戶,前置預估的帶來額外開銷較多,難以帶來導入性能的提升。

流水線送出導入方案

流水錢送出導入方案能夠有效避免前置預估帶來的額外開銷。在此次導入的 MapReduce 運作期間,如果未導入的資料量足夠多且本次的 Map 已完成,那麼便會啟動下一次的預計算,保證下一次的導入隻需要計算資源而沒有預計算的額外開銷;如果預計算任務先于此次導入完成,那麼在具備充足資源的前提下會直接送出下一次的導入任務,進一步提高資料導入的并行度。送出流水線如下:

卓越産品計劃丨神策分析性能優化詳解:批量導入優化

在完成以上批量導入性能優化之後,神策資料能夠幫助企業客戶在資料量增大的業務場景中有效降低延時,已經獲得了衆多客戶的認可。這也為神策資料的「卓越産品計劃」落地實踐提供了更多價值層面支援,我們将持續推動産品功能、性能、穩定性不斷邁向新台階,打造更多打造極緻文化與産品研發結合的最佳實踐!

繼續閱讀