1. 程式人生 > >基於Spark UI效能優化與除錯——初級篇

基於Spark UI效能優化與除錯——初級篇

Spark有幾種部署的模式,單機版、叢集版等等,平時單機版在資料量不大的時候可以跟傳統的java程式一樣進行斷電除錯、但是在叢集上除錯就比較麻煩了...遠端斷點不太方便,只能通過Log的形式進行資料分析,利用spark ui做效能調整和優化。

那麼本篇就介紹下如何利用Ui做效能分析,因為本人的經驗也不是很豐富,所以只能作為一個入門的介紹。

大體上會按照下面的思路進行講解:

  • 怎麼訪問Spark UI
  • SparkUI能看到什麼東西?job,stage,storage,environment,excutors
  • 調優的一些經驗總結

Spark UI入口

如果是單機版本,在單機除錯的時候輸出資訊中已經提示了UI的入口:

17/02/26 13:55:48 INFO SparkEnv: Registering OutputCommitCoordinator
17/02/26 13:55:49 INFO Utils: Successfully started service 'SparkUI' on port 4040.
17/02/26 13:55:49 INFO SparkUI: Started SparkUI at http://192.168.1.104:4040
17/02/26 13:55:49 INFO Executor: Starting executor ID driver on host localhost

如果是叢集模式,可以通過Spark日誌伺服器xxxxx:18088者yarn的UI進入到應用xxxx:8088,進入相應的Spark UI介面。

主頁介紹

上面就是Spark的UI主頁,首先進來能看到的是Spark當前應用的job頁面,在上面的導航欄:

  • 1 代表job頁面,在裡面可以看到當前應用分析出來的所有任務,以及所有的excutors中action的執行時間。
  • 2 代表stage頁面,在裡面可以看到應用的所有stage,stage是按照寬依賴來區分的,因此粒度上要比job更細一些
  • 3 代表storage頁面,我們所做的cache persist等操作,都會在這裡看到,可以看出來應用目前使用了多少快取
  • 4 代表environment頁面,裡面展示了當前spark所依賴的環境,比如jdk,lib等等
  • 5 代表executors頁面,這裡可以看到執行者申請使用的記憶體以及shuffle中input和output等資料
  • 6 這是應用的名字,程式碼中如果使用setAppName,就會顯示在這裡
  • 7 是job的主頁面。

模組講解

下面挨個介紹一下各個頁面的使用方法和實踐,為了方便分析,我這裡直接使用了分散式計算裡面最經典的helloworld程式——WordCount,這個程式用於統計某一段文字中一個單詞出現的次數。原始的文字如下:

for the shadow of lost knowledge at least protects you from many illusions

上面這句話是有一次逛知乎,一個標題為 讀那麼多書,最後也沒記住多少,還為什麼讀書?其中有一個回覆,引用了上面的話,也是我最喜歡的一句。意思是:“知識,哪怕是知識的幻影,也會成為你的鎧甲,保護你不被愚昧反噬”(來自知乎——《為什麼讀書?》)

程式程式碼如下:

public static void main(String[] args) throws InterruptedException {
        SparkConf sparkConf = new SparkConf();
        sparkConf.setMaster("local[2]");
        sparkConf.setAppName("test-for-spark-ui");
        JavaSparkContext sc = new JavaSparkContext(sparkConf);
    <span class="hljs-comment">//知識,哪怕是知識的幻影,也會成為你的鎧甲,保護你不被愚昧反噬。</span>
    JavaPairRDD&lt;<span class="hljs-built_in">String</span>,Integer&gt; counts = sc.textFile( <span class="hljs-string">"C:\\Users\\xinghailong\\Desktop\\你為什麼要讀書.txt"</span> )
            .flatMap(line -&gt; Arrays.asList(line.split(<span class="hljs-string">" "</span>)).iterator())
            .mapToPair(s -&gt; <span class="hljs-keyword">new</span> Tuple2&lt;<span class="hljs-built_in">String</span>,Integer&gt;(s,<span class="hljs-number">1</span>))
            .reduceByKey((x,y) -&gt; x+y);

    counts.cache();
    <span class="hljs-built_in">List</span>&lt;Tuple2&lt;<span class="hljs-built_in">String</span>,Integer&gt;&gt; result = counts.collect();
    <span class="hljs-keyword">for</span>(Tuple2&lt;<span class="hljs-built_in">String</span>,Integer&gt; t2 : result){
        System.out.println(t2._1+<span class="hljs-string">" : "</span>+t2._2);
    }
    sc.stop();