1、調優背景
Spark作爲Zeppelin的SQL底層執行引擎,通過Thriftserver處理jdbc連接,爲提高硬件資源利用率、IO帶寬和內存利用率,特針對性的進行Spark性能調優,目的是提高多租戶環境下Spark SQL執行效率。
2、整體調優結果
表2-1 整體調優結果
sql NO. |
MR |
sp-1(s) |
sp-2(p) |
sp-3(ec) |
sp-4(or) |
sp-5 |
sql1 |
690 |
71 |
37.7 |
29.5 |
29.2 |
27.4s |
sql2 |
428.2 |
96.6 |
61 |
32.3 |
31.6 |
33.5 |
sql3 |
192.5 |
138.5 |
47.3 |
35.4 |
37.3 |
35.4 |
sql4 |
188 |
154. |
76.8 |
51.7 |
49.5 |
48.8 |
sql5 |
1409 |
393 |
265 |
184 |
179.5 |
231 |
sql6 |
580.6 |
147.7 |
173 |
52 |
53.4 |
43.5 |
sql7 |
9128.5 |
2467 |
1240 |
1176 |
1258 |
1274 |
sql8 |
216 |
21 |
40 |
18.1 |
18.7 |
21.5 |
sql9 |
404 |
127 |
113 |
116.2 |
112.5 |
117.4 |
調優隨機選取線上9條SQL,表橫軸是調優測試項目,測試在集羣空閒情況下進行,後一個的測試都是疊加前面測試參數。從數據可參數經過調優,理想環境下性能相對Spark默認參數可提高50%到300%。
表2-2 調優項目說明
測試項目 |
說明 |
MR |
使用Hive測試 |
sp-1 |
默認spark參數測試 |
sp-2 |
spark.sql.shuffle.partitions參數 |
sp-3 |
executor與core參數比例 |
sp-4 |
spark.shuffle.*參數 |
sp-5 |
spark.sql.files.openCostInBytes參數 |
主要調優參數就是這幾個,實際調優參數不止這幾個,下文將說明。此外因爲Spark現在默認開啓tungsten,所以省略tungsten調參。
3、單個參數調優記錄
1)並行度測試記錄
表3-1 並行度調優結果
sql NO. |
200 partitions |
400 partitions |
600 partitions |
sql1 |
71 |
50 |
37.7 |
sql2 |
96.6 |
95 |
61 |
sql3 |
138.5 |
126 |
47.3 |
sql4 |
154. |
179 |
76.8 |
sql5 |
393 |
303.8 |
265 |
sql6 |
147.7 |
186 |
173 |
sql7 |
2467 |
1626 |
1240 |
sql8 |
232.7 |
37 |
40 |
sql9 |
127 |
136 |
113 |
從調優結果和參考其他公司提供的信息看,對於公司數據規模,增大並行度有明顯的性能提高,而且從sql7的數據看出,增大並行度,對大SQL性能提升效果顯著。
2)core和memory比例測試記錄
本測試的分區數爲600,主要測試executor的core和memory比例,core越多,能同時處理的task越多。
表3-2 core和memory比例測試結果
|
1core,4G |
2core,6G |
2core,7G |
2core ,8G |
3core,6G |
3core,9G |
sql1 |
37.7 |
30 |
44 |
29.5 |
78.6 |
30 |
sql6 |
61 |
122 |
107 |
164 |
377 |
144 |
sql7 |
1240 |
failed |
failed |
1176 |
failed |
failed |
1core對應4G是集羣初始參數配置,這裏選取3條典型sql記錄詳細測試結果,根據比較發現1core 對3G內存對中小sql能跑通,對稍大sql(如sql7)則直接因爲內存不足failed,考慮到實際測試其他公司推薦參數,最佳配比是2core對應8G內存,能更好利用core和mem(這裏內存其實越大肯定越好)。
3)spark shuffle測試記錄
這裏涉及參數主要是spark.shuffle.file.buffer和spark.reducer.maxSizeInFlight。其中spark.shuffle.file.buffer主要負責shuffle write過程寫數據到磁盤過程的buffer,如果內存大的話建議提高該參數;spark.reducer.maxSizeInFlight負責shuffle read過程中reduce端機器從map端機器同時讀取數據的大小。
表 3-3 spark shuffle測試記錄
sql NO. |
file.buffer=32k(默認),maxSizeInFlight=48M |
file.buffer=48k,maxSizeInFlight=64M |
sql1 |
29.5 |
29.2 |
sql2 |
32.3 |
31.6 |
sql3 |
35.4 |
37.3 |
sql4 |
51.7 |
49.5 |
sql5 |
184 |
179.5 |
sql6 |
52 |
53.4 |
sql7 |
1176 |
1258 |
sql8 |
18.1 |
18.7 |
sql9 |
116.2 |
112.5 |
比較測試結果可以發現,提高buffer對執行時間沒有顯著影響,而由理論和其他公司經驗,提高buffer是能提高執行效率的。經分析發現集羣配置2core對應的8G內存是很保守的,shuffle過程的連接數有M * R個,每個連接都有一個buffer,對應消耗內存不小,對內存本就喫緊的job因內存不足,影響執行效率,由於內存約束,增加該shuffle參數對job執行時間沒有顯著影響。
4)spark.sql.files.openCostInBytes參數調優
該參數默認4M,表示小於4M的小文件會合併到一個分區中,用於減小小文件,防止太多單個小文件佔一個分區情況。
表3-4spark.sql.files.openCostInByte測試記錄
sql NO. |
spark.sql.files.openCostInByte = 4M |
spark.sql.files.openCostInBytes = 8M |
sql1 |
29.2 |
27.4s |
sql2 |
31.6 |
33.5 |
sql3 |
37.3 |
35.4 |
sql4 |
49.5 |
48.8 |
sql5 |
179.5 |
231 |
sql6 |
53.4 |
43.5 |
sql7 |
1258 |
1274 |
sql8 |
18.7 |
21.5 |
sql9 |
112.5 |
117.4 |
由數據比較可見,對job執行效率有一定提升,但是對於sql5則效率降低,經分析sql5每個分區的input大小是7.5M左右,在參數臨界位置附近,反而降低執行效果。但是對於小SQL,可能有少量性能提升。
4、其他調優測試
1)數據本地性調優
涉及參數有spark.locality.wait.process,spark.locality.wait.node, spark.locality.wait.rack,分別是計算進程內、節點內、機架數據本地性的超時時間間隔,在集羣繁忙的時候網絡會不暢通,提高該值會有效提高數據locality比例,但是太高則會造成等待時間過長。
表4-1 不同locality情況下執行時間情況
sql |
locality情況 |
執行時間(s) |
||
Node local |
Rack local |
Any |
||
sql1 |
214 |
232 |
0 |
140.2 |
326 |
122 |
0 |
26.4 |
|
sql6 |
52067 |
1492 |
635 |
139 |
49456 |
1392 |
142 |
41 |
|
49998 |
1380 |
53 |
36 |
從表中結果可以明顯看出,locality級別越高(即計算離數據越近),job執行時間越短,因此調節這組參數對提高job執行時間有明顯效果,因爲能減小網絡傳輸開銷,提高執行效率。
2)數據格式對查詢效率影響測試
spark.sql.hive.convertCTAS默認爲false,如果爲true則表示用戶創建的表使用parquet格式,下面測試不同數據格式建表的存儲大小和查詢時間記錄。
表4-2 不用格式對查詢影響
|
格式 |
讀取數據量(KB) |
存儲大小(byte) |
查詢時間(s) |
sql-10 |
text |
1167.5 |
1164841 |
10.5 |
orc |
1028.3 |
572035 |
10.9 |
|
parquet |
1083 |
1093378 |
10.7 |
|
sql-11 |
text |
41.7 |
42687 |
7.8 |
orc |
33.1 |
25841 |
4.3 |
|
parquet |
21.7 |
45112 |
4.9 |
由表看出,orc格式的存儲效率最佳,查詢時間性能也比較好。考慮開啓參數,建表默認使用orc格式。
3)spark.executor.overhead.memory參數測試記錄
下面兩張表從不同維度看堆外內存參數對計算的影響。
表4-3 overheadmemory不同值調優記錄
spark.yarn.executor.overhead |
200 partitions |
400 partitions |
512M |
failed |
522 |
1024M |
393 |
303.8 |
由數據可以看出,當overheadmemory內存比較小(512M)時增大分區能緩解計算壓力,讓計算成功執行。
表4-4 overheadmemory=512M情況測試記錄
SQL |
200partitions |
400partitions |
SQL4 |
288.7 |
199.1 |
SQL5 |
failed |
522 |
表4-4驗證了表4-3測試的觀點。
4)對sql7最佳性能調優的記錄
本測試作爲實驗性質,針對大SQL進行調優,目的是尋找大SQL調優的極限。
表4-5 sql7最佳性能調優
sql7參數 |
stage1併發數 |
執行時間 |
1core,4G,200partitiions,1G executor.memoryOverhead |
/ |
2467 |
2core,8Gmem,600partitions,1G executor.memoryOverhead |
2160 |
failed |
2core,12Gmem,1500partitions,1G executor.memoryOverhead |
1280 |
1308 |
2core,12Gmem,3500partitions,1G executor.memoryOverhead |
1280 |
1132 |
3core,12Gmem,3500partitions,,2G executor.memoryOverhead |
1748 |
986 |
3core,8Gmem,3500partitions,2G executor.memoryOverhead |
2160 |
954 |
3core,8Gmem,5000partitions,2G executor.memoryOverhead |
2160 |
838.1 |
這裏因爲時間因素,沒繼續往下調,但從調優實驗結果看,合理的core,mem比例以及並行度是能顯著提升執行效率,從2000多秒到800多秒,達到300%提升。
5、Zeppelin用戶調優參數
經過調優測試,SQL用戶在寫SQL中可以調節的參數如下表彙總。
表4-6 SQL用戶可調節參數
參數 |
說明 |
spark.sql.shuffle.partitions |
對於大SQL,提高該值顯著提升執行效率和穩定性 |
spark.sql.autoBroadcastJoinThreshold |
對於大表join小表,當數據級差距明顯時可增大該閾值,能減小網絡數據拉取開銷 |
spark.dynamicAllocation.enabled |
該特性用於join操作,目的是實現無shuffle的join,不是對所有SQL有效,調整爲true可開啓該特性 |
|
|
SQL用戶通過設置這幾個參數,能一定程度提高SQL執行效率和穩定性。
6、GC調優
這裏根據調研,有效的參數主要是InitiatingHeapOccupancyPercent,表示ConcGCThreads和G1HeapRegionSize調優記錄如下表:
表6-1 GC調優記錄
序號 |
InitiatingHeapOccupancyPercent |
ConcGCThreads |
G1HeapRegionSize |
SQL |
時間 |
1 |
45(默認) |
5(默認) |
2(默認) |
sql12 |
485 |
sql13 |
387 |
||||
2 |
35 |
15 |
2 |
sql12 |
458 |
sql13 |
335 |
||||
3 |
35 |
15 |
4 |
sql12 |
451 |
sql13 |
334 |
||||
4 |
35 |
15 |
6 |
sql12 |
489 |
sql13 |
297 |
表6-2 GC1日誌分析指標
|
Throughput |
Avg GC Time |
Max GC Time |
Total GC Count |
Total GC Time |
G1 Humongous Allocation |
Allocation Failure |
1 |
99.4% |
8ms |
70ms |
118 |
920ms |
40 |
7 |
2 |
98.24% |
12ms |
120ms |
277 |
3420ms |
141 |
33 |
3 |
99.65% |
11ms |
70ms |
85 |
910ms |
24 |
17 |
4 |
99.4% |
11ms |
70ms |
146 |
1550ms |
67 |
20 |
備註:GC分析日誌通過http://gceasy.io分析得出
該測試在測試集羣進行,使用倉庫的兩張表作爲測試用例,根據執行結果,發現不同參數對執行時間影響不大,但是根據執行時間和GC日誌分析的指標,推薦第三組參數。
7、總結
調優參數雖名目多樣,但最終目的是提高CPU利用率,降低帶寬IO,提高緩存命中率,減少數據落盤。
不同數據量的最優參數都不相同,調優目的是讓參數適應數據的量級以最大程度利用資源,經調優發現並不是所有參數有效,有的參數的效果也不明顯,最後折中推薦如下調優參數以適應絕大多數SQL情況,個別SQL需要用戶單獨調參優化。(以下參數主要用於Spark Thriftserver)
表7-1 調優參數值
參數 |
含義 |
默認值 |
調優值 |
spark.sql.shuffle.partitions |
併發度 |
200 |
800 |
spark.executor.overhead.memory |
executor堆外內存 |
512m |
1.5G |
spark.executor.memory |
executor堆內存 |
1G |
9G |
spark.executor.cores |
executor擁有的core數 |
1 |
3 |
spark.locality.wait.process |
進程內等待時間 |
3 |
3 |
spark.locality.wait.node |
節點內等待時間 |
3 |
8 |
spark.locality.wait.rack |
機架內等待時間 |
3 |
5 |
spark.rpc.askTimeout |
rpc超時時間 |
10 |
1000 |
spark.sql.autoBroadcastJoinThreshold |
小表需要broadcast的大小閾值 |
10485760 |
33554432 |
spark.sql.hive.convertCTAS |
創建表是否使用默認格式 |
false |
true |
spark.sql.sources.default |
默認數據源格式 |
parquet |
orc |
spark.sql.files.openCostInBytes |
小文件合併閾值 |
4194304 |
6291456 |
spark.sql.orc.filterPushdown |
orc格式表是否謂詞下推 |
false |
true |
spark.shuffle.sort.bypassMergeThreshold |
shuffle read task閾值,小於該值則shuffle write過程不進行排序 |
200 |
600 |
spark.shuffle.io.retryWait |
每次重試拉取數據的等待間隔 |
5 |
30 |
spark.shuffle.io.maxRetries |
拉取數據重試次數 |
3 |
10 |
任何參數設置都不可能對所有SQl有效,這裏的推薦參數主要針對公司中小SQL(執行時間不超過10分鐘)適用,對於大SQL如sql7則需單獨調參才能高效運行。以上測試均爲公司實際環境進行 。
測試環境:600+物理機集羣,spark 2.0.1 on yarn
**文章會同步到公衆號,關注公衆號,交流更方便:**