最近就計算與存儲分離的一套組合: Spark + OSS的性能進行了調優,取得了一些數據,這裡記錄一下。我測試的工作負載如下:

這裡測試的具體的數據是一個Parquet格式保存的數據,每個數據文件10G左右。Spark集羣的配置是每個Executor4C16G, 幾十個Executor的一個集羣。

計算與存儲分離從架構上來說可以讓分工更進一步細化: 做計算引擎的專心做計算引擎,做存儲的專心做存儲;從用戶角度來說讓用戶可以避免Vendor Locked In, 把數據以公開的格式保存在對象存儲上, 用戶如果什麼時候想遷移到其它平臺,只要把數據複製走就好了。但是對性能調優也帶來了挑戰,原本緊密結合的計算和存儲被拆開,調優的時候需要通盤考慮。

OSS參數調優

計算跟存儲分離之後,很影響速度的一塊是從存儲拉取數據的速度,開源引擎(Spark, Presto) 在跟這些對象存儲(AWS S3, Aliyun OSS)打交道都是通過Hadoop File System的介面, Aliyun OSS也實現了HDFS的介面, 在它的官方文檔上暴露了一些可以進行調優的參數: hadoop.apache.org/docs/

fs.oss.multipart.download.size

從Aliyun OSS讀取數據的每個請求獲取數據的大小。

可以看出,在指定的工作負載下 128000 是個最優值,當Download Size小於這個值的時候可能又太多時間花在來回Round Trip上,因此比較耗時,如果Download Size大於這個值的話,單次獲取數據花費時間過長,導致後續計算流程飢餓,因此性能會下降(猜測)。

fs.oss.multipart.download.ahead.part.max.number

OSS預讀取的個數。

在我的工作負載下,最優值是 4, 在預讀取數值過小的時候沒有起到預讀取的效果,而在預讀取數據過多的時候,對於ORC/Parquet這種列存數據,會存在多次seek操作,過多的預讀會造成數據浪費和網路阻塞。

fs.oss.multipart.download.threads

OSS同時下載數據的線程數。

  • 2: 68s
  • 4: 62s
  • 8: 64s
  • 16: 62s
  • 32: 64s

如果從平均時間來看,選擇不同的線程數性能差距不是太大,但是如果線程數太少(2), 性能確實會比線程數多一點的時候差一點,因為沒有充分利用多核的性能。

Spark的性能

spark.sql.files.maxPartitionBytes

這個參數控制Spark任務一個partition的數據量大小。這個參數會影響讀取OSS數據的時候產生的Task的個數。

從數據可以看出,134217728 * 3是最優值,Max Partition Bytes太小的時候Task數太多,需要太多輪才能執行完所有的Task;而如果太大前面花過多時間在數據讀取上,造成後續計算資源飢餓(猜測)。

總結

這次優化的思路是從底向上,從存儲到計算挨個調優,從存儲本身的格式,到OSS拉取數據的效率,最後到Spark切分分區的個數。不過這裡得到的參數實在特定的負載下進行的測試,不代表它們是通用的最優值。

計算引擎跟Object Store配合工作需要做更多的調優工作,原因在於Object Store其實不是一個真正的文件系統[1],很多在文件系統上很高效的操作在Object Store上面比較低效,比如rename, 在文件系統上面rename一個目錄是很輕量級的操作,但是在Object Store上面需要對目錄下面每個具體的文件進行rename操作,而每個rename操作背後都可能對應一個http請求,因此把Object Store當做文件系統使用需要做專門的性能調優。比如spark關於寫入操作就有一個針對Object Store的優化演算法,以減少rename的調用次數: spark.hadoop.mapreduce.fileoutputcommitter.algorithm.version=2[1]。

關於針對Object Store查詢的優化,Qubole做過很多事情,主要的優化點是Split Calculation, 在查詢開始的初期計算引擎需要獲取所有文件的元數據,比如文件大小,以決定哪些文件應該歸入一個Split,如果文件比較多的話,這個過程會耗費很多時間,Qubole做的一項優化就是批量獲取元信息,大大減少Split Calculation的時間,極端情況下可以優化幾十倍。[2][3][4]。

參考資料

  1. Spark: Integration with Cloud Infrastructures
  2. SparkSQL in the Cloud: Optimized Split Calculation
  3. Optimizing Hadoop for S3 – Part 1
  4. Optimizing S3 Bulk Listings for Performant Hive Queries

推薦閱讀:

相關文章