不要告訴別人(fast工程的意義)fast工程有戰(zhàn)略意義嗎,F(xiàn)AST 2022 有哪些值得關注的論文?,零點書屋,
0這篇論文是databricks公司首次將內部的基于c++的native執(zhí)行引擎細節(jié)發(fā)表在SIGMOD 2022,作者公共23人,論文地址:https://www-cs.stanford.edu/~matei/papers/2022/sigmod_photon.pdf
?www-cs.stanford.edu/~matei/papers/2022/sigmod_photon.pdf本文不是對論文的翻譯,而是將論文中詳細的設計和細節(jié)拿出來記錄簡介:論文首先闡述了lakehouse的作用。
首先,企業(yè)會將大量數(shù)據(jù)存儲在彈性、可擴展的data lake上比如amazon s3、azure data lamapinfo破解版ke storage,google cloud storage等,這些數(shù)據(jù)可能是以apache parquet
、orc、delta lake等open file format存儲的raw、uncurated datasets,客戶/用戶可以通過presto,spark等計算引擎訪問,工作負載包括BI,ml等其次,為了獲取更高的性能、
數(shù)據(jù)治理,企業(yè)會通過ETL把部分數(shù)據(jù)從data lake上傳輸?shù)絛ata warehouse(比如apache hive)中,實際這是一個兩層的存儲架構,這樣帶來的成本顯而易見所以,出現(xiàn)了所以lakehouse(databrick的產品就是Delta Lake)基于mapinfo破解版。
對象存儲構建了data warehouse的能力,比如統(tǒng)一的數(shù)據(jù)訪問、數(shù)據(jù)治理、SQL支持等,這樣的單層架構對于用戶訪問數(shù)據(jù)非常友好為了更好的查詢performance,delta lake做了不少的優(yōu)化,比如transactions和time travel,data clustering和data skipping indeices等。
但是僅僅在存儲層努力是不夠的,還需要在query engine 這層努力,這就是本論文要闡述的photonPhoton主要的挑戰(zhàn):1)與傳統(tǒng)的data warehouse上的執(zhí)行引擎不同,photon需要解決新問題,就是raw、uncurated data,mapinfo破解版其特性是:可能存在是highly irregular datasets,poor physical layout,large fields,no useful clustering or data statistics,string來代表date或者int,
數(shù)據(jù)缺失值不一定用NULL填充而是默認值等等這個其實就是在機器學習、深度學習的場景,樣本數(shù)據(jù)就是上面提到的raw uncurated data,比如展現(xiàn)字段通常比較大,點擊數(shù)據(jù)也比較稀疏,feature log dump。
的數(shù)據(jù)也比較大等等對比之前的非常規(guī)整的交易數(shù)據(jù),DL場景的數(shù)據(jù)會更加不規(guī)則和缺少統(tǒng)計信息,因此對于計算引擎并不友好為了解mapinfo破解版決這個問題,photon是使用vectorized-interpreted model。
,而不是code generation(spark基于code generation) 所謂vectorized-interpreted,就是x100(論文放在文末,這也是clickhouse的框架執(zhí)行模型,在表達式這塊ck可以使用llvm來進行code generation加速執(zhí)行)的執(zhí)行模型,內存列存格式和。
批處理,這樣可以很方便利用CPU SIMD等指令,減少單次處理數(shù)據(jù)帶來的IO overhead,減少虛函數(shù)調用次數(shù)等額外開銷等等有諸多好處2)希望支持已有的spark,并且語義兼容,表現(xiàn)在SQL兼容mapinfo破解版和dataframe API兼容,也就是說對于上層用戶來講是透明的。
這點是為了留住客戶,如果說這套引擎不兼容spark api和sql,那么可想而知,客戶反饋肯定是非常差的所以為了解決這個問題,photon是整合到了spark框架中的,與已有的spark api和sql完全兼容。
大體來說,Databricks有一個從apache spark fork的一個databricks runtime(DBR),加入了更多的優(yōu)化和改進photon從算子層面重寫然后fit into DBR,作為query plan的執(zhí)行者,這樣即使有部分算子photon不支持可以fall back to DBR。
從這點來mapinfo破解版說,photon只是在算子級別實現(xiàn)了vectorized query engine,外層的DBR依然是已有的架構,DBR實現(xiàn)了query optimization,memory manager,IO,monitoring,photon需要與這些組件交互。
這點當然也限制了photon的發(fā)揮,因為spark是row-based處理數(shù)據(jù),那么中間必然有row到column的相互轉換,而且內存管理部分也需要與JVM交互, 增加了實現(xiàn)復雜度3)性能更好,spark基于JVM,集群負載是cpu bounding,因此轉向c++實現(xiàn)。
這毫無疑問,隨著硬件發(fā)展目前計算引擎已經(jīng)從早期的io bounding轉向mapinfo破解版了cpu bounding,我們的集群也是如此,因此如果重構必然要基于c++重寫,另外一個例證是presto也在基于c++做native query engine。
現(xiàn)在的趨勢就是基于c++或者rust構建native的執(zhí)行引擎,未來jvm的執(zhí)行引擎可能會逐漸淡出歷史舞臺完成其歷史使命,在大數(shù)據(jù)早期因為受限于磁盤或者網(wǎng)絡,整個系統(tǒng)的瓶頸往往在IO,因此jvm構建是合適的,可以更快的構建出產品比如
hadoop spark presto等目前網(wǎng)絡普遍在20Gbps甚至50G/100G,RDMA技術,磁盤也從早期的HDD發(fā)展到SSD,傲騰等帶寬更大、延遲更低,加上軟件上的異步預取、cache、并行計算mapinfo破解版。
等技術,IO瓶頸已經(jīng)基本消除CPU重新成為瓶頸另外一方面,c++、rust、llvm等語言和工具鏈更加成熟,所以,在大數(shù)據(jù)領域出現(xiàn)類似impala、clickhouse、datafusion等native的執(zhí)行引擎,未來會逐步擴大其。
scope,成為更加高效的解決方案總體來說,photon是基于c++實現(xiàn)的vectorized query engine,語義和內存管理兼容spark,并且在raw, uncurated data上做了大量優(yōu)化。
背景databricks的lakehouse整體架構總體上存算分離,分為4個部分,1· raw data storage,允許用戶選擇獨立的low comapinfo破解版st storage,比如S3,ADLS,GCS,主要是防止客戶data lock-in和昂貴的遷移成本,databricks提供各種connector來訪問不同的底層存儲,數(shù)據(jù)本身的格式也可能有多種,比如parquet,
orc等等2.automatic data management,這層就是Delta Lake,基于云對象存儲實現(xiàn)了數(shù)倉的特性,ACID,time travel,audit logging,fast metadata over tabular datasets,DetaLake的data 和。
metadata 都是基于parquet格式存儲,實現(xiàn)了auto data clusmapinfo破解版tering,cacheing等3.彈性執(zhí)行層,下圖展示了執(zhí)行層架構,這層邏輯上實現(xiàn)了“數(shù)據(jù)面”,所有的數(shù)據(jù)處理都在這層完成,包括internal query,比如auto data-clustering metadata access,還有客戶的queries,比如ETL,SQL,ML等。
每天大概有EB的數(shù)據(jù)被處理,可以看出databricks的客戶挺多的,這層需要彈性、可靠性高、性能好Photon就是通過處理單線層的query執(zhí)行on each partition of data遷入到執(zhí)行層中。
執(zhí)行層是跑在云廠商提供的VM上,這個就是spark的典型架構了,包括driver,負責協(xié)調,若干mapinfo破解版executor負責read and process data,driver和executor組成了DBR。
Lakehouse整體架構4.UI層,不解釋The Databricks Runtime(DBR)DBR是在開源的apache spark上進行了改進和優(yōu)化,photon是DBR的lowest level,處理single thread task with in the context of DBRs 。
multi-threaded shared-nothing execution model.下面是簡單的DBR任務提交過程,跟spark一樣,簡單重復下提交到DBR的應用被稱為jobs,mapinfo破解版每個job按照寬依賴被分層stages,stage被換分層tasks,每個task對應數(shù)據(jù)的一個分區(qū)partition。
stages之間blocking,串行執(zhí)行,下游stage讀取上有的數(shù)據(jù)輸出,按照stage進行容錯或者自適應執(zhí)行(spark3里的AQE)DBR用單節(jié)點的driver進行調度,query planning,以及其他中央化的工作,driver管理1到多個executor node,每個node運行多個task,每個。
task進行數(shù)據(jù)讀取、變化、輸出SQL query也是使用DBR這套架構,driver負責對SQL文本或者使用dataframe API生成的dataframe mapinfo破解版object轉換成query planQuery plan就是tree of SQL operators(比如filter, project, shuffle) that maps to a lists of stages.在query planning之后,driver就提交task執(zhí)行各個stages,每個task運行in-memory execution engine來處理數(shù)據(jù)集。
Photon就是類似的執(zhí)行引擎Phonton的設計要點總體上,photon是用c++實現(xiàn)的一個列式、批處理也就是vectorized query engine,以shared lib遷入到DBR,run as mapinfo破解版part of single-threaded task in DBR within an executors JVM process. 類似DBR,photon也是把SQL用tree of operator來表示,每個op實現(xiàn)HasNext()/GetNext()接口,從每個child
pull data,這個api也用來跟JVM上的operator通信每個op內部使用列式、向量化(也就是批)來處理數(shù)據(jù),這個與JVM的op以code generation的模式、row based是有差別的,因此在photon與。
JVM算子的邊界上需要做數(shù)據(jù)格式的轉換下面詳細展開JVM vs Native exmapinfo破解版ecution這個就簡單說下上面已經(jīng)說了不少,論文里也提到了目前集群都是cpu bounding,原因1是ssd cache,2是。
delta lake有很多IO優(yōu)化,比如data clustering,3是新的工作負載數(shù)據(jù)本身是un-normalized,large strings,unstructured nested data,因此更看中性能。
所有這些帶來的后果是JVM base execution engine成為瓶頸JVM大內存GC->off heap op->code難維護,java code generation受限于generated method size, or code mapinfo破解版cache size,有可能fall back到far slower的volcano-style interpreted code path。
因此選擇native實現(xiàn),這點也可以理解,clickhouse已經(jīng)在這塊做的非常成功了,apache doris也發(fā)布了vectorized execution engine2. interpreted vectorization vs code-gen。
這里的主要問題是計算框架采用向量化還是code gen?前者代表論文是monetdb/x100,后者代表論文是hyper前者的實現(xiàn)代表是clickhouse,monetdb,后者是spark sql,hmapinfo破解版yper,impala等。
前者優(yōu)點是,可以利用批處理以弱化虛函數(shù)調用開銷、SIMD指令、CPU pipeline和內存友好后者是在volcano style基礎上完全消除了虛擬函數(shù)開銷最終photon選擇前者,他們基于weld作code-generation,做了POC驗證,得出的結論是:。
易于開發(fā)和scale,可觀測性更強,易于適應changing data,specialization is still possible具體就不展開了,可以去看論文這兩種方法其實是可以結合的,在clickhouse的blog中就有過闡述,也有一篇論文說這個事情,框架采用vectorization,具體到表達mapinfo破解版式計算可以采用code-gen,這樣性能是最高的。
3. row vs column-oriented executionphonton中采用了列存內存模型,而不是spark的行存模型,主要理由是列存方便使用SIMD指令處理、更高效的pipelining、
序列化(傳輸or spill),數(shù)據(jù)源本身也是列存模型,比如parquet等,維護內存字典優(yōu)化內存等4.partial roll out這個要解決的點是如何在不影響已有workload的情況下透明上線,因為databricks上面跑了很多客戶的sql或者是dataframe api的代碼。
photon需要做到的是如果部分算子還沒有實現(xiàn),那么需要mapinfo破解版能fallback到老的代碼,不影響query的執(zhí)行,接下來的重點是如何與jvm base的DBR整合以實現(xiàn)這個目標,具體設計在下面Vectorized Execution in Photon
首先看下batched columnar data layout,典型的布局,如下圖,
注意這里除了按照列去存儲連續(xù)數(shù)據(jù)外,還增加了position list列,用來指示active rows(not filtered,也就是有效數(shù)據(jù))另外一種設計是設計一個bitmap來指示,但是論文說這種情況在某些場景下會導致整體性能下降。
Vectorized Execution Kernels這就是計算圖的實現(xiàn),圖的節(jié)mapinfo破解版點是operator,數(shù)據(jù)在圖中流動,TensorFlow也是類似的設計,x100首先提出該思想,op的處理粒度是vector of data,也就是向量化的數(shù)據(jù),下面有個
kernel的實現(xiàn)感受下,
注意參數(shù)里的RESTRICT關鍵字,這意思是參數(shù)指針地址都不同,因此編譯器可以做更多優(yōu)化,在clickhouse里大概提升了平均20%的性能Filters和conditonals的實現(xiàn)是通過修改position list of a column batch。
Vectorized hash table,這里實現(xiàn)了vectorized access,查詢氛圍3步,1是基于batch數(shù)據(jù)算hash,2是一mapinfo破解版個probe kernel跟進hash value load pointer(指向value,注意這里的value是行存),3是跟左表的比,這里也是向量化操作的。
所以3步都是可以做向量化操作引入SIMD,性能很高自適應執(zhí)行 Adaptive execution在lakehouse中的一大挑戰(zhàn)就是缺少統(tǒng)計信息,元信息,以及normalization,因此在此類數(shù)據(jù)集上的高效執(zhí)行是個挑戰(zhàn)。
Phonton的解決方法是支持batch level adaptivity,也就是說在batch size data的小數(shù)據(jù)上實現(xiàn)數(shù)據(jù)統(tǒng)計,元信息構建以此來優(yōu)化kernel執(zhí)行內存管理,photon實現(xiàn)
內存池,這mapinfo破解版里是基操了,對于定長數(shù)據(jù)做了most-recentaly-used cache,變長數(shù)據(jù)獨立處理,這里主要思想是跟進數(shù)據(jù)大小、模式分級精細化管理而且要與spark框架集成下面重點討論如何與DBR集成。
Integration with DBR Photon必須要與DBR進行集成,這里主要討論的是query planner and memory management首先討論對spark sql的支持,這里做的事就是convert spark plans to photon plans,具體做法是在catalyst里面加入轉換規(guī)則,規(guī)則處理如下:1是walk the input plan bottomapinfo破解版m up,然后map spark的node到Photon node。
如果一個node在photon中不支持的話就插入一個transition node負責將列批數(shù)據(jù)轉換成row-wise format這個legacy系統(tǒng)是在DBR里執(zhí)行的,需要注意的是要避免過多的此類轉換,否則代價太高了。
2是在file scan和first photon node間插入一個adaptor node用來將文件讀取的數(shù)據(jù)轉成列存數(shù)據(jù),這里用了zero copy技術,因為parquet本身也是列存的下圖是個例子:。
Executing Phonton Plans在做完query planning后,DBR會啟動tasmapinfo破解版ks按照stages執(zhí)行plan,photon執(zhí)行結點首先將photon part 到一個PB消息中,通過JNI傳輸?shù)絧hoton c++ lib,后者反序列化PB消息并執(zhí)行,執(zhí)行的過程跟JVM的過程類似,每個算子實現(xiàn)HasNext()/GetNext()接口,父節(jié)點以列批pull data from 子節(jié)點。
對于plan中有data exchange的點,photon會按照spark shuffle格式寫一份數(shù)據(jù),并把metadata傳遞給sparkspark框架執(zhí)行shuffle,然后啟動新的photon task來讀數(shù)據(jù),這里注意的是數(shù)據(jù)序列化和。
反序列化一致性Adapter node mapinfo破解版to read scan dataphoton的leaf node總是adapter node,這個node拿到spark的scan node獲取的列存數(shù)據(jù)(因為數(shù)據(jù)源是列存的格式比如parquet),adapter node的GetNext()函數(shù)就是調用JNI從spark的OffheapColumnVecto中拿數(shù)據(jù),這里傳遞了2個pointer,1是列存數(shù)據(jù),2是NULL數(shù)組,每次JNI的調用代價大概是c++。
虛擬函數(shù)調用代價23ns per call這樣也就實現(xiàn)了上文提到的數(shù)據(jù)讀取做到zero copyTransition node to pass photon data to spamapinfo破解版rkphoton的last node是transition node,必須將列批數(shù)據(jù)轉成row-wise格式供spark算子后續(xù)處理。
注意的是這里的轉換是成本很大的,所以不能做太多,photon后續(xù)還會持續(xù)改進這里Unified Memory Management因為photon是以share lib方式遷入到JVM進程中,因此必須要hooks into
apache spark的內存管理為了解決這個問題,photon團隊將memory reservation和memory allocation分開處理memory reservation是向spark unified memory managemapinfo破解版ment要求內存,這個操作可能引發(fā)spill,也就是spark會向memory consumer釋放內存以滿足新的要求,這個動作會導致。
data spillphoton也是在這套體系中的,也就是說可能引發(fā)self spill在photon內部也是依據(jù)已有的策略來確定哪個memory consumer spill,思路是比如要reserve N bytes,按照consumer的memory size從小到大排序,最后選擇第一個大于N bytes的consumer來。
spill,原因是盡量減少consumer的spill次數(shù),從而提升整體性能一旦photon reserve內存成功,就可以成功進mapinfo破解版行內存的開辟無需spill所以在photon spilling operator比如hash join,group by等,對于輸入數(shù)據(jù)的處理分為2個階段,第一階段是內存的reservation,第二階段是allocation階段,這樣再第二階段不會發(fā)生spill,這樣就保證了當前op的高效處理,photon團隊也強調這樣的策略很關鍵,因為在context中數(shù)據(jù)量經(jīng)常很大如果說在處理當前op經(jīng)常會發(fā)生spill的話,整個流程就又卡磁盤IO了,并不能發(fā)揮出向量化執(zhí)行引擎優(yōu)勢。
Managing On-heap vs Off-heap memoryspark有個靜態(tài)的max offheap sizemapinfo破解版的配置用來限制每個節(jié)點可以分配的堆外內存,photon主要使用堆外內存,因此不會被GC影響,但是有個場景是broadcast(比如broadcast hash join),photon還是需要依賴框架的broadcast機制,這樣需要photon堆外內存copy到堆內存,這里可能引發(fā)OOM,photon做法是增加1個listener在query執(zhí)行結束后清理部分自身的state來釋放內存。
與其他部分的融合與兼容性最后討論下photon與DBR和開源的spark結合問題因為photon只是對plan部分進行了改變,所以spark框架上做的很多事情依然可以復用,比如AQE,還有就是photon的mmapinfo破解版etrics也與已有的兼容,可觀測性比較好 。
在語義兼容方面,為了做到與spark和DBR完全兼容,photon使用unit tests,end to end tests,fuzz tests來綜合保證效果評估得益于:列存格式、向量化、SIMD指令。
、runtime adaptivity,photon的主要加速場景是cpu heavy的,比如,join,aggregation,expression evaluation,另外還可以加速其他場景比如寫parquet文件,對于network io 或者disk io bounding場景加速其實不明顯。
下圖是各種測試,
注意photon目前只支持shmapinfo破解版uffle hash join,不支持sort merge joinspark的shuffle hash join也是不支持spill的,因為spill會帶來大量隨機IO,所以spark會用sort merge join來應對大量數(shù)據(jù)join。
關于JVM的轉換代價,photon團隊也做了測試,從內存的列存int類型數(shù)據(jù)讀,整體執(zhí)行時間0.06%損耗在JNI-internal methods,0.2%損耗在adapter node總體看JNI或者轉換沒有太大代價。
相比DBR,photon另外一塊比較優(yōu)勢的點就是runtime adaptivity:1)adapting to sparse batmapinfo破解版ches有些場景下有很多數(shù)據(jù)是比較稀疏的,比如ML,photon會在每個batch上track列數(shù)據(jù)的稀疏性,在做join probe的時候在稀疏列上會進行compact增加內存吞吐,還有如果不做compact會比DBR差,因為稀疏數(shù)據(jù)導致了high overhead,然而DBR因為通過code-gen方式消除了虛函數(shù)調用開銷盡管是tuple at time。
這也是需要針對稀疏數(shù)據(jù)進行compact的原因效果如下圖:
2)adaptive string encoding,shuffle是性能殺手,所以photon進行了優(yōu)化來減少shuffle數(shù)據(jù)大小,手段主要是1)縮小uuid數(shù)據(jù)寬度,默認uumapinfo破解版id是36B,優(yōu)化到128bit表示,類似ML里的量化,
2)在shuffle寫前加lz4壓縮,另外壓縮也會導致內存占用較小從而避免spill,當然代價是多耗費一點cpu。下圖是效果:
總結photon團隊從現(xiàn)實出發(fā),實現(xiàn)了spark的向量化處理、微批adaptivity,與已有DBR和spark兼容,在cpu heavy的場景提升非常明顯,國內也有一些公司做了類似的嘗試比如阿里云、第四范式
等,從效果看非常不錯工作量可以看到不小,論文是Matei領銜23人完成,需要一個工程能力很強的團隊從計算引擎的角度看,photon未必是state-of-art,受限于現(xiàn)實原因,photon必須要嵌入到DBR中mapinfo破解版,大量與JVM交互,數(shù)據(jù)格式也需要列與行互轉,帶來一定的。
overhead另外一條路,個人認為是基于clickhouse來演進,首先實現(xiàn)clickhouse與hive數(shù)倉或者數(shù)據(jù)湖的整合,其次,支持shuffle hash join和shuffle merge join,再次通過寫checkpoint增強執(zhí)行ETL等大query的容錯能力。
這樣的clickhouse可以說是state-of-art的執(zhí)行引擎,在性能和功能方面都非常完善。