W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗值獎勵
RPC-client的部分又分為:
(1)序列化反序列化的部分(上圖中的1、4)
(2)發(fā)送字節(jié)流與接收字節(jié)流的部分(上圖中的2、3)
前一篇文章討論了序列化與范序列化的細節(jié),這一篇文章將討論發(fā)送字節(jié)流與接收字節(jié)流的部分。
客戶端調(diào)用又分為同步調(diào)用與異步調(diào)用
同步調(diào)用的代碼片段為:
Result = Add(Obj1, Obj2);// 得到Result之前處于阻塞狀態(tài)
異步調(diào)用的代碼片段為:
Add(Obj1, Obj2, callback);// 調(diào)用后直接返回,不等結(jié)果
處理結(jié)果通過回調(diào)得到:
callback(Result){// 得到處理結(jié)果后會調(diào)用這個回調(diào)函數(shù)
…上圖中的左邊大框,就代表了調(diào)用方的一個工作線程。
左邊粉色中框,代表了RPC-client組件。
右邊橙色框,代表了RPC-server。
藍色兩個小框,代表了同步RPC-client兩個核心組件,序列化組件與連接池組件。
白色的流程小框,以及箭頭序號1-10,代表整個工作線程的串行執(zhí)行步驟:
1)業(yè)務(wù)代碼發(fā)起RPC調(diào)用,Result=Add(Obj1,Obj2)
2)序列化組件,將對象調(diào)用序列化成二進制字節(jié)流,可理解為一個待發(fā)送的包packet1
3)通過連接池組件拿到一個可用的連接connection
4)通過連接connection將包packet1發(fā)送給RPC-server
5)發(fā)送包在網(wǎng)絡(luò)傳輸,發(fā)給RPC-server
6)響應(yīng)包在網(wǎng)絡(luò)傳輸,發(fā)回給RPC-client
7)通過連接connection從RPC-server收取響應(yīng)包packet2
8)通過連接池組件,將conneciont放回連接池
9)序列化組件,將packet2范序列化為Result對象返回給調(diào)用方
10)業(yè)務(wù)代碼獲取Result結(jié)果,工作線程繼續(xù)往下走
RPC框架需要支持負載均衡、故障轉(zhuǎn)移、發(fā)送超時,這些特性都是通過連接池組件去實現(xiàn)的。
連接池組件
【INIT】
和下游RPC-server(一般是一個集群),建立N個tcp長連接,即所謂的連接“池”
【getConnection】
從連接“池”中拿一個連接,加鎖(置一個標志位),返回給調(diào)用方
【putConnection】
將一個分配出去的連接放回連接“池”中,解鎖(也是置一個標志位)
如何實現(xiàn)負載均衡?
回答:連接池中建立了與一個RPC-server集群的連接,連接池在返回連接的時候,需要具備隨機性。
如何實現(xiàn)故障轉(zhuǎn)移?
回答:連接池中建立了與一個RPC-server集群的連接,當連接池發(fā)現(xiàn)某一個機器的連接異常后,需要將這個機器的連接排除掉,返回正常的連接,在機器恢復后,再將連接加回來。
如何實現(xiàn)發(fā)送超時?
回答:因為是同步阻塞調(diào)用,拿到一個連接后,使用帶超時的send/recv即可實現(xiàn)帶超時的發(fā)送和接收。
上圖中左邊的框框,是少量工作線程(少數(shù)幾個就行了)進行調(diào)用與回調(diào)。
中間粉色的框框,代表了RPC-client組件。
右邊橙色框,代表了RPC-server。
藍色六個小框,代表了異步RPC-client六個核心組件:上下文管理器,超時管理器,序列化組件,下游收發(fā)隊列,下游收發(fā)線程,連接池組件。
白色的流程小框,以及箭頭序號1-17,代表整個工作線程的串行執(zhí)行步驟:
1)業(yè)務(wù)代碼發(fā)起異步RPC調(diào)用,Add(Obj1,Obj2, callback)
2)上下文管理器,將請求,回調(diào),上下文存儲起來
3)序列化組件,將對象調(diào)用序列化成二進制字節(jié)流,可理解為一個待發(fā)送的包packet1
4)下游收發(fā)隊列,將報文放入“待發(fā)送隊列”,此時調(diào)用返回,不會阻塞工作線程
5)下游收發(fā)線程,將報文從“待發(fā)送隊列”中取出,通過連接池組件拿到一個可用的連接connection
6)通過連接connection將包packet1發(fā)送給RPC-server
7)發(fā)送包在網(wǎng)絡(luò)傳輸,發(fā)給RPC-server
8)響應(yīng)包在網(wǎng)絡(luò)傳輸,發(fā)回給RPC-client
9)通過連接connection從RPC-server收取響應(yīng)包packet2
10)下游收發(fā)線程,將報文放入“已接受隊列”,通過連接池組件,將conneciont放回連接池
11)下游收發(fā)隊列里,報文被取出,此時回調(diào)將要開始,不會阻塞工作線程
12)序列化組件,將packet2范序列化為Result對象
13)上下文管理器,將結(jié)果,回調(diào),上下文取出
14)通過callback回調(diào)業(yè)務(wù)代碼,返回Result結(jié)果,工作線程繼續(xù)往下走
如果請求長時間不返回,處理流程是:
15)上下文管理器,請求長時間沒有返回
16)超時管理器拿到超時的上下文
17)通過timeout_cb回調(diào)業(yè)務(wù)代碼,工作線程繼續(xù)往下走
上下文管理器
為什么需要上下文管理器?
回答:由于請求包的發(fā)送,響應(yīng)包的回調(diào)都是異步的,甚至不在同一個工作線程中完成,需要一個組件來記錄一個請求的上下文,把請求-響應(yīng)-回調(diào)等一些信息匹配起來。
如何將請求-響應(yīng)-回調(diào)這些信息匹配起來?
這是一個很有意思的問題,通過一條連接往下游服務(wù)發(fā)送了a,b,c三個請求包,異步的收到了x,y,z三個響應(yīng)包:
(1)怎么知道哪個請求包與哪個響應(yīng)包對應(yīng)?
(2)怎么知道哪個響應(yīng)包與哪個回調(diào)函數(shù)對應(yīng)?
回答:這是通過【請求id】來實現(xiàn)請求-響應(yīng)-回調(diào)的串聯(lián)的。
整個處理流程如上,通過請求id,上下文管理器來對應(yīng)請求-響應(yīng)-callback之間的映射關(guān)系:
1)生成請求id
2)生成請求上下文context,上下文中包含發(fā)送時間time,回調(diào)函數(shù)callback等信息
3)上下文管理器記錄req-id與上下文context的映射關(guān)系,
4)將req-id打在請求包里發(fā)給RPC-server
5)RPC-server將req-id打在響應(yīng)包里返回
6)由響應(yīng)包中的req-id,通過上下文管理器找到原來的上下文context
7)從上下文context中拿到回調(diào)函數(shù)callback
8)callback將Result帶回,推動業(yè)務(wù)的進一步執(zhí)行
如何實現(xiàn)負載均衡,故障轉(zhuǎn)移?
回答:與同步的連接池思路相同。不同在于,同步連接池使用阻塞方式收發(fā),需要與一個服務(wù)的一個ip建立多條連接,異步收發(fā),一個服務(wù)的一個ip只需要建立少量的連接(例如,一條tcp連接)。
如何實現(xiàn)超時發(fā)送與接收?
回答:同步阻塞發(fā)送,可以直接使用帶超時的send/recv來實現(xiàn),異步非阻塞的nio的網(wǎng)絡(luò)報文收發(fā),如何實現(xiàn)超時接收呢?(由于連接不會一直等待回包,那如何知曉超時呢?)這時,超時管理器就上場啦。
超時管理器,用于實現(xiàn)請求回包超時回調(diào)處理。
每一個請求發(fā)送給下游RPC-server,會在上下文管理器中保存req-id與上下文的信息,上下文中保存了請求很多相關(guān)信息,例如req-id,回包回調(diào),超時回調(diào),發(fā)送時間等。
超時管理器啟動timer對上下文管理器中的context進行掃描,看上下文中請求發(fā)送時間是否過長,如果過長,就不再等待回包,直接超時回調(diào),推動業(yè)務(wù)流程繼續(xù)往下走,并將上下文刪除掉。
如果超時回調(diào)執(zhí)行后,正常的回包又到達,通過req-id在上下文管理器里找不到上下文,就直接將請求丟棄(因為已經(jīng)超時處理過了)。
however,異步回調(diào)和同步回調(diào)相比,除了序列化組件和連接池組件,會多出上下文管理器,超時管理器,下游收發(fā)隊列,下游收發(fā)線程等組件,并且對調(diào)用方的調(diào)用習慣有影響(同步->回調(diào))。異步回調(diào)能提高系統(tǒng)整體的吞吐量,具體使用哪種方式實現(xiàn)RPC-client,可以結(jié)合業(yè)務(wù)場景來選?。▽r延敏感的可以選用同步,對吞吐量敏感的可以選用異步)。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: