揭秘RPC框架-實現原理
一、背景
在傳統的垂直應用架構領域,比較流行的有LAMP(Linux+Apache+Mysql+Php)+MVC架構(SSH,SSI),通常應用代碼會統一打成一個war包,部署在Tomcat等WEB容器中,不同的應用功能之間通過本地API進行調用,基本不存在跨進程的遠程服務調用, 他們適用於小規模應用場景,即所有功能部署在同一個進程中,用於前後台邏輯的分離。很明顯,垂直應用架構有如下幾個弊端:
1、開發維護成本高,部署效率低(全量編譯和部署)
2、團隊協作效率差,部分公共功能重複開發,代碼重複高
3、系統可靠性差,單點故障頻繁
4、維護和定製困難,業務代碼不好拆分
5、新功能上線周期變長,各模塊強耦合(公共API測試工作量大,回歸時間長,新特性無法獨立部署和交付,需要和老功能一起編譯打包測試)
當垂直應用越來越多,應用之間的跨進程交互不可避免,將核心和公共服務抽取出來,作為獨立的服務,提高業務復用,RCP架構應運而生,再結合服務治理形成面向服務架構(SOA),進行服務生命周期管理,服務發現自動註冊,服務降級,流量控制等。為進一步提高服務的可用性,將服務進行原子化拆分,獨立打包部署,通過這種微服務模式,深入敏捷開發、持續交互實踐,對業務侵入性降到了最低,擴容方便運維成本也大幅降低,深受互聯網公司青睞。
二、RPC簡介
RPC(Remote Procedure Call),一種進程間通信方式,允許像調用本地過程一樣調用遠程服務,可以有不同的實現方式,如RMI,HTTPInvoker等,它具有如下幾個特點:
1、遠程服務調用簡單、透明
2、跨進程調用通用化,單機調用到遠程調用
3、屏蔽底層數據傳輸方式(TCP/UDP)、序列化方式(xml/json/二進位)與網路通信(BIO/NIO)細節,客戶端只需要介面,而服務部署在遠程。
單純的RPC框架(如FaceBook開源的Thrift)並不是完整的分散式服務框架,可以理解為:RPC框架+服務自動註冊與發現+服務治理=分散式服務框架 。當然一個分散式服務架構遠不止如此,比較常見的功能包括「服務發布訂閱+服務路由+集群容錯+服務調用模式+多協議+序列化方式+統一配置+服務監控+服務安全+故障快速定位定界+服務發現+服務治理+服務降級+服務隔離+服務降級+服務心跳/重連+流量控制+超時控制+服務生命周期管理+心跳機制+服務多版本+負載均衡」等等。
三、RPC調用過程
一次RCP調用返回涉及到客戶端與服務端的往返通信,具體如下圖所示:
客戶端通過代理類封裝請求方法和參數,將請求序列化後發出網路請求,服務端接收客戶端請求,首先進行反序列化拿到客戶端的請求對象進行相關處理,發起本地調用,將調用結果進行序列化通過網路返回發往客戶端,客戶端對響應碼流進行反序列並將結果返回給客戶端,從而實現一次RPC握手。這也是我們後面實現一個簡單RPC示常式序的基本思路。在Client Stub進行客戶端請求參數的綁定並進行網路交互,在Server Stub進行參數的解綁映射發起本地調用並對結果封裝返回。其實業界諸多的分散式通信框架也是如此,只是它的每一步都考慮了更為完整的處理機制。
四、一個簡單的例子
通過上述對RPC過程的分析,我們已經知道要實現一個RCP模型,客戶端處理器(Client Stub)和服務端處理器(Server Stub)是關鍵。下面我們通過代碼來逐一剖析,即不依賴任何第三方類庫,實現一個簡單的RPC框架。
4.1 客戶端代碼
先定義一個介面EchoService:
public interface EchoService {
String echo(String ping);
int add(int a, int b);
}
4.2 服務端代碼
public class EchoServiceImpl implements EchoService {
@Override
public String echo(String ping) {
return ping != null ? ping + "--> i am ok" : "i am ok";
}
@Override
public int add(int a, int b) {
return a+b;
}
}
4.3 客戶端處理器
實現遠程服務的本地代理,通過jdk動態代理的攔截機制,將本地調用封裝成遠程服務調用,然後將結果進行封裝返回給本地客戶端。
public class RpcImporter{
分析:採用jdk動態代碼模式封裝客戶端發起網路請求,當代理對象調用真實目標對象的方法時,其會自動跳轉到代碼對象關聯的handler對象的invoke方法進行調用,Object returnValue = method.invoke(subject,args);
4.4 服務端處理器
public class RpcExporter {
}
4.5 客戶端調用代碼
public class RpcClientTest {
public static String HOST_NAME = "localhost";
public static int PORT = 8998;
4.6 執行結果
1、先啟動服務端,顯示
begin connect client...
2、然後啟動客戶端
客戶端輸出:
服務端輸出:
五、總結
RPC架構分為三部分:
(1)服務提供者(Provider),運行在伺服器端,提供服務介面定義與服務實現類。
(2)服務發布者(RPCExporter),運行在伺服器端,負責將本地服務發布成遠程服務,管理遠程服務,提供給服務消費者使用。
(3)本地服務代理(RPCImporter),運行在客戶端,通過遠程代理對象調用遠程服務。
最後分享一個分散式服務框架典型實例架構模型


TAG:技術之積累 |