為什麼Apache Spark速度很快以及如何使其運行更快

如果在開發和實施Spark作業時應用所有這些規則,那麼破紀錄的處理工具將以驚人的結果回報您。

這些建議僅僅是掌握Apache Spark的第一步。 在接下來的文章中,我們將詳細討論其不同模塊,以更好地瞭解Spark的功能。

本文最初在INVIVOO的技術博客上發表。


為什麼Apache Spark速度很快以及如何使其運行更快

> Apache Spark logo

Spark可以快速完成任務。 自從2010年首次引入該框架以來,它一直是該框架的主要賣點。

提供基於內存的替代Map-Reduce極大地推動了大數據生態系統,並且在過去幾年中,這代表了公司採用大數據系統的主要原因之一。

憑藉其廣泛的用例,易用性和記錄設置功能,當涉及大數據架構中的數據處理時,Spark迅速成為每個人的首選框架。

第一部分:Spark ABC

Spark的關鍵組件之一是它的SparkSQL模塊,它可以將批處理Spark作業編寫為類似SQL的查詢。 為此,Spark依靠複雜的機制在後臺運行,以通過執行引擎運行這些查詢。 該機制的核心是Catalyst:Spark的查詢優化器,它通過生成作業的物理執行計劃來完成許多繁重的工作。

即使此過程的每一步都經過精心改進,以優化工作的各個方面。 在鏈的末端,您仍然可以做很多事情,以使您的Spark作業運行得更快。 但是,在此之前,讓我們深入探討Catalyst的工作方式。

首先,讓我們從基礎開始

Spark提供了多種與其SparkSQL接口進行交互的方式,主要的API是DataSet和DataFrame。 這些高級API建立在面向對象的RDD API之上。 並且在保留某些主要功能(例如使用模式)的同時保留了其主要特徵。 (有關詳細比較,請參閱Databricks博客上的本文)。

使用的API的選擇主要取決於您使用的語言。 DataSet僅在Scala / Java中可用,並且自Spark 2.0發行以來,已為這些語言替換DataFrame。 每個人都有一定的特權和優勢。 好消息是,Spark在後臺使用了相同的執行引擎來運行您的計算,因此您可以輕鬆地從一個API切換到另一個API,而不必擔心執行級別上會發生什麼。

也就是說,無論您使用哪種API,提交作業時都會經過統一的優化過程。

Spark如何看待世界

您可以在Spark應用程序中執行的操作分為兩種類型:

· Transform 轉換:這些操作在應用於RDD時,將返回對通過轉換創建的新RDD的引用。 一些最常用的轉換是過濾器和映射。 (以下是可用轉換的完整列表)

· Action 行動:當應用於RDD時,這些操作將返回非RDD值。 一個很好的例子是count操作,該操作將RDD中的元素數返回給Spark驅動程序,或者收集一個將RDD的內容發送給驅動程序的操作。 (請參閱此鏈接以獲取可在RDD上執行的操作的完整列表)。

由於這些API基於RDD機制構建,因此DataFrame和DataSet操作分為相同的類別。

接下來要做的區分是以下兩種類型的轉換:

· 窄轉換:將這些轉換應用於RDD時,分區之間沒有數據移動。 將該轉換應用於RDD的每個分區的數據,並得到具有相同分區數的新RDD,如下圖所示。 例如,過濾器是一個狹窄的轉換,因為將過濾器應用於每個分區的數據,並且所得數據表示新創建的RDD中的一個分區。

為什麼Apache Spark速度很快以及如何使其運行更快

> A narrow transformation (Source: Databricks)

· 廣泛的轉換:這些轉換需要在分區之間進行數據移動,也就是所謂的隨機播放。 數據跨網絡移動,新創建的RDD的分區基於多個輸入分區的數據,如下所示。 一個很好的例子就是sortBy操作,其中所有輸入分區中的數據都在生成帶有新分區的RDD的過程中根據特定列進行排序。

為什麼Apache Spark速度很快以及如何使其運行更快

> A wide transformation (Source: Databricks)

因此,當您將作業提交給Spark時,您提交的基本上是一系列操作和轉換,然後由Catalyst轉換為作業的邏輯計劃,然後生成理想的物理計劃。

第二部分:Spark 魔術

現在,我們知道了Spark如何看待提交給它的工作,讓我們研究一下將動作和轉換列表轉換為工作的物理執行計劃的機制。

Spark是個懶惰的魔術師

首先,使用Spark時要記住的一個重要概念是它依賴於惰性評估。 這意味著,當您提交作業時,Spark只會在必須執行時(即,當它收到一個動作時(例如,當驅動程序要求一些數據或何時需要將數據存儲到HDFS中))發揮其魔力。

Spark無需立即一一運行轉換,而是將這些轉換存儲在DAG(有向無環圖)中,並且一旦接收到動作,它就會運行整個DAG並交付請求的輸出。 這樣一來,它就可以基於作業的DAG優化其執行計劃,而無需順序運行轉換。

一切如何發生

Spark依靠其優化器Catalyst進行必要的優化,以生成最有效的執行計劃。 Catalyst的核心包括一個通用庫,專用於表示樹並應用規則來操縱它們。 它利用Scala中的函數式編程構造,並提供特定於關係查詢處理的庫。

Catalyst的主要數據類型是由節點對象組成的樹,該樹上應用了一組規則對其進行優化。 這些優化通過四個不同的階段執行,如下圖所示:

為什麼Apache Spark速度很快以及如何使其運行更快

> Catalyst's optimization phases (source: Databricks)

邏輯/物理計劃

一開始可能不是很清楚的區別是術語"邏輯計劃"和"物理計劃"的使用。 簡而言之,邏輯計劃由一棵樹組成,該樹描述了需要做的事情,而沒有暗示如何做,而物理計劃則恰好描述了樹中每個節點將要做什麼。

例如,邏輯計劃僅表示需要執行聯接操作,而物理計劃則為該特定操作修復了聯接類型(例如ShuffleHashJoin)。

現在,我們來完成這四個步驟,並深入研究Catalyst的邏輯。

步驟1:分析

Catalyst優化管道的起點是一組未解決的屬性引用或關係。 無論您使用的是SQL還是DataFrame / Dataset API,SparkSQL最初都不會對您的數據類型或您所指的列是否存在(這就是未解決的意思)一無所知。 如果您提交選擇查詢,SparkSQL將首先使用Catalyst來確定您傳遞的每一列的類型以及您所使用的列是否實際存在。 為此,它主要依賴於Catalyst的樹和規則機制。

它首先為未解決的邏輯計劃創建一棵樹,然後開始在其上應用規則,直到解析所有屬性引用和關係。 在整個過程中,Catalyst依賴於Catalog對象,該對象跟蹤所有數據源中的表。

步驟2:邏輯優化

在此階段,Catalyst獲得了一些幫助。 隨著2017年Spark 2.2的發佈,引入了基於成本的優化器框架。 與基於規則的優化相反,基於成本的優化器使用統計信息和基數來查找最有效的執行計劃,而不是簡單地應用一組規則。

分析步驟的輸出是一個邏輯計劃,然後在第二步中進行一系列基於規則和基於成本的優化。 Catalyst將所有優化規則應用於邏輯計劃,並與基於成本的優化器一起使用,以將優化的邏輯計劃交付至下一步。

步驟3:物理規劃

就像上一步一樣,SparkSQL將Catalyst和基於成本的優化器同時用於物理規劃。 在利用一組物理規則和統計信息提供最有效的物理計劃之前,它會基於優化的邏輯計劃生成多個物理計劃。

步驟4:代碼生成

最後,Catalyst使用準符號(Scala提供的特殊功能)來生成要在每臺計算機上運行的Java字節碼。 Catalyst通過將作業的樹轉換為由Scala評估的抽象語法樹(AST)來使用此功能,然後由該樹編譯並運行生成的代碼。

總結一下

Spark SQL依靠複雜的管道來優化其需要執行的作業,並且在此過程的所有步驟中都使用其優化器Catalyst。 這種優化機制是Spark天文性能及其有效性的主要原因之一。

第三部分:將Spark推向新的高度

現在,我們檢查了Spark的複雜優化過程,很明顯,Spark依靠精心打造的機制來達到驚人的速度。 但是認為無論您如何做,Spark都能為您帶來最佳效果,這是一個錯誤。

尤其是從另一個數據處理工具遷移時,很容易做出假設。 與您一直使用的工具相比,處理時間減少了50%,這可能使您相信Spark正在全速運行,並且您無法進一步減少執行時間。 事實是,可以。

通過上面討論的過程,Spark SQL及其優化程序Catalyst可以自行完成奇蹟,但是通過一些曲折和技巧,您可以將Spark提升到一個新的水平。 因此,讓我們討論如何從頻譜的末端優化Spark作業

總是在引擎蓋下看一看

使用Spark時要記住的第一件事是,執行時間本身並沒有多大的意義。 要評估作業的績效,重要的是要知道幕後運行情況。 在開發和測試階段,您需要經常使用explain函數來查看要分析的語句生成的物理計劃,而對於深入分析,您可以添加擴展標誌以查看Spark的不同計劃。 選擇了SQL(從解析的邏輯計劃到物理計劃)。 這是檢測潛在問題和不必要階段的好方法,而無需實際執行作業。

知道何時使用緩存

處理大型數據集和複雜作業時,緩存非常重要。 它允許您保存計劃在後續階段中使用的數據集,以使Spark不再從頭開始創建它們。 這種優勢有時使開發人員陷入"超高速緩存"狀態,從而使高速緩存的數據集成為負擔,使您的工作變慢而不是對其進行優化。 要確定需要緩存的數據集,您必須準備整個工作,然後通過測試嘗試找出哪些數據集真正值得緩存,以及在什麼時候可以不持久化以釋放它們在內存中佔據的空間。 已緩存。 有效地使用緩存可以使Spark更快地運行某些計算10倍,這可以大大減少作業的總執行時間。

瞭解您的集群和數據

充分利用Spark的關鍵要素是根據您的集群微調其配置。 在某些情況下,可能要依靠默認配置,但是通常您離獲得更令人印象深刻的結果僅是一個參數。 選擇合適的執行程序數量,每個執行程序的內核數量以及每個執行程序的內存大小都是可以極大地影響您的工作性能的要素,因此請毫不猶豫地執行基準測試以查看是否可以使用某些參數。 優化。

最後,要牢記的一個重要因素是,您需要知道要處理的數據以及每次操作的期望。 如果一個階段花費的時間過長,即使它處理的數據少於其他階段,那麼您應該檢查另一側正在發生的事情。 在執行繁重的代碼和運行代碼時,Spark很棒,但是隻有您可以檢測到與您定義工作方式有關的業務相關問題。

(本文翻譯自Mahdi Karabiben的文章《Why Apache Spark Is Fast and How to Make It Run Faster》,參考:https://towardsdatascience.com/why-apache-spark-is-fast-and-how-to-make-it-run-faster-9d31bf3eae04)


分享到:


相關文章: