? ? ? ? 社區(qū)版HBase-1.0.0里面的RPC跟hadoop中的RPC差不多,也是用了protobuffer、nio等技術(shù)來實現(xiàn)的。下面主要通過客戶端跟服務(wù)器端兩個部分以及一次createtable請求來講解hbase中的RPC。
一、客戶端
? ? ? ? 這里客戶端做的事情非常簡單,就是編寫java代碼,生成一個隨機字符串,然后以該字符串為表名,發(fā)出一個建表的請求(HBase還沒有任何權(quán)限控制)。下面是用eclipse一直跟蹤到發(fā)出網(wǎng)絡(luò)請求的方法調(diào)用棧。
? ? ? ? 關(guān)于客戶端部分,覺得最值得一提的還是使用protobuffer的部分(吐槽一句要不是因為這個,客戶端真的會簡單很多)。下面是client端使用到的跟protobuffer有關(guān)的類的類圖:
? ? ? ? 首先是MasterProtos類,這個類以protobuffer方式封裝了所有有關(guān)的請求與應(yīng)答,例如CreateTableRequest 以及CreateTableResponse;接著是MasterService這個類,這里以抽象方法的形式定義了差不多所有的操作HMaster的方法(感覺跟后面要講的Interface接口是一樣一樣的),除此之外還提供了構(gòu)造Stub以及BlockingStub的方法;Interface以及BlockingInterface分別以非阻塞的方式以及阻塞的方式定義了操作HMaster的方法,接口的區(qū)別在于Interface的所有方法的最后一個參數(shù)都是一個callback函數(shù),而BlockingInterface則沒有這個參數(shù);Stub以及BlockingStub分別通過聚合不同的channel實現(xiàn)自己的接口,從繼承關(guān)系來看RpcChannel接口的繼承類只有CoprocessorRpcChnnel以及它的子類,所以猜測非阻塞方式的接口八成都是給hbase里面endpoint(類似數(shù)據(jù)庫中的存儲過程與函數(shù))調(diào)用的時候使用的,而普通的RPC例如這里的創(chuàng)建表就是通過BlockingRpcChannel實現(xiàn)的,上面方法的調(diào)用棧也說明了這一點。
? ? ? ? 客戶端的實現(xiàn)還有很多細節(jié),比如調(diào)用超時、共享連接等等,這里就不細講了,可以自己看看代碼。
二、服務(wù)器
? ? ? ? 以前再將HMaster的啟動時,講過HMaster啟動很重要的一個過程就是啟動自己的RPC服務(wù)-MasterRpcServices,其中相關(guān)協(xié)議注冊代碼如下:
? ? ? ? 可以看見這里有注冊上面講到的MasterService,由于服務(wù)端在linux上以命令行的形式啟動,所以不能像上面那樣截取棧調(diào)用信息。但是打開相關(guān)代碼,可以觀察到由MasterRpcServices調(diào)用HMaster中的createTable方法,最后在后者的代碼中以如下方式處理請求:
? ? ? 這里最重要的就是service.submit這個方法了,其中service是ExecutorService類型的成員變量。按照代碼里面的注釋來看ExecutorService差不多就是一個模仿reactor模型(可以參考http://www.blogjava.net/DLevin/archive/2015/09/02/427045.html)實現(xiàn)的處理模型了,有一個可以提交請求的隊列以及一系列的處理請求線程(handler)。大數(shù)據(jù)中有很多組件都是模仿這種思路實現(xiàn)的RPC服務(wù)端,例如hdfs以及yarn。
三、其他
? ? ? ? 這里沒有細節(jié)講述服務(wù)端是如何識別發(fā)過來的RPC請求的,這是因為以前寫過類似的Hadoop服務(wù)端處理請求時是如何是別的,主要還是客戶端在傳輸RPC請求的時候?qū)⒎椒ê灻麑懭刖W(wǎng)絡(luò)IO,服務(wù)端會根據(jù)這個來判斷調(diào)用什么方法。