上周在調優一個job ,發現spark history 出現一個重復出現的job , 這個job 寫著Listing leaf files and directorioes for 55 paths ...... job 190 到job 197 全是一樣的job. 這8個job 花了71 min.很奇怪。當然完成8個job 要花71min 也正常,executor 調度是要時間的。 不正常的是為什么要重復做一樣的job .根據線索去查源碼"Listing leaf files and directorioes for". 在https://github.com/apache/spark/blob/v2.3.1/sql/core/src/main/scala/org/apache/spark/sql/execution/datasources/InMemoryFileIndex.scala#L199。 這段代碼的注釋說,這個函數的功能是循環遍歷一組路徑下的文件。會選擇相應的策略來遍歷路徑。繼續往下看,知道了他所謂的策略就是如果一組路徑的數量 大于sparkSession.sessionState.conf.parallelPartitionDiscoveryThreshold( default value 32) ,就會開啟一個job 去遍歷所有partitions.? 用spark job 去遍歷路徑下的文件至少是并發的,性能肯定要好點。
問題的是為什么要重復地去讀路徑下的文件呢,直到我在log 里面發現了這句話。
Evicting cached table partition metadata from memory due to size constraints
? (spark.sql.hive.filesourcePartitionFileCacheSize = 262144000 bytes). This may impact query planning performance
大概的意思是table partition metadata 已經超過250M, 超過spark.sql.hive.filesourcePartitionFileCacheSize閾值了。會影響性能。根據線索『Evicting cached table partition metadata from memory due to size constraints 』去查詢源碼https://github.com/apache/spark/blob/master/sql/core/src/main/scala/org/apache/spark/sql/execution/datasources/FileStatusCache.scala#L126。這個函數會把表的partition 信息放到memory 里面。
到這里,我這里能猜出來就是這張表的partition 信息已經超過250M, 放不進內存,然后需要一次次地去遍歷partition paths 獲取partition 的信息例如文件大小,partition的字段信息。
然后我去查了下這張表partitions的信息。 一個partition 3g,居然被分成了3409 分片 , 平均一個分片文件1m.
解決方法: repartition,將3g? 重新repartition 13g 文件,這樣一個分片229M.?
經過數據清洗之后(你看到的是這8個字,我大概洗了8個小時都不止了)。我重新跑了這個job ,只出現了一次『Listing leaf files and directorioes for 55 paths 』 。 當第一次遍歷完這個表的partition 信息后, spark 就直接信息放內存里面了。不會再反復起job讀文件了。 ?執行時間當然大幅度減少。
我當時在心里問了2個問題
1. 為什么spark 要收集partition 信息,收集了這些信息有什么用處?
?spark 有些query 要做優化的時候,需要partition信息,where dt>'2020-01-01' and dt<'2020-02-01' 像partition 上的謂詞下推是需要收集partition 的信息的。
2. 為什么spark 不問 hive metastore 查詢去拿partition 信息呢,如果是其他格式例如 sequence file(這張hive table 是parquet 格式) ,是不是沒有這個問題?
spark里面不是所有的datasource 都是hive。除了hive ,還有json, parquet, orc 其他格式,為了搜集這些數據格式的信息。spark 自己寫了一個catalog. 但是無論是什么格式,如果一直有小文件的問題,那么問題也是一定存在的。