咱們談大數據性能調優,到底在談什麼,它的本質是什麼,以及 Spark 在性能調優部份的要點,這兩點讓在進入性能調優以前都是一個相當重要的問題,它的本質限制了咱們調優到底要達到一個什麼樣的目標或者說咱們是從什麼本源上進行調優。但願這篇文章能爲讀者帶出如下的啓發:算法
編程的時候發現一個驚人的規律,軟件是不存在的!全部編程高手級別的人不管作什麼類型的編程,最終思考的都是硬件方面的問題!最終思考都是在一秒、一毫秒、甚至一納秒究竟是如何運行的,而且基於此進行算法實現和性能調優,最後都是回到了硬件!數據庫
在大數據性能的調優,它的本質是硬件的調優!即基於 CPU(計算)、Memory(存儲)、IO-Disk/ Network(數據交互) 基礎上構建算法和性能調優!咱們在計算的時候,數據確定是存儲在內存中的。磁盤IO怎麼去處理和網絡IO怎麼去優化。編程
在大數據性能本質的思路上,咱們應該須要在那些方面進行調優呢?好比:bash
大數據最怕的就是數據本地性(內存中)和數據傾斜或者叫數據分佈不均衡、數據轉輸,這個是全部分佈式系統的問題!數據傾斜實際上是跟你的業務緊密相關的。因此調優 Spark 的重點必定是在數據本地性和數據傾斜入手。網絡
這是一張來至於官方的經典資源使用流程圖,這裏有三大組件,第一部份是 Driver 部份,第二就是具體處理數據的部份,第三就是資源管理部份。這一張圖中間有一個過程,這表示在程序運行以前向資源管理器申請資源。在實際生產環境中,Cluster Manager 通常都是 Yarn 的 ResourceManager,Driver 會向 ResourceManager 申請計算資源(通常狀況下都是在發生計算以前一次性進行申請請求),分配的計算資源就是 CPU Core 和 Memory,咱們具體的 Job 裏的 Task 就是基於這些分配的內存和 Cores 構建的線程池來運行 Tasks 的。數據結構
[下圖是 Spark 官方網站上的經典Spark架框圖]app
固然在 Task 運行的過程當中會大量的消耗內存,而Task又分爲 Mapper 和 Reducer 兩種不一樣類型的 Task,也就是 ShuffleMapTask 和 ResultTask 兩種類型,這類有一個很關建的調優勢就是如何對內存進行使用。在一個 Task 運行的時候,默應會佔用 Executor 總內存的 20%,Shuffle 拉取數據和進行聚合操做等佔用了 20% 的內存,剩下的大概有 60% 是用於 RDD 持久化 (例如 cache 數據到內存),Task 在運行時候是跑在 Core 上的,比較理想的是有足夠的 Core 同時數據分佈比較均勻,這個時候每每可以充分利用集羣的資源。 框架
核心調優參數以下:分佈式
1
2
3
4
5
6
7
|
num-executors
executor-memory
executor-cores
driver-memory
spark.default.parallelizm
spark.storage.memoryFraction
spark.shuffle.memoryFraction
|
Shuffle 分開兩部份,一個是 Mapper 端的Shuffle,另一個就是 Reducer端的 Shuffle,性能調優有一個很重要的總結就是儘可能不使用 Shuffle 類的算子,咱們能避免就儘可能避免,由於通常進行 Shuffle 的時候,它會把集羣中多個節點上的同一個 Key 匯聚在同一個節點上,例如 reduceByKey。而後會優先把結果數據放在內存中,但若是內存不夠的話會放到磁盤上。Shuffle 在進行數據抓取以前,爲了整個集羣的穩定性,它的 Mapper 端會把數據寫到本地文件系統。這可能會致使大量磁盤文件的操做。如何避免Shuffle能夠考慮如下:性能
大數據必然要思考的核心性能問題不外乎 CPU 計算、內存管理、磁盤和網絡IO操做,這是無可避免的,可是能夠基於這個基礎上進行優化,思考如何最優化的使用計算資源,思考如何在優化代碼,在代碼層面上防避墜入性能弱點;思考如何減小網絡傳輸和思考如何最大程度的實現數據分佈均衡。
在資源管理調優方面能夠設置一些參數,好比num-executors、executor-memory、executor-cores、driver-memory、spark.default.parallelizm、spark.storage.memoryFraction、spark.shuffle.memoryFraction
Shuffle 所致使的問題是全部分佈式系統都沒法避免的,可是如何把 Shuffle 所帶來的性能問題減小最低,是一個很可靠的優化方向。Shuffle 的第一階段即Mapper端在默應狀況下會寫到本地,而reducer經過網絡抓取的同一個 Key 在不一樣節點上都把它抓取過來,內存可能不夠,不夠的話就寫到磁盤中,這可能會致使大量磁盤文件的操做。在實際編程的時候,能夠用一些比較高效的RDD算子,例如 reduceByKey、aggregrateByKey、coalesce、foreachPartition、repartitionAndSortWithPartitions。