向量化執(zhí)行引擎框架 Gluten 宣布正式開源,并亮相 Spark 技術(shù)峰會(huì)
近日舉辦的 Databricks Data & AI Summit 2022 上,來自 Intel 的陳韋廷和來自 Kyligence 的張智超共同分享了 Intel 和 Kyligence 兩家企業(yè)自 2021 年合作共建的全新開源項(xiàng)目「Gluten」。這也是 Gluten 首次在全球平臺(tái)上亮相,今天我們將一起通過本文進(jìn)一步了解 Gluten。
Gluten 項(xiàng)目旨在為 Apache Spark 注入 Native Vectorized Execution 的能力,極大優(yōu)化 Spark 的執(zhí)行效率和成本。目前,Gluten 社區(qū)的主要參與方有 Intel、Kyligence 等。
“ Kyligence 企業(yè)級(jí)產(chǎn)品源自 Apache Kylin,今天,兩者在離線數(shù)據(jù)處理、即時(shí)查詢分析等方面,都深度集成了 Spark 的能力。通過 Gluten 這一開源項(xiàng)目,Kylin 和 Kyligence 企業(yè)級(jí)產(chǎn)品將有效提升 OLAP 查詢性能和執(zhí)行效率,尤其是在云原生版本 Kyligence Cloud 中,將更大程度地降低整體擁有成本(TCO),提高云端數(shù)據(jù)分析的成本效率,加速大型客戶從傳統(tǒng)數(shù)據(jù)分析架構(gòu)轉(zhuǎn)向云原生數(shù)據(jù)湖架構(gòu)的進(jìn)程。
——Kyligence 聯(lián)合創(chuàng)始人兼 CTO 李揚(yáng)”
#01
為什么需要 Gluten
近年來,隨著 IO 技術(shù)的提升,尤其是 SSD 和萬兆網(wǎng)卡的普及,大家基于 Apache Spark 的數(shù)據(jù)負(fù)載場(chǎng)景遇到越來越多的 CPU 計(jì)算瓶頸,而不是傳統(tǒng)認(rèn)知中的 IO 瓶頸。而眾所周知,基于 JVM 進(jìn)行 CPU 指令的優(yōu)化比較困難,因?yàn)?JVM 提供的 CPU 指令級(jí)的優(yōu)化(例如 SIMD)要遠(yuǎn)遠(yuǎn)少于其他 Native 語言(例如 C++)。
同時(shí),大家也發(fā)現(xiàn)目前開源社區(qū)已經(jīng)有比較成熟的 Native Engine(例如 ClickHouse、Velox),具備了優(yōu)秀的向量化執(zhí)行(Vectorized Execution)能力,并被證明能夠帶來顯著的性能優(yōu)勢(shì),然而它們往往游離于 Spark 生態(tài)之外,這對(duì)已經(jīng)嚴(yán)重依賴 Spark 計(jì)算框架、無法接受大量運(yùn)維和遷移成本的用戶而言不夠友好。Gluten 社區(qū)希望能夠讓 Spark 用戶無需遷移,就能享受這些成熟的 Native Engine 帶來的性能優(yōu)勢(shì)。
無獨(dú)有偶,前不久 Databricks 在 SIGMOD 2022 發(fā)表了一篇關(guān)于 Photon 項(xiàng)目的文章“Photon: A Fast Query Engine for Lakehouse Systems”[1],文章詳細(xì)描述了 Databricks 如何在 Apache Spark 中集成 Photon 這一 Native 子系統(tǒng),通過向量化執(zhí)行等方面的優(yōu)化,為 Apache Spark 帶來執(zhí)行性能的大幅提升。Gluten 項(xiàng)目在 Photon 公開前就已獨(dú)立地立項(xiàng)和啟動(dòng),不過我們看到在實(shí)現(xiàn)思路和加速效果上兩者具有一定的相似性。
下圖來自 Databricks 公開的演講材料[2],從圖中可以看出引入 Native Vectorized 引擎(Photon)的性能收益,勝過過去 5 年來所有性能優(yōu)化的總和。而性能的提升又可以帶來 Spark 使用體驗(yàn)的提升和 IT 成本的下降,這一點(diǎn)在企業(yè)用戶動(dòng)輒使用成百上千臺(tái)服務(wù)器用來運(yùn)行 Spark 作業(yè)的今天,是非常誘人的進(jìn)步。目前 Photon 并不開源,因此 Gluten 項(xiàng)目可以很好地填補(bǔ)行業(yè)在這里的空白。
#02
Gluten 項(xiàng)目是什么?
Gluten 這個(gè)單詞在拉丁文中有膠水的意思,Gluten 項(xiàng)目的作用也正像膠水一樣,主要用于“粘合” Apache Spark 和作為 Backend 的 Native Vectorized Engine。Backend 的選項(xiàng)有很多,目前在 Gluten 項(xiàng)目中已經(jīng)明確開始支持的有 Velox[3]、Clickhouse 和 Apache Arrow。
從這個(gè)定位出發(fā),我們結(jié)合下圖可以大致看到 Gluten 項(xiàng)目需要提供哪些能力:
2.1 Plan Conversion & Fallback
這是 Gluten 最核心的能力,簡(jiǎn)單來講就是通過 Spark Plugin 的機(jī)制,把 Spark 查詢計(jì)劃攔截并下發(fā)給 Native Engine 來執(zhí)行,跳過原生 Spark 不高效的執(zhí)行路徑。整體的執(zhí)行框架仍沿用 Spark 既有實(shí)現(xiàn),包括消費(fèi)接口、資源和執(zhí)行調(diào)度、查詢計(jì)劃優(yōu)化、上下游集成等。
一般來講,Native Engine 的能力,無法 100% 覆蓋 Spark 查詢執(zhí)行計(jì)劃中的算子,因此 Gluten 必須分析 Spark 查詢執(zhí)行計(jì)劃中哪些算子是可以下推給 Native Engine 的,并將這些相鄰的、可下推的算子封裝成一個(gè) Pipeline,序列化并發(fā)送給 Native Engine 來執(zhí)行并返回結(jié)果。我們依賴了一個(gè)獨(dú)立的名為 substrait 的開源項(xiàng)目[4],其使用 protobuf 來實(shí)現(xiàn)引擎中立的查詢計(jì)劃的序列化。
對(duì)于 Native Engine 無法承接的算子,Gluten 安排 fallback 回正常的 Spark 執(zhí)行路徑進(jìn)行計(jì)算。Databricks 的 Photon 目前也只是支持了部分 Spark 算子,應(yīng)該是采用了類似的做法。
在線程模型的角度,Gluten 使用以 JNI 調(diào)用 Library 的形式,在 Spark Executor Task 線程中直接調(diào)用 Native 代碼,并且嚴(yán)格控制 JNI 調(diào)用的次數(shù)。因此,Gluten 并不會(huì)引入復(fù)雜的線程模型,具體示意可參考下圖:
2.2 Memory Management
由于 Native 代碼和 Spark Java 代碼在同一個(gè)進(jìn)程中運(yùn)行,因此 Gluten 具備了統(tǒng)一管理 Native 空間和 JVM 空間內(nèi)存的條件。在 Gluten 中,Native 空間的代碼在申請(qǐng)內(nèi)存的時(shí)候,會(huì)先向本地的 Memory Pool 申請(qǐng)內(nèi)存,如果內(nèi)存不足,會(huì)進(jìn)一步向 JVM 中 Task Memory Manager 申請(qǐng)內(nèi)存配額,得到相應(yīng)配額后才會(huì)在 Native 空間成功申請(qǐng)下內(nèi)存。通過這種方式,Native 空間的內(nèi)存申請(qǐng)也受到 Task Memory Manager 的統(tǒng)一管理。當(dāng)發(fā)生內(nèi)存不足的現(xiàn)象時(shí),Task Memory Manager 會(huì)觸發(fā) spill,不管是 Native 還是 JVM 中的 operator 在收到 spill 通知時(shí)都會(huì)釋放內(nèi)存。
2.3 Columnar Shuffle
Shuffle 本身就是影響性能的重要一環(huán),由于 Native Engine 大多采用列式(Columnar)數(shù)據(jù)結(jié)構(gòu)暫存數(shù)據(jù),如果簡(jiǎn)單的沿用 Spark 的基于行數(shù)據(jù)模型的 Shuffle,則會(huì)在 Shuffle Write 階段引入數(shù)據(jù)列轉(zhuǎn)行的環(huán)節(jié),在 Shuffle Read 階段引入數(shù)據(jù)行轉(zhuǎn)列的環(huán)節(jié),才能使數(shù)據(jù)可以流暢周轉(zhuǎn)。但是無論行轉(zhuǎn)列,還是列轉(zhuǎn)行的成本都不低。因此,Gluten 必須提供完整的 Columnar Shuffle 機(jī)制以避開這里的轉(zhuǎn)化開銷。
和原生 Spark 一樣,Columnar Shuffle 也需要支持內(nèi)存不足時(shí)的 spill 操作,優(yōu)先保證查詢的健壯性。
2.4 Compatibility
用戶出于所在公司技術(shù)棧的考慮,可能會(huì)偏向使用兼容不同的 Native Engine。因此,Gluten 有必要定義清晰的 JNI 接口,作為 Spark 框架和底層 Backend 通信的橋梁。這些接口用來滿足請(qǐng)求傳遞、數(shù)據(jù)傳輸、能力檢測(cè)等多個(gè)方面的需求。開發(fā)者只需要實(shí)現(xiàn)這些接口,并滿足相應(yīng)的語義保障,就能利用 Gluten 完成 Spark 和 Native Engine 的“粘合”工作。
在 Spark 一側(cè), 目前的架構(gòu)設(shè)計(jì)中也預(yù)留的 Shim Layer 用來適配支持不同版本的 Spark。
2.5 其他方面的優(yōu)化
除了使用 Native 代碼挖掘向量化執(zhí)行的性能收益,Photon 的性能收益也來源于其他方面的優(yōu)化(主要是查詢優(yōu)化器),不過這些優(yōu)化很多并未開源,Gluten 項(xiàng)目也在不斷吸納這部分的開源版本的優(yōu)化。
#03
Status & Roadmap
目前 Gluten 社區(qū)已經(jīng)完成 Velox Backend 和 Clickhouse Backend 在 TPC-H 數(shù)據(jù)集上的驗(yàn)證工作。兩種 backend 在 TPC-H 1000 數(shù)據(jù)集下的性能表現(xiàn)如下圖所示,可以看到無論是哪種 backend,都收獲了較為顯著的性能提升。對(duì)于所有 TPC-H 的所有查詢,我們僅通過簡(jiǎn)單的集成,在并沒有對(duì) backend 做深度定制的前提下就能普遍獲得大于兩倍的性能提升,這是非常令人振奮的。
接下來,我們將圍繞以下方面展開 Gluten 社區(qū)的工作:
完成在 TPC-DS 數(shù)據(jù)集上的驗(yàn)證和性能測(cè)試工作
完善數(shù)據(jù)類型和函數(shù)的支持工作
完善數(shù)據(jù)源對(duì)接、數(shù)據(jù)源格式的支持工作
完善 CICD 流程和測(cè)試覆蓋
嘗試 Remote Shuffle Service 的對(duì)接工作
嘗試其他硬件加速的工作