微服務7:通信之RPC
★微服務系列
1 什麼是RPC通信
2 RPC通信詳解
2.1 RCP角色和職能

2.2 RPC調用流程
RPC(Remote Procedure Call)遠程過程調用,即一個節點通過網絡調用的方式來請求另一個節點提供的服務的過程,也可以簡單的理解為client訪問server上提供的函數。
他的基本調用流程如下:
- 客戶端(client)以本地調用方式(即以接口的方式)調用服務;
- 客戶端存根(client stub)接收到調用後,負責將方法、參數等組裝成能夠進行網絡傳輸的消息體(將消息體對象序列化為二進制 byte[]);
- 客戶端通過sockets將消息發送到服務端;
- 服務端存根( server stub)收到消息後進行解碼(將消息對象反序列化);
- 服務端存根( server stub)根據解碼結果調用本地的服務;
- 本地服務執行並將結果返回給服務端存根( server stub);
- 服務端存根( server stub)將返回結果打包成消息(將結果消息對象序列化);
- 服務端(server)通過sockets將消息發送到客戶端;
- 客戶端存根(client stub)接收到結果消息,並進行解碼(將結果消息反序列化);
- 客戶端(client)得到最終結果。
2.3 多
內容項 | RPC調用 | 本地調用 |
函數尋址 | IP端口路由(NamingService + LoadBalancer)+函數路由 | 內存指針 |
傳遞數據 | 序列化後的數據流 | 內存對象 |
調用方異常處理 | timeout、retry、curcuit breaker | 拋出Exception / 函數返回固定異常標識的數據 |
被調用方異常處理 | 認證鑒權、過載保護 | 入參檢查 / 執行異常捕獲和處理 |
問題定位 | 分佈式Trace、監控、日誌中心 | 日誌記錄 / 斷點調試跟蹤 |
性能優化 | 連接池、多路復用、線程池、輕量級線程、non-block IO 等 | 編譯器優化(inline等) |
這裡可以看出rpc比函數調用複雜的多,比如:
- 函數尋址:你怎樣調到你想要的哪個函數?在本地調用中其實就是一個函數指針,但是在RPC場景下,你要找到這個函數其實非常複雜,一個服務一般有多個下游實例,首先要選擇一個下游實例,一般這個是由NamingService+LB來實現,到達對應的實例後,服務端還要解析請求體,找到函數名,然後做函數路由。
- 數據傳遞:在本地調用過程中其實就是傳遞一個指針或者值,在RPC場景下其實是通過網絡傳遞的,網絡上需要傳遞一個內存對象序列化之後的一個二進制網絡數據流,response回來的時候也需要經過一個反序列化的過程。
- 異常處理:本地調用的情況下,無非就是判斷下這個函數的返回值或者有沒有拋一些異常,但是在RPC場景下就很複雜,比如網絡擁塞了,服務端處理慢了或者超時,還有很多異常的情況,所以我們要做很多系統容錯的事情,比如:超時、重試等策略來解決這些問題。本地調用的時候我只需要檢查參數是否合法,但是在RPC的場景下我們要做一些類似認證鑒權,過載保護等策略,避免流量過大將server打掛。
- 問題定位:本地調用方法很多,比如:斷點調試,打本地日誌。但是在RPC場景下,這些方法其實是行不通的,我們需要分佈式tracing、監控和分佈式日誌中心來幫助我們定位問題。
- 性能優化:本地調用其實我們不用關心太多,因為編譯器會幫我們做一些列的優化,但是在RPC的場景下,就需要我們自己優化通信效率,常用的優化手段比如:連接池、多路復用、線程池等等很多方法,這些方法實現起來都非常的複雜。現在大家應該能理解RPC場景是非常複雜的
正因為有如此的複雜性,所以我們需要一個RPC框架來處理這些複雜的事情,讓RPC看起來就像本地調用一樣簡單。
RPC 框架調用流分析
2.6.1 RPC框架功能(簡單版本)
實現的過程:
- client初始化一個channel,監聽NamingService,從服務名字中解析出來服務真正的上游實例地址
- 客戶端將請求的的數據進行序列化
- 上游可能多個實例,需要LB去選擇一個下游的IP+Port,選出來之後需要和上游實例建立連接和發送請求
- 建立連接之後發送請求
- 服務端接着接受連接和接受數據,收到數據之後將二進制數據反序列化為一個內存對象request
- 然後再調用server的響應方法進行處理
- 服務端通過sockets將消息發送到客戶端;
- 客戶端接收到結果消息,並進行解碼(將結果消息反序列化)
2.6.2 RPC框架功能(複雜版本)
有些RPC框架不只是處理通信相關的工作(如數據的序列化和反序列化,協議的解析/打包,數據的壓縮解壓縮,數據的加密和解密),還可以做很多微服務治理的工作。
比如Dubbo支持對服務的治理,包括 服務註冊與發現、故障注入、超時重試、負載均衡、連接管理和健康檢查等。除此之外,服務端還有認證鑒權、並發流量限制、函數路由、協議適配和參數校驗等等複雜的策略。
所以一個成熟的RPC框架也可以是一個非常複雜全面的分佈式系統,在一定程度上協助工程進行微服務建設。
對比項 | Dubbo | gRPC | brpc | Thrift |
公司 | Ali | Baidu | ||
通訊協議 | tcp/http | http2 | 多種協議 | tcp/http |
序列化協議 | 可擴展 | protobuf | protobuf/json/mcpack | 可擴展 |
開發語言 | Java | 跨語言 | C++ / Java | 跨語言 |
主要特點 | 服務治理、擴展性 | 跨語言、性能 | 高性能、擴展性 | 跨語言 |
github star |
36.9K | 33.5K | 12.9K | 8.9K |
2.8 與RESTful API 的區別
RPC 主要用於公司內部的服務調用,性能消耗低,傳輸效率高,實現複雜。
HTTP 主要用於對外的異構環境,瀏覽器接口調用,App 接口調用,第三方接口調用等。
RPC 使用場景(大型的網站,內部子系統較多、接口非常多的情況下適合使用 RPC):
- 長鏈接。不必每次通信都要像 HTTP 一樣去 3 次握手,減少了網絡開銷。
- 註冊發佈機制。RPC 框架一般都有註冊中心,有豐富的監控管理;發佈、下線接口、動態擴展等,對調用方來說是無感知、統一化的操作。
- 安全性,沒有暴露資源操作。
- 微服務支持。就是最近流行的服務化架構、服務化治理,RPC 框架是一個強力的支撐。
3 總結
通過本篇我們詳細學習了RPC的概念和原理,以及它能夠提供的能力。也對目前業內主流的RPC的框架有了一定的了解。後面一篇我們以Dobbo為例子,來學習下怎麼使用RPC框架來進行服務之間的通信。