Spark Tuning概述:
Spark Program的瓶頸:
CPU:
memory:
CPU和memory合稱爲資源
network bandwidth:
Spark哪些地方可以優化:
storing RDDs in serialized form to decrease memory usage
以序列化的方式存儲減少內存的使用
memory:
內存調優:
1. 對象佔用了多少內存 cache測試一下
2. 訪問對象花費的內存
By default, Java objects are fast to access,
but can easily consume a factor of 2-5x more space than
the “raw” data inside their fields
3. GC (garbage collection)
Memory Management
Execution: shuffles, joins, sorts and aggregations
Storage: cache
統一內存管理:
兩者能互相借內存
但是,執行可以強行佔用存儲的內存
存儲不能強行佔用執行的內存 (強行的意思是,兩者都在工作的時候,
如果必要,執行的時候內存不夠了,可以不管storage,直接拿它的內存)
Spark1.5之前默認採用的是StaticMemoryManager,exe的最大安全內存和storage的最大安全內存都是固定的,調優的話需要手動去調優
Spark1.6之後默認採用的是UnifiedMemoryManager
UnifiedMemoryManager
// 假如系統內存10G 系統默認的reservedMemory是300M
val usableMemory = systemMemory - reservedMemory //10G-300M
//默認內存最大使用百分之60
val memoryFraction = conf.getDouble("spark.memory.fraction", 0.6)
//(10G-300M)*0.6
(usableMemory * memoryFraction).toLong
// 最大存儲所佔內存佔0.5 所以最大運行內存也佔0.5
onHeapStorageRegionSize =
(maxMemory * conf.getDouble("spark.memory.storageFraction", 0.5)).toLong,
GC:
Serialization:
Java:
large
slow
Kryo(spark2.4對應的是version 4):
並不支持all serializable types
需要註冊 register the classes
quickly
compact(緊湊,小)
如果沒註冊
就會慢一些,大一些
更換序列化方式:
沒有必要寫到代碼裏
建議寫到 $SPARK_HOME/conf/spark-default
也可以 ./spark-submit --conf key=value (優先級高一些)
測試數據佔用內存:
data==>rdd.cache 默認採用MEMORY_ONLY
data==>rdd.cache() 採用MEMORY_ONLY_SER
然後將spark.serializer 更改爲Kryo
data==>rdd.cache() 採用MEMORY_ONLY_SER
再regist後
data==>rdd.cache() 採用MEMORY_ONLY_SER
查看RDD佔用內存
1. put rdd into cache,look at the Storage
2. 在代碼中使用SizeEstimator類的estimate方法
SizeEstimator.estimate(path) 爲啥大了那麼多???
將文件變成RDD,本身會擴大2-5倍
但是上面這個estimate爲啥會接近10倍
並行度:
textFile 中的參數 minPartition 可以改用以提升並行度
groupByKey,reduceByKey(在PairRDDFunction)
總體來說:
set the config property spark.default.parallelism to change the default
可以在配置文件中更改 spark.default.parallelism 來改變默認的並行度
推薦一個core跑兩到三個task(不管是實際core還是虛擬core)
廣播變量:
減少每個task的內存(增加並行度):
分區太大,一個分區裝的數據太多,可能會導致OOM
需要通過增加並行度的方式來解決,這樣可以使每個分區的數量減少。
但是這種增加並行度的方式解決不了數據傾斜
數據本地性:
當一個作業申請到資源以後,需要Driver端將code發到Executor中去,之後需要在Executor上執行操作。
如果Executor執行的這個代碼和他操作需要的數據在一個節點上,這個計算的速度就會很快,效率也會很高
數據本地性是指code和data要儘可能近,最好是能在一個節點(理想)
tips:一個作業在申請完資源後,就被定到一臺機器上了,正常情況下之後再移動的只能是數據
數據和code的位置關係:
PROCESS_LOCAL(最佳) : 兩者在一個JVM裏,是一個進程的操作;這種情況是數據已經cache到executor中了(executor:run tasks and cache data)
NODE_LOCAL: (一臺機器)數據在HDFS上,作業在Executor上;跑的是兩個進程
RACK_LOCAL:
ANY: