不少小夥伴都遇到過須要爲分佈式系統調用更換RPC的問題,爲何會遇到這種事呢?其實,在系統搭建初期,需求簡單,架構簡單,最重要的是請求量也少,因此不少系統都採用快速原型開發模式,對rpc的要求不高,隨便找一個順手的或者熟悉的rpc框架套進系統中便可。可是隨着業務複雜度增高,系統承載的請求量增高,可能一開始所採用的RPC框架顯現出一些致命的問題,好比大扇出問題。咱們以Thrift爲例。例如隨着業務複雜度的增加,咱們面臨着以下的需求。
如圖所示,每一次請求,上游服務都要獲取下游A~Z一共26個服務的結果,而後把這26個服務的結果拼裝返回給前端服務。有人說,26個服務是否是有些誇張了,個人系統中根本沒有遇到過這個狀況。這實際一點不誇張,一個業務複雜的系統通過服務拆分,最後拆成一些高內聚低耦合的獨立服務,很是容易達到這樣一個服務種類數,並且26還遠遠不是不少。那麼遇到這種問題,傳統的同步的RPC怎麼解決這個問題呢?html
以Thrift爲例,若是須要訪問26個服務,爲了保證請求處理速度,必需要並行訪問各個下游服務(不能串行請求,由於這將致使 一次請求的響應時間至少爲timeA + timeB + ...... + timeZ),那麼咱們只能經過多線程進行併發。前端
經過多線程併發請求,咱們基本可以達處處理一次請求至多須要 max(timeA, timeB, ......, timeZ),可是實際上要比這個稍多。看樣子咱們必須弄一個請求線程池,但是這個池子要多大呢?假如如今前端請求速率爲 P,那麼爲了保證每一個請求處理時間都儘量快,咱們須要一個大小爲 26 * P的線程池。雖然,初看起來可能還能夠應付,畢竟請求線程在發送網絡請求後,會阻塞在IO,它會放棄CPU,從而使得計算線程得到CPU,不會浪費多少CPU的資源,可是當P太大就很差了。好比P爲100或者1000,這個時候線程數過多可能就會形成CPU調度開銷增大,由於它會增長CPU的線程切換負擔。後端
因此,咱們更換RPC,當且僅當,當前的RPC已經形成了系統負擔,對於業務量不大的系統,RPC的更換並無必要,可是爲了技術提高你也能夠更換RPC,只不過收益可能不大。網絡
考慮到Thrift對於大扇出並不合適,咱們可能須要下面這樣工做模式的RPC。
這種反應器模型(只是簡單舉例子)能夠減小請求線程數。這種RPC使用系統的Epoll進行後端服務的請求以及數據的接收,這樣不管多少請求,只使用一個線程完成,經過Epoll的機制在數據到來或者可發送的狀況下通知用戶進程,只不過最後須要把接收到的數據返回給計算線程使用。這種模型其實要比Thrift那種那好一些。我本身也在業餘時間實現了一個簡單的RPC框架:http://www.cnblogs.com/haolujun/p/7527313.html ,比較粗糙可是足夠小。
還有有不少開源的RPC框架,fbthrift,GRPC均可以應對大扇出,找到適合你的系統,而且改動量和後期維護成本最低的那個。多線程
把系統遷移到新的RPC上,除了改動代碼外,就是要作到兼容,系統在遷移過程當中可能須要在兩套RPC框架上運行,而且必須作到平滑遷移。例如,通常的分佈式系統可能會長成以下的樣子。
服務B1~B4把本身的地址寫入到ETCD中,可是因爲咱們一開始並未考慮到RPC的遷移,因此value對應的是服務的地址,沒有服務使用的rpc類型等等。架構
對於A1~A2,B1~B4,能夠先選擇一部分進行平滑過渡,例如咱們選擇A1,B1~B2進行遷移。
上線步驟以下:併發
下線A1,B1,B2。框架
更新A1配置,使其重新的key:service_new_rpc中讀取後端服務列表。分佈式
更新B1,B2配置,使其在新的key:service_new_rpc中註冊本身。ide
啓動B1,B2。
啓動A1。
對於A2,B3,B4重複如上步驟。
經過這種方式,咱們能夠平滑的進行服務遷移。可是它的缺點很明顯,須要一個新的key,並且後期還須要一點點把服務挪回到舊的key上。
這個方案必須更改一些解析代碼,使其可以兼容新的ETCD中value的格式,以下圖。
首先改造A代碼,使其可以兼容新地址解析格式。新地址格式在每一個地址後加上RPC類型標識:T(Thrift),G(GRPC),新格式和舊格式的兼容很容易,只需在解析的時候找一下分割符,並判斷分隔符最後一部分是T是G仍是什麼都沒有,沒有就默認爲T。
改造A代碼,使其可以根據後端服務在ETCD中的RPC類型使用不一樣的RPC框架調用後端。
改造B1~B4的配置,在ETCD中註冊本身的時候把RPC類型順便加上。
改造B1~B2,使用新RPC做爲服務端,而且在註冊的時候把RPC類型設置爲G。
改造B3~B4,使用新RPC做爲服務端,而且在註冊的時候把RPC類型設置爲G。
經過這個步驟,咱們就能作到RPC的平滑遷移。這個方式的缺點也有:須要同時維護兩套RPC框架,直到其中一種RPC完全下線。可是優勢也有,沒有增長新key。
更換RPC並不像想象中的那樣困難,只要理清先後邏輯,一點點的遷移,最終你的服務會所有搞定。最重要的問題是你的系統真的達到了非得換RPC的地步了麼?