卓越產(chǎn)品計(jì)劃丨神策分析性能優(yōu)化詳解:批量導(dǎo)入優(yōu)化

追求卓越

打造極致文化與產(chǎn)品研發(fā)結(jié)合的最佳實(shí)踐

神策已啟動(dòng)「卓越產(chǎn)品計(jì)劃」

產(chǎn)品功能、性能、穩(wěn)定性不斷邁向新臺(tái)階

在為客戶提供服務(wù)時(shí),我們通常會(huì)根據(jù)導(dǎo)入數(shù)據(jù)量、用戶資源以及用戶對(duì)于延時(shí)的要求來(lái)決定數(shù)據(jù)導(dǎo)入方案。接下來(lái),本文將重點(diǎn)圍繞批量導(dǎo)入性能優(yōu)化,從“避免數(shù)據(jù)傾斜”和“提高并行度”兩個(gè)維度,詳細(xì)講述神策分析性能優(yōu)化之批量導(dǎo)入性能優(yōu)化的進(jìn)化歷程。

關(guān)注神策數(shù)據(jù)公眾號(hào),了解更多產(chǎn)品解讀。

數(shù)據(jù)倉(cāng)庫(kù)常采用分區(qū)的方式進(jìn)行數(shù)據(jù)組織。神策將數(shù)據(jù)分區(qū)分為三層:第一層為 project_id,代表用戶項(xiàng)目;第二層是 day_id,代表日期;第三層為 event_bucket(默認(rèn)為 10 個(gè),可自主配置),代表數(shù)據(jù)對(duì)應(yīng)事件的分桶。批量導(dǎo)入會(huì)涉及多個(gè)項(xiàng)目、多個(gè)日期的多個(gè)事件,同一個(gè)項(xiàng)目、同一天的同一個(gè)事件桶數(shù)據(jù)應(yīng)該輸出到同一個(gè)文件,在保證文件質(zhì)量(文件大小以及壓縮比)的基礎(chǔ)上,導(dǎo)入性能優(yōu)化核心要解決兩個(gè)問(wèn)題:第一,避免數(shù)據(jù)傾斜;第二,盡可能提高并行度。

三層分區(qū)作為 PartitionKey 導(dǎo)入方案

PartitionKey 導(dǎo)入方案跟三層分區(qū)保持一致,使用(project_id, day_id, event_bucket)三元組作為 MapReduce 任務(wù)的 PartitionKey,直接對(duì) PartitionKey.hashCode()%reduceNum 進(jìn)行數(shù)據(jù) shuffle。

數(shù)據(jù) shuffle 擁有更優(yōu)的文件質(zhì)量,可以保證一個(gè)分區(qū)下的數(shù)據(jù)文件數(shù)最少,但卻不能避免數(shù)據(jù)傾斜問(wèn)題,如果相同的(project_id, day_id, event_bucket)一次性導(dǎo)入大量數(shù)據(jù),那么便會(huì)導(dǎo)致導(dǎo)入性能急劇下降。

slice 導(dǎo)入方案

為了解決(project_id, day_id, event_bucket)三元組作為 PartitionKey 可能引起的數(shù)據(jù)傾斜問(wèn)題,我們?cè)趦?yōu)化方案中引入了遞增的 slice 補(bǔ)充到 PartitionKey 中。也就是說(shuō),如果相同的(project_id, day_id, event_bucket)一次性導(dǎo)入大量數(shù)據(jù),則會(huì)將原來(lái)的一個(gè) PartitionKey 變成 n 個(gè) slice,如(project_id, day_id, event_bucket, slice_id=0),(project_id, day_id, event_bucket, slice_id=1)……該 shuffle 方案可以很好地避免數(shù)據(jù)傾斜問(wèn)題。

如何切分 slice?在優(yōu)化過(guò)程中,我們會(huì)按照數(shù)據(jù)量切分 slice。slice_capacity 表示一個(gè)切分slice的數(shù)據(jù)條數(shù)閾值,比如 slice_capacity=10 萬(wàn),那么第一個(gè) 10 萬(wàn)對(duì)應(yīng)的 slice_id=0,第二個(gè) 10 萬(wàn)對(duì)應(yīng)的 slice_id=1,以此類推。

但是,按照固定數(shù)量進(jìn)行 slice 切分可能會(huì)面臨以下兩個(gè)問(wèn)題:

相同(project_id, day_id, event_bucket)下 slice_id=0 的數(shù)據(jù)較多,可能會(huì)導(dǎo)致數(shù)據(jù)傾斜

切分 slice 的 slice_capacity 閾值參數(shù)設(shè)置難度較大,閾值太大容易引起數(shù)據(jù)傾斜,閾值過(guò)小會(huì)導(dǎo)致數(shù)據(jù)被切分得太碎,文件質(zhì)量無(wú)法保障

對(duì)此,我們做了進(jìn)一步優(yōu)化:第一,slice_id 依然從 0 開(kāi)始,但第二個(gè) slice_id 則從 100-10000 之間隨機(jī)生成初始值,然后依次遞增;第二,slice_capacity 不設(shè)置固定閾值,只設(shè)置最大/最小值,初始化為最小值,然后按照 2 的次冪遞增到最大值。

舉個(gè)例子,對(duì)于相同的(project_id, day_id, event_bucket)數(shù)據(jù),假設(shè)slice_capacity 初始值是 5 萬(wàn),最大值為 50 萬(wàn),則第一個(gè) 5 萬(wàn)對(duì)應(yīng)的 slice_id=0;第二個(gè) 10 萬(wàn)對(duì)應(yīng)的 slice_id=rand(100-10000),若 slice_id=3000,那么第三個(gè) 40 萬(wàn)的 slice_id=3001,第四個(gè) 50 萬(wàn)的 slice_id=3002 ,以此類推。

slice_id=0 的數(shù)據(jù)量變少,可以在保證文件質(zhì)量的前提下減少數(shù)據(jù)傾斜的概率。與此同時(shí),非 slice_id=0 的數(shù)據(jù)采用隨機(jī)方式可以有效打散之后的大數(shù)據(jù)量分區(qū),進(jìn)一步提升導(dǎo)入并行度。

數(shù)據(jù)分布預(yù)估導(dǎo)入方案

引入 slice 后,雖然可以一定程度上提升導(dǎo)入的性能,但依舊很難 100% 精準(zhǔn)地避免數(shù)據(jù)傾斜。因此,我們進(jìn)一步優(yōu)化,提出了數(shù)據(jù)分布預(yù)估的導(dǎo)入策略。

1、后置預(yù)估

后置預(yù)估假設(shè):用戶導(dǎo)入的數(shù)據(jù)分布在一定時(shí)間范圍內(nèi)是一致的。比如,用戶在 10 點(diǎn)導(dǎo)入了 100 萬(wàn) key=(project_id=2, day_id=19902, event_bucket =3),那么用戶在 11 點(diǎn)也會(huì)繼續(xù)導(dǎo)入 100 萬(wàn)左右的 key=(project_id=2, day_id=19902, event_bucket =3)。

于是我們?cè)O(shè)計(jì)了后置預(yù)估方式的導(dǎo)入優(yōu)化策略。

首次導(dǎo)入使用 slice 導(dǎo)入,假設(shè)導(dǎo)入后的 key 分布如下:

(project_id=2, day_id=19902, event_bucket =3)100 萬(wàn) 3 個(gè)文件 1G

(project_id=2, day_id=19902, event_bucket =0)10 萬(wàn) 1 個(gè)文件 100M

(project_id=2, day_id=19902, event_bucket =1)20 萬(wàn) 1 個(gè)文件 100M

(project_id=2, day_id=19903, event_bucket =1)20 萬(wàn) 1 個(gè)文件 100M

(project_id=3, day_id=19903, event_bucket =1)20 萬(wàn) 1 個(gè)文件 100M

……

據(jù)此,我們可以預(yù)估下一次批量導(dǎo)入的分布。在提交 MapReduce 之前計(jì)算好每一個(gè) key 對(duì)應(yīng)的 reduce 分布,假設(shè)一個(gè) reduce 分配 50 萬(wàn)數(shù)據(jù),那么 10 個(gè) reduce(project_id=2, day_id=19902, event_bucket =3)將分布在 reduce = (0,1)上,(project_id=2,day_id=19902, event_bucket =0)(project_id=2,day_id=19902, event_bucket =1)(project_id=2, day_id=19903, event_bucket =1)將分布在 reduce=2 上,(project_id=3,day_id=19903, event_bucket =1)分布在 reduce=3 上, 其余未知 key 分配到剩下的 reduce。

我們可以看到,該導(dǎo)入策略不僅可以保證文件質(zhì)量,還可以提高數(shù)據(jù)導(dǎo)入的并行度。但我們?nèi)孕枰P(guān)注這兩個(gè)問(wèn)題:第一,每日 0 點(diǎn)前后,數(shù)據(jù)分布會(huì)發(fā)生質(zhì)的改變,因?yàn)?day_id 變了,因此在 0 點(diǎn)左右關(guān)閉導(dǎo)入策略可能會(huì)導(dǎo)致數(shù)據(jù)導(dǎo)入速度驟降;第二,當(dāng)導(dǎo)入歷史數(shù)據(jù)時(shí),會(huì)造成數(shù)據(jù)分布發(fā)生根本性改變進(jìn)而導(dǎo)致策略失效,因此一旦有較大延遲時(shí)可關(guān)閉此導(dǎo)入策略。

2、前置預(yù)估

前置預(yù)估是指針對(duì)本次導(dǎo)入的數(shù)據(jù)計(jì)算數(shù)據(jù)分布,然后精確控制每一個(gè) key 對(duì)應(yīng)的 reduce。這種策略除了會(huì)帶來(lái)一定的前置計(jì)算額外開(kāi)銷,近乎完美。在客戶環(huán)境的單個(gè)任務(wù)具體應(yīng)用中,對(duì)于導(dǎo)入數(shù)據(jù)量大的客戶,優(yōu)化效果明顯;對(duì)于常規(guī)數(shù)據(jù)量的客戶,前置預(yù)估的帶來(lái)額外開(kāi)銷較多,難以帶來(lái)導(dǎo)入性能的提升。

流水線提交導(dǎo)入方案

流水錢提交導(dǎo)入方案能夠有效避免前置預(yù)估帶來(lái)的額外開(kāi)銷。在此次導(dǎo)入的 MapReduce 運(yùn)行期間,如果未導(dǎo)入的數(shù)據(jù)量足夠多且本次的 Map 已完成,那么便會(huì)啟動(dòng)下一次的預(yù)計(jì)算,保證下一次的導(dǎo)入只需要計(jì)算資源而沒(méi)有預(yù)計(jì)算的額外開(kāi)銷;如果預(yù)計(jì)算任務(wù)先于此次導(dǎo)入完成,那么在具備充足資源的前提下會(huì)直接提交下一次的導(dǎo)入任務(wù),進(jìn)一步提高數(shù)據(jù)導(dǎo)入的并行度。提交流水線如下:

在完成以上批量導(dǎo)入性能優(yōu)化之后,神策數(shù)據(jù)能夠幫助企業(yè)客戶在數(shù)據(jù)量增大的業(yè)務(wù)場(chǎng)景中有效降低延時(shí),已經(jīng)獲得了眾多客戶的認(rèn)可。這也為神策數(shù)據(jù)的「卓越產(chǎn)品計(jì)劃」落地實(shí)踐提供了更多價(jià)值層面支持,我們將持續(xù)推動(dòng)產(chǎn)品功能、性能、穩(wěn)定性不斷邁向新臺(tái)階,打造更多打造極致文化與產(chǎn)品研發(fā)結(jié)合的最佳實(shí)踐!

關(guān)注神策數(shù)據(jù)公眾號(hào),了解更多產(chǎn)品解讀。

(免責(zé)聲明:本網(wǎng)站內(nèi)容主要來(lái)自原創(chuàng)、合作伙伴供稿和第三方自媒體作者投稿,凡在本網(wǎng)站出現(xiàn)的信息,均僅供參考。本網(wǎng)站將盡力確保所提供信息的準(zhǔn)確性及可靠性,但不保證有關(guān)資料的準(zhǔn)確性及可靠性,讀者在使用前請(qǐng)進(jìn)一步核實(shí),并對(duì)任何自主決定的行為負(fù)責(zé)。本網(wǎng)站對(duì)有關(guān)資料所引致的錯(cuò)誤、不確或遺漏,概不負(fù)任何法律責(zé)任。
任何單位或個(gè)人認(rèn)為本網(wǎng)站中的網(wǎng)頁(yè)或鏈接內(nèi)容可能涉嫌侵犯其知識(shí)產(chǎn)權(quán)或存在不實(shí)內(nèi)容時(shí),應(yīng)及時(shí)向本網(wǎng)站提出書面權(quán)利通知或不實(shí)情況說(shuō)明,并提供身份證明、權(quán)屬證明及詳細(xì)侵權(quán)或不實(shí)情況證明。本網(wǎng)站在收到上述法律文件后,將會(huì)依法盡快聯(lián)系相關(guān)文章源頭核實(shí),溝通刪除相關(guān)內(nèi)容或斷開(kāi)相關(guān)鏈接。 )