1. 程式人生 > >Hadoop中的RPC實現(概述)

Hadoop中的RPC實現(概述)

  •       Hadoop作為一個儲存與服務的基礎性平臺,同時它的內部有采用了master/slave架構,那麼其內部通訊和與客戶端的互動就是必不可少的了。Hadoop在實現時拋棄了JDK自帶的一個RPC實現——RMI,而自己基於IPC模型實現了一個高效的輕量級RPC。

整體結構

    在IPC包中,最重要的3個類是ServerC,lient和RPC,它們具有層次化的結構
  1.    1.RPC類是對Server、Client的具體化。在RPC類中規定,客戶程式發出請求呼叫時,引數型別必須是Invocation;從伺服器返回的值型別必須是ObjectWritable。為了加強理解,可以檢視測試類TestIPC。在那裡,規定的引數型別與返回值型別都是LongWritable。
  2.    2.RPC類是對Server、Client的包裝,簡化使用者的使用。如果一個類需充當伺服器,只需通過RPC類的靜態方法getServer獲得Server例項,然後start。同時此類提供協議介面的實現。如果一個類充當客戶端,可以通過getProxy或者waitForProxy獲得一個實現了協議介面的proxy object,與伺服器端互動。為了加強理解,可以檢視測試類TestRPC,在那裡,實現的協議介面為TestProtocol。
  • Server類

  1.     1.啟動Listener程序。如果收到需要建立連線的請求,將建立連線,然後在上面捕獲讀操作的命令。收到命令之後,將把解析客戶端發過來資訊的工作委派給Connection。Connection把資訊封裝到Call物件中,放入佇列中,待Handler處理。
  2.     2.啟動指定數目的Handler執行緒,處理客戶端對指定方法呼叫的請求,然後把結果返回給客戶端。
  • Client類

  1.     1.用Call封裝好呼叫資訊,然後藉助從連線池中取出的Connection向伺服器端傳送,等待結果。如果到指定伺服器的Connection不存在,將馬上建立。Connection執行緒讀取伺服器方法呼叫的返回資訊。完成之後,通知主執行緒。

客戶端C要發起向服務端S的關於方法M呼叫
    1. C首先建立一個通向S的連線getConnection,然後將此次呼叫放入CallList裡,這樣客戶端就可以同時發生很多呼叫,每個呼叫用ID來識別。
    2. 傳送呼叫引數。呼叫引數是Client的呼叫方(比如NameNode,DataNode等)指定的,一般就是一個Invocation物件,裡面包含要呼叫的方法和引數。瞭解JAVA動態代理類
java.lang.reflect.Proxy會對這裡的理解有很大幫助。
    3. 等待呼叫結果.Client.Connection是個執行緒類,啟動了之後唯一做的時候就是等待呼叫結果

    對於伺服器端,其有一個方法start指定了啟動伺服器開始監聽,這個start被四個類呼叫,分別是TaskTracker.initialize,Namenode.initialize,Jobtracker.offerService,Datanode.startDatanode顯然,任何兩者之間的通訊都是考這個client-server模型實現的。
    server start後,幹了三件事
    1. 啟動listen,監聽客戶端Call
    2. 啟動response,隨時準備將處理結果發回client
    3. 啟動10個handler,處理具體的請求。

    這裡必須對
java NIO機制瞭解,才能看的明白。

當客戶端呼叫來到的時候
   1. listen首先將呼叫doaccept將Connection附加給selectionkey,然後呼叫doread新增,doread會呼叫Connecton的方法將呼叫新增到呼叫列表,該列表是BlockingQueue,其保持列表先進先出的特性而且支援同步
   2. listen將call新增到calllist後,handler因為一直在檢測calllist,於是其立刻開始處理,處理完畢後,其將結果儲存在call物件中,然後呼叫response開始向客戶端寫。這裡hadler呼叫的call只是一個未實現的方法,具體實現在RPC.Server中,這點需要注意。
   3. Response也監視responselist,如果responselist中某個call需要將結果寫入客戶端,就寫出,當某個call的結果被髮送完畢,從responselist中刪除該call物件。

    這裡有個細節:handler完成call之後就開始向客戶端寫call結果,但是結果可能太多,無法通過一次性發送完畢,而傳送之後還要等待client接受完畢才能再發,如果現在handler在那裡等待客戶端接受完畢,然後再發,效率不高。解決辦法是handler處理完畢之後,只向client傳送一次處理結果。如果這一次將處理結果傳送完畢,接下來就沒有response的事情了,如果沒有傳送完畢,接下來response負責將剩下的處理結果傳送給客戶端。這樣handler的併發量會大一些。

    伺服器實現中大量利用監視佇列,比如handler就直觀堅持calllist,一旦發現數據就開始處理,而response就監視responselist,發現數據需要傳送就開始傳送。