天天看點

HBase rpc架構介紹

概述

總體結構如下:

HBase rpc架構介紹

用戶端

子產品介紹

排程執行

該子產品主要提供接口轉換、錯誤重試、服務分組等能力;

1:接口轉換

服務層定義的服務接口與使用者層不同,比如put/delete/increment/append等操作底層都是調用的mutate接口,而batch相關的操作,無論是讀還是寫都調用multi接口;

轉換邏輯封裝為一個callable對象,交由RpcRetryingCaller處理;

2:錯誤重試

RpcRetryingCaller負責與服務代理子產品直接互動 ,以及錯誤時的重試;

3:服務分組

batch相關的操作可能會涉及到多個rs,需要按照rs進行分組,然後多線程并發請求,這些邏輯是在AsyncProcess中;

對于非batch類請求則直接使用RpcRetryingCaller進行調用,AsyncProcess的内部實際上也是依賴了該類來執行單個rs請求;

服務代理

服務代理通常叫stub,即樁的意思,其實作了與服務端同樣的接口;

對排程執行子產品而言,調用stub的方法就相當于調用遠端的服務,而不必關心實作細節;

這部分依賴protobuf元件,通過在proto檔案中定義service及message類型的參數,可直接生成接口和stub實作類;

在ConnectionImplementation類中有一個Map類型的stubs變量,其key為service name + regionserver,value則是stub執行個體;

通信子產品

該子產品主要進行序列化和io處理;

目前HBase已采用netty作為底層的io架構,用戶端的核心類為NettyRpcClient;

服務代理層的stub類中含有一個BlockingRpcChannel類型的變量,而rpcClient通過實作該接口并将執行個體注入來與之對接;

序列化則是依賴protobuf元件,序列化與反序列化的邏輯都放在NettyRpcDuplexHandler中,該類注冊在netty的pipeline,會基于不同的事件自動調用;

元件互動

HBase rpc架構介紹

這裡面整體調用脈絡比較清晰,值得注意的是,應用線程在調用底層io線程進行發送之前,會将請求相關的東西封裝到一個call對象裡面,然後将其暫存在一個id2call的map中,在拿到傳回結果時,根據結果資料中的callId,再從id2call中擷取對應的call對象,并喚醒應用線程;

線程互動

分為簡單請求和複雜請求兩種情況,差別在于是否使用額外的線程池;

簡單請求

非multi和scan;

HBase rpc架構介紹

複雜請求

multi和scan;

HBase rpc架構介紹

服務端

該子產品主要負責資料的讀取、反序列化并封裝為call對象;

核心實作類為NettyRpcServer,通過在pipeline中注冊的一些handler來完成上述處理;

資料流的格式大緻如下:

HBase rpc架構介紹

對其處理可分為3個階段:

1、讀取preamble(序文)

這是連接配接建立後,最先要發送的資料,共有6個位元組,格式為"HBasXX",後兩位為與版本和校驗相關的數字;

相關的handler為FixedLengthFrameDecoder和NettyRpcServerPreambleHandler,前者負責讀取定長位元組數,後者負責校驗内容;

2、讀取connectionHeader

該部分包含size和data,讀取完前述的preamble之後再讀取4個位元組即為size,轉換後的int即代表了data部分的長度;

connectionHeader用來對連接配接進行一些約定,比如請求的serviceName、編碼、壓縮及加密設定等,具體參見RPC.proto檔案中的ConnectionHeader;

相關的handler為NettyRpcFrameDecoder和NettyRpcServerRequestDecoder,前者負責讀取定長位元組得到size以及根據size讀取data,後者則通過調用ServerRpcConnection的processConnectionHeader方法進行進一步處理;

connectionHeader隻會發送和處理一次,後續的資料就都是request了;

3、讀取request

該部分的資料讀取部分與connectionHeader一緻,差別在于處理方法為ServerRpcConnection的processRequest;

其内部主要包含requestHeader和param兩部分;

requestHeader為單次請求的總體描述,比如請求的方法名、優先級、逾時時間等,具體參見RPC.proto檔案中的RequestHeader;

param為所請求方法的參數,比如GetRequest、MutateRequest等,具體參見Client.proto和HBase.proto檔案中的相關定義;

通信子產品得到的call對象會交由rpcScheduler進行排程,目前預設實作為SimpleRpcScheduler;

rpcScheduler的主要作用是根據請求類型把請求配置設定給不同的rpcExecutor執行個體,請求類型有3種:普通請求、高優先級請求和replication請求,而rpcExecutor的實作目前主要由RWQueueRpcExecutor和FastPathBalancedQueueRpcExecutor兩種,不同的類型使用了不同實作,關系如下:

HBase rpc架構介紹

RWQueueRpcExecutor的特點是内部可以對讀寫隔離,以及對get和scan隔離,所謂隔離的意思是,call對象會放入獨立的callQueue,并使用獨立的handler進行處理;

HBase rpc架構介紹

FastPathBalancedQueueRpcExecutor不支援隔離,其特點是對于空閑的handler,讓其自旋而不是阻塞,以減少線程上下文切換的消耗;

HBase rpc架構介紹

服務實作

服務端實作類需要實作一些接口,例如AdminService.BlockingInterface、ClientService.BlockingInterface、MasterService.BlockingInterface等;

HMaster的服務實作類主要是MasterRpcServices,HRegionServer的服務實作類主要是RSRpcServices;

service相關的類會在啟動階段進行初始化,然後在請求處理時根據connection的serviceName擷取到對應的service執行個體,再根據call對象的method和param進行方法的調用;

以HRegionServer為例,大概的service相關執行個體及調用關系如下:

HBase rpc架構介紹