本篇咱們深刻源碼,探究一下livy解釋器的實現原理。java
ReplDriver
是真正最終運行的Driver程序對應的類(其基類是第三篇中提到的RSCDrvier
)。在這一層,重點關注handle系列方法:web
def handle(ctx: ChannelHandlerContext, msg: BaseProtocol.ReplJobRequest): Int = { ... } def handle(ctx: ChannelHandlerContext, msg: BaseProtocol.CancelReplJobRequest): Unit = { ... } def handle(ctx: ChannelHandlerContext, msg: BaseProtocol.ReplCompleteRequest): Array[String] = { ... } def handle(ctx: ChannelHandlerContext, msg: BaseProtocol.GetReplJobResults): ReplJobResults = { ... }
這些方法其實負責處理各類類型的request,例如BaseProtocol.ReplJobRequest
就是處理執行代碼
請求。前面有篇提到的RpcServer
,負責基於netty啓動服務端,而且綁定處理請求的類,其內部的dispatcher
會負責經過反射,找到對應的handle方法並調用。apache
關於RPC,這裏只是提一下,後面的篇章再跟你們一塊兒分析細節
本篇的重點是探究REPL,因此咱們重點從BaseProtocol.ReplJobRequest
處理方法跟入:session
def handle(ctx: ChannelHandlerContext, msg: BaseProtocol.ReplJobRequest): Int = { session.execute(EOLUtils.convertToSystemEOL(msg.code), msg.codeType) }
這裏調用了session對象的execute,因此繼續進去看session對象ide
ReplDriver
持有Session對象的實例,在ReplDriver
初始化階段實例化,並調用了session.start()
方法:oop
session會建立SparkInterpreter
,並調用SparkInterpreter.start
。ui
session的execute
方法最終會調用SparkInterpreter.execute
。spa
在Livy
中SparkInterpreter
是一種Interpreter
(接口)。一樣是Interpreter
的還有:netty
SparkInterpreter.start
主要乾的事情就是初始化SparkILoop
。SparkILoop
是org.apache.spark.repl
包下的類,它其實就是spark自己實現REPL的核心類。livy在這裏其實只是包裝了spark自己已經實現的功能。另一件事情,就是第三篇中提到的在解釋器中bind變量,下面的代碼就是bind變量的過程:code
上面代碼中的bind
方法和execute
方法就是核心方法,其實現方法就是直接調用SparkILoop
的對應方法:
// execute其實最後調到interpret // code就是要執行的代碼 override protected def interpret(code: String): Result = { sparkILoop.interpret(code) } // name: 變量名 // tpe: 變量類型 // value: 變量對象真實引用 // modifier: 變量各類修飾符 override protected def bind(name: String, tpe: String, value: Object, modifier: List[String]): Unit = { sparkILoop.beQuietDuring { sparkILoop.bind(name, tpe, value, modifier) } }
到這裏其實思路已經比較清晰了,咱們獲得下面的層次關係圖:
本篇從源碼的角度分析了livy如何利用spark實現的REPL,實現交互式代碼運行。所以,有了livy,至關於把spark的REPL搬到了web。