整體結構
在IPC(inter process call,進程間的通信)包中,最重要的3個類是Server,Client和RPC,它們具有層次化的結構。
- 1.RPC
- (1) RPC類是對Server、Client的具體化。
- 在RPC類中規定,客戶程序發出請求調用時,參數類型必須是Invocation;從服務器返回的值類型必須是ObjectWritable。
- 爲了加強理解,可以查看測試類TestIPC。在那裏,規定的參數類型與返回值類型都是LongWritable。
- (2) RPC類是對Server、Client的包裝,簡化用戶的使用。
- 如果一個類需充當服務器,只需通過RPC類的靜態方法getServer獲得Server實例,然後start。同時此類提供協議接口的實現。如果一個類充當客戶端,可以通過getProxy或者waitForProxy獲得一個實現了協議接口的proxy object,與服務器端交互。
- 爲了加強理解,可以查看測試類TestRPC,在那裏,實現的協議接口爲TestProtocol。
-
2.Server類
- (1).啓動Listener進程。
- 如果收到需要建立連接的請求,將建立連接,然後在上面捕獲讀操作的命令。收到命令之後,將把解析客戶端發過來信息的工作委派給Connection。Connection把信息封裝到Call對象中,放入隊列中,待Handler處理。
- (2).啓動指定數目的Handler線程,處理客戶端對指定方法調用的請求,然後把結果返回給客戶端。
-
3.Client類
- 用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機制瞭解,才能看的明白。這裏,可以參考博文:(todo)
當客戶端調用來到的時候
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,發現數據需要發送就開始發送。