如何為分布式系統優雅的更換RPC
很多小夥伴都遇到過需要為分布式系統調用更換RPC的問題,為什麽會遇到這種事呢?其實,在系統搭建初期,需求簡單,架構簡單,最重要的是請求量也少,所以很多系統都采用快速原型開發模式,對rpc的要求不高,隨便找一個順手的或者熟悉的rpc框架套進系統中即可。但是隨著業務復雜度增高,系統承載的請求量增高,可能一開始所采用的RPC框架顯現出一些致命的問題,比如大扇出問題。我們以Thrift為例。例如隨著業務復雜度的增長,我們面臨著如下的需求。
如圖所示,每一次請求,上遊服務都要獲取下遊A~Z一共26個服務的結果,然後把這26個服務的結果拼裝返回給前端服務。有人說,26個服務是不是有些誇張了,我的系統中根本沒有遇到過這個情況。這實際一點不誇張,一個業務復雜的系統經過服務拆分,最後拆成一些高內聚低耦合的獨立服務,非常容易達到這樣一個服務種類數,而且26還遠遠不是很多。那麽遇到這種問題,傳統的同步的RPC怎麽解決這個問題呢?
以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,只不過收益可能不大。
需要什麽樣的RPC?
考慮到Thrift對於大扇出並不合適,我們可能需要下面這樣工作模式的RPC。
這種反應器模型(只是簡單舉例子)可以減少請求線程數。這種RPC使用系統的Epoll進行後端服務的請求以及數據的接收,這樣無論多少請求,只使用一個線程完成,通過Epoll的機制在數據到來或者可發送的情況下通知用戶進程,只不過最後需要把接收到的數據返回給計算線程使用。這種模型其實要比Thrift那種那好一些。我自己也在業余時間實現了一個簡單的RPC框架:http://www.cnblogs.com/haolujun/p/7527313.html ,比較粗糙但是足夠小。
如何遷移到新的RPC?
把系統遷移到新的RPC上,除了改動代碼外,就是要做到兼容,系統在遷移過程中可能需要在兩套RPC框架上運行,並且必須做到平滑遷移。例如,一般的分布式系統可能會長成如下的樣子。
服務B1~B4把自己的地址寫入到ETCD中,但是由於我們一開始並未考慮到RPC的遷移,所以value對應的是服務的地址,沒有服務使用的rpc類型等等。
方案1 添加新key
對於A1~A2,B1~B4,可以先選擇一部分進行平滑過渡,例如我們選擇A1,B1~B2進行遷移。
上線步驟如下:
下線A1,B1,B2。
更新A1配置,使其從新的key:service_new_rpc中讀取後端服務列表。
更新B1,B2配置,使其在新的key:service_new_rpc中註冊自己。
啟動B1,B2。
啟動A1。
對於A2,B3,B4重復如上步驟。
通過這種方式,我們可以平滑的進行服務遷移。但是它的缺點很明顯,需要一個新的key,而且後期還需要一點點把服務挪回到舊的key上。
方案2 代碼兼容
這個方案必須更改一些解析代碼,使其能夠兼容新的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的地步了麽?
如何為分布式系統優雅的更換RPC