Doris開發(fā)手記4:倍速性能提升,向量化導(dǎo)入的性能調(diào)優(yōu)實(shí)踐

最近居家中,對(duì)自己之前做的一些工作進(jìn)行總結(jié)。正好有Doris社區(qū)的小伙伴吐槽向量化的導(dǎo)入性能表現(xiàn)并不是很理想,就借這個(gè)機(jī)會(huì)對(duì)之前開發(fā)的向量化導(dǎo)入的工作進(jìn)行了性能調(diào)優(yōu),取得了不錯(cuò)的優(yōu)化效果。借用本篇手記記錄下一些性能優(yōu)化的思路,拋磚引玉,希望大家多多參與到性能優(yōu)化的工作總來。

1.看起來很慢的向量化導(dǎo)入

問題的發(fā)現(xiàn)

來自社區(qū)用戶的吐槽:向量化導(dǎo)入太慢了啊,我測試了xx數(shù)據(jù)庫,比Doris快不少啊。有招嗎?

啊哈?慢這么多嗎? 那我肯定得瞅一瞅了。
于是對(duì)用戶case進(jìn)行了復(fù)現(xiàn),發(fā)現(xiàn)用戶測試的是代碼庫里ClickBench的stream load,80個(gè)G左右的數(shù)據(jù),向量化導(dǎo)入耗時(shí)得接近1200s,而非向量化導(dǎo)入耗時(shí)為1400s。

向量化 非向量化
1230s 1450s

ClickBench是典型的大寬表的場景,并且為Duplicate Key的模型,原則上能充分發(fā)揮向量化導(dǎo)入的優(yōu)勢。所以看起來一定是有些問題的,需要按圖索驥的來定位熱點(diǎn):

定位熱點(diǎn)的技巧

筆者通常定位Doris代碼的熱點(diǎn)有這么幾種方式,通過這些方式共同組合,能幫助我們快速定位到代碼真正的瓶頸點(diǎn)

  • Profile: Doris自身記錄的耗時(shí),利用Profile就能分析出大致代碼部分的瓶頸點(diǎn)。缺點(diǎn)是不夠靈活,很多時(shí)候需要手動(dòng)編寫代碼,重新編譯才能添加我們需要進(jìn)行熱點(diǎn)觀察的代碼。

  • FlameGraph: 一旦通過Profile分析到大概的熱點(diǎn)位置,筆者通常會(huì)快速通讀一遍代碼,然后結(jié)合火焰圖來定位到函數(shù)熱點(diǎn)的位置,這樣進(jìn)行的優(yōu)化通常就有的放矢了。關(guān)于火焰圖的使用可以簡要參考Doris的官方文檔的開發(fā)者手冊(cè)。

  • Perf: 火焰圖只能大致定位到聚合函數(shù)的熱點(diǎn),而且編譯器經(jīng)過內(nèi)聯(lián),匯編優(yōu)化之后,單純通過火焰圖的函數(shù)級(jí)別就不一定夠用了。通常需要進(jìn)一步分析匯編代碼的問題,這時(shí)則可以用開發(fā)手記2中提到的perf來定位匯編語言的熱點(diǎn)。當(dāng)然,perf并不是萬能的,很多時(shí)候需要我們基于代碼本身的熟稔和一些優(yōu)化經(jīng)驗(yàn)來進(jìn)一步進(jìn)行調(diào)優(yōu)。

接下來我們就基于上述的調(diào)優(yōu)思路,來一起分析一下這個(gè)問題。

2.優(yōu)化與代碼解析

基于火焰圖,筆者梳理出在向量化導(dǎo)入時(shí)的幾部分核心的熱點(diǎn)。針對(duì)性的進(jìn)行了問題分析與解決:

緩慢的Cast與字符串處理

在CSV導(dǎo)入到Doris的過程之中,需要經(jīng)歷一個(gè)文本數(shù)據(jù)解析,表達(dá)式CAST計(jì)算的過程。顯然,這個(gè)工作從火焰圖中觀察出來,是CPU的耗損大戶

字符串處理的耗時(shí)圖

上面的火焰圖可以觀察出來,這里有個(gè)很反常的函數(shù)調(diào)用耗時(shí)FunctionCast::prepare_remove_prepare,這里需要根據(jù)源碼來進(jìn)一步分析。

在進(jìn)行cast過程之中需要完成null值拆分的工作,比如這里需要完成String Cast Int的操作流程如下圖所示:

image.png

這里會(huì)利用原始的block,和待cast的列建立一個(gè)新的臨時(shí)block來進(jìn)行cast函數(shù)的計(jì)算。

image.png

上面標(biāo)紅的代碼會(huì)對(duì)std::set進(jìn)行大量的CPU計(jì)算工作,影響的向量化導(dǎo)入的性能。在導(dǎo)入表本身是大寬表的場景下,這個(gè)問題的嚴(yán)重性會(huì)進(jìn)一步放大。

進(jìn)行了問題定位之后,優(yōu)化工作就顯得很簡單了。顯然進(jìn)行cast的時(shí)候,我們僅僅只需要進(jìn)行cast計(jì)算的相關(guān)列,而并不需要整個(gè)block中所有的列都參與進(jìn)來。所以筆者這里實(shí)現(xiàn)了一個(gè)新的函數(shù) create_block_with_nested_columns_only_args來替換create_block_with_nested_columns_impl,原本對(duì)100列以上的計(jì)數(shù)問題,減少為對(duì)一個(gè)列進(jìn)行處理,問題得到了顯著的改善。

優(yōu)化前 優(yōu)化后
1230s 980s
缺頁中斷的優(yōu)化

解決了上面問題之后,繼續(xù)來對(duì)火焰圖進(jìn)行分析,發(fā)現(xiàn)了在數(shù)據(jù)寫入memtable時(shí),產(chǎn)生了下面的熱點(diǎn):缺頁中斷。

image.png

這里得先簡單了解一下什么是缺頁中斷

缺頁中斷

如上圖所示:CPU對(duì)數(shù)據(jù)進(jìn)行計(jì)算時(shí),會(huì)請(qǐng)求獲取內(nèi)存中的數(shù)據(jù)。而CPU層級(jí)看的內(nèi)存地址是:Virtual Address,需要經(jīng)過特別的CPU結(jié)構(gòu)MMU進(jìn)行虛擬地址到物理地址的映射。而MMU會(huì)到TLB(Translation lookaside buffer,記住這個(gè)是個(gè)緩存),查找對(duì)應(yīng)的虛擬地址到物理地址的映射。由于操作系統(tǒng)中,內(nèi)存都是通過頁進(jìn)行管理的,地址都是基于頁內(nèi)存地址的偏移量,所以這個(gè)過程變成了查找起始頁地址的一個(gè)工作。如果目標(biāo)虛存空間中的內(nèi)存頁,在物理內(nèi)存中沒有對(duì)應(yīng)的頁映射,那么這種情況下,就產(chǎn)生了缺頁中斷(Page Fault)。

缺頁中斷顯然會(huì)帶來一些額外的開銷:

  • 用戶態(tài)到內(nèi)核態(tài)的切換
  • 內(nèi)核處理缺頁錯(cuò)誤

所以,頻繁的出現(xiàn)缺頁中斷,對(duì)導(dǎo)入的性能產(chǎn)生了不利的影響,需要嘗試解決它。

內(nèi)存復(fù)用

這里大量的內(nèi)存使用,取址都是對(duì)于Column進(jìn)行操作導(dǎo)致的,所以得嘗試從內(nèi)存分配的源頭來解決這個(gè)問題。

解決思路也很簡單,既然缺頁中斷是內(nèi)存沒有映射引起的,那這里就盡量復(fù)用之前已經(jīng)使用過的內(nèi)存,這樣,自然也不會(huì)引起缺頁中斷的問題了,對(duì)于TLB的緩存訪問也有了更高的親和度。

Doris內(nèi)部本身支持了ChunkAlloctor的類來進(jìn)行內(nèi)存分配,復(fù)用,綁核的邏輯,通過ChunkAlloctor能大大提升內(nèi)存申請(qǐng)的效率,對(duì)于當(dāng)前case的缺頁中斷也能起到規(guī)避的效果:

image.png

通過替換podarray的內(nèi)存分配的邏輯之后,效果也很符合預(yù)期,通過火焰圖進(jìn)行觀察,缺頁中斷的占比大量的減少,性能上也獲得了可觀的收益。

優(yōu)化前 優(yōu)化后
980s 776s

3.一些相關(guān)的優(yōu)化的TODO:

  • CSV的數(shù)據(jù)格式解析:通過4kb的cache 來預(yù)取多行數(shù)據(jù),利用并SIMD指令集來進(jìn)一步性能優(yōu)化

  • 缺頁中斷的優(yōu)化:部分內(nèi)存分配拷貝過程之中的page fault的問題, 可以考慮引入大頁內(nèi)存機(jī)制來進(jìn)一步進(jìn)行缺頁中斷,頁內(nèi)存cache的優(yōu)化

4.小結(jié)

當(dāng)然,筆者進(jìn)行的向量化導(dǎo)入工作只是Doris向量化導(dǎo)入中的一部分工作。很多社區(qū)的同學(xué)也深入?yún)⑴c了相關(guān)工作,在當(dāng)前的基礎(chǔ)上又有得到了更為理想的性能表現(xiàn)??傊?,性能優(yōu)化的工作是永無止境的.

這里也特別鳴謝社區(qū)的兩位同學(xué)的code review和分析幫助:@xinyiZzz, @Gabriel

Bingo!請(qǐng)大家期待下一個(gè)1.2版本全面向量化的Doris,相信在性能和穩(wěn)定性上,一定會(huì)帶給各位驚喜。

最后,也希望大家多多支持Apache Doris,多多給Doris貢獻(xiàn)代碼,感恩~~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容