有時候我們希望能對spark ui進行一些定制化增強。并且我們希望盡可能不更改spark的源碼。為了達到此目标,我們會從如下三個方面進行闡述:
了解spark ui的處理流程
現有executors頁面分析
自己編寫一個helloword頁面
spark ui 在sparkcontext 對象中進行初始化,對應的代碼:
這裡做了兩個動作,
通過sparkui.createliveui 建立一個sparkui執行個體 _ui
通過 _ui.foreach(_.bind())啟動jetty。bind 方法是繼承自webui,該類負責和真實的jetty server api打交道。
和傳統的web服務不一樣,spark并沒有使用什麼頁面模闆引擎,而是自己定義了一套頁面體系。我們把這些對象分成兩類:
架構類,就是維護各個頁面關系,和jetty api有關聯,負責管理的相關類。
頁面類,比如頁面的tab,頁面渲染的内容等
架構類有:
sparkui,該類繼承子webui,中樞類,負責啟動jetty,儲存頁面和url path之間的關系等。
webui
頁面類:
sparkuitab(繼承自webuitab) ,就是首頁的标簽欄
webuipage,這個是具體的頁面。
sparkui 負責整個spark ui建構是,同時它是一切頁面的根對象。
對應的層級結構為:
在sparkcontext初始化的過程中,sparkui會啟動一個jetty。而建立起jetty 和webuipage的橋梁是org.apache.spark.ui.webui類,該類有個變量如下:
這個org.eclipse.jetty.servlet.servletcontexthandler是标準的jetty容器的handler,而
pagetohandlers 則維護了webuipage到servletcontexthandler的對應關系。
這樣,我們就得到了webuipage 和 jetty handler的對應關系了。一個http請求就能夠被對應的webuipage給承接。
從 mvc的角度而言,webuipage 更像是一個controller(action)。内部實作是webuipage被包括進了一個匿名的servlet. 是以實際上spark 實作了一個對servlet非常mini的封裝。如果你感興趣的話,可以到org.apache.spark.ui.jettyutils 詳細看看。
目前spark 支援三種形态的http渲染結果:
text/json
text/html
text/plain
一般而言一個webuipage會對應兩個handler,
在頁面路徑上,html和json的差別就是html的url path 多加了一個"/json"字尾。 這裡可以看到,一般一個page最好實作
render
renderjson
兩個方法,以友善使用。
另外值得一提的是,上面的代碼也展示了url path和對應的處理邏輯(controller/action)是如何關聯起來的。其實就是pagepath -> page的render函數。
我們以 executors 顯示清單頁 為例子,來講述怎麼自定義開發一個page。
首先你需要定義個tab,也就是executorstab,如下:
executorstab會作為一個标簽顯示在spark首頁上。接着定義一個executorspage,作為标簽頁的呈現内容,并且通過
關聯上 executorstab 和 executorspage。
executorspage 的定義如下:
實作executorspage.render方法:
最後一步調用
輸出設定頁面頭并且輸出content頁面内容。
這裡比較有意思的是,spark 并沒有使用類似freemarker或者velocity等模闆引擎,而是直接利用了scala對html/xml的文法支援。類似這樣,寫起來也蠻爽的。
如果想使用變量,使用{}即可。
那最終這個tag是怎麼添加到頁面上的呢?如果你去翻看了源碼,會比較心疼,他是在sparkui的initialize方法裡定義的:
那我們新增的該怎麼辦?其實也很簡單啦,通過sparkcontext擷取到 sparkui對象,然後調用attachtab方法即可完成,具體如下:
如果你是在spark-streaming裡,則簡單通過如下代碼就能把你的頁面頁面添加進去:
添加新的tab可能會報錯,scala報的錯誤比較讓人困惑,可以試試加入下面依賴:
實作新增一個helloword頁面
我們的例子很簡單,類似下面的圖:

無标題.png
按前文的描述,我們需要一個tab頁,以及一個展示tab對應内容的page頁。其實就下面兩個類。
org.apache.spark.streaming.ui2.kktab:
org.apache.spark.streaming.ui2.ttpage 如下:
記得添加上面提到的jetty依賴。