1. 程式人生 > >分散式系統基礎-遠端過程呼叫(RPC)

分散式系統基礎-遠端過程呼叫(RPC)

1、RPC簡介

RPC(Remote Procedure Call,遠端過程呼叫)是建立在Socket之上的一種多程序間的通訊機制。不同於複雜的Socket通訊方式,RPC的初心是設計一套遠端通訊的通用框架,這個框架能夠自動處理通訊協議、物件序列化、網路傳輸等複雜細節,並且希望開發者使用這個框架以後,呼叫一個遠端機器上的介面程式碼與以本地方法呼叫的程式碼“看起來沒什麼區別”,從而大大減小分散式的開發難度,使得不懂網路程式設計的程式設計師也能比較容易的開發分散式系統。

RPC最初是由Sun公司提出,即Sun RPC,後來成為IETF國際標準,至今仍然重要的NFS協議就是最早的基於RPC的一個重要案例。

為了將一個傳統的程式改寫成RPC程式,我們要在程式裡面另外加一些程式碼,這個過程叫做stub過程,我們可以想象一個傳統程式,他的一個程序被轉移到一個遠端機器中,在客戶端及服務端分別有一個stub模組實現了遠端過程呼叫所需的通訊功能,比如引數及呼叫結果的序列化功能,並通過網路完成遠端傳輸,因為Stub與原來的Server使用了同樣的介面,因此增加這些Stub程式碼既不需要更改原來的Client端的呼叫邏輯,也不需要更改服務端Server的邏輯程式碼,這個過程如下圖所示:

這裡寫圖片描述

整個RPC流程如下:

  1. 服務消費方(client)以本地呼叫方式呼叫服務。
  2. client stub接收到呼叫後負責將方法、引數等組裝成能夠進行網路傳輸的訊息體。
  3. client stub找到伺服器地址,並將訊息傳送到服務端。
  4. server stub收到訊息後進行解碼。
  5. server stub根據解碼結果呼叫本地服務。
  6. 本地服務執行並將結果返回給server stub。
  7. server stub將返回結果打包成訊息併發送至消費方。
  8. client stub接收到訊息並進行解碼。
  9. 服務消費方得到最終結果。

要實現一個完整的RPC框架,就需要如下專有技術。

  1. 高效能網路程式設計技術。
  2. 物件(資料結構)序列化和反序列化技術。
  3. 自動程式碼生成或者動態代理程式設計技術。

比如Java裡經典的RPC框架RMI,就用到了Java預設的序列化機制和動態代理程式設計技術。不過,Java裡的RMI及其他語言裡特定的RPC框架大都存在一個很明顯的缺陷,即僅限本語言的客戶端呼叫,換種語言就無法呼叫了,而開發需要支援多種語言的RPC框架,其難度至少上升一個數量級。

2、SOAP出現

20世紀90年代後期,XML成為計算機工業新的銀彈,幾乎所有定義為XML的東西都是好的。1999年底,工業界看到了SOAP的釋出。SOAP由微軟和DevelopMentor釋出,隨後交給W3C作為標準。SOAP使用XML作為RPC新的物件序列化機制,IBM則又繼續發揚光大這條路線,推出Web Service等整套方案。

SOAP嚴格意義上是屬於XML-RPC(XML Remote Procedure Call)技術的一種變種,一個XML-RPC請求訊息就是一個HTTP-POST請求訊息,其請求訊息主體基於XML格式。客戶端傳送XML-RPC請求訊息到服務端,呼叫服務端的遠端方法並在服務端上執行遠端方法。遠端方法執行完畢之後返回響應訊息給客戶端,其響應主體同樣基於XML格式。遠端方法的引數支援數字、字串、日期等,也支援陣列和其他複雜結構型別,SOAP是第一次真正成功的解決了多語言多平臺支援的開放性RPC標準。

一個SOAP請求例項(驗證使用者資訊)如下:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ser="http://service.webservice.tfs.com">
   <soapenv:Header/>
   <soapenv:Body>
      <ser:checkUser>
         <!--Optional:-->
         <ser:userKey>?</ser:userKey>
      </ser:checkUser>
   </soapenv:Body>
</soapenv:Envelope>

對應的應答報文如下:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Body>
      <ns:checkUserResponse xmlns:ns="http://service.webservice.tfs.com">
         <ns:return xsi:nil="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
      </ns:checkUserResponse>
   </soapenv:Body>
</soapenv:Envelope>

我們看到,SOAP的報文很複雜而且編碼臃腫,由於它是面向機器識別的表達格式,所以程式設計師很難直接理解他的報文,這個缺陷最終導致了SOAP的末路與HTTP REST的通訊方式的興起。

HTTP REST採用讓人容易理解的JSON格式來傳遞請求與應答引數,因而開發更為方便,但是HTTP REST已經脫離了RPC的範疇了,最明顯的特徵是:它無需客戶端stub程式碼與服務端stub程式碼,呼叫也不再是類似本地方法呼叫的方式了。

在RPC的路線演化過程中,雖然意外的產生了HTTP REST這個慢慢侵佔RPC大部分應用領地的“異類”,並且導致了一度盛行的XML-RPC的滅絕,但同時促進了正統RPC技術走向一個新的發展階段,追求更高的效能及增加對多語言多平臺的支援,成為越來越多的開源RPC框架的目標,典型的代表為Thrift、Apache Avro等新生的開源框架,這些框架在大多數系統、大型分散式系統及移動網際網路應用方面被越來越多的公司使用。

3、Zero Ice

提到RPC,不得不說的就是Zero Ice,作為RPC領域的絕對王者,ICE發展至今已經成為一個很強大的微服務架構平臺,很適合作為大型分散式系統、電商系統、電信金融等關鍵系統的基礎架構,其優勢主要有。

  1. 在RPC通訊這個核心領域裡,效能第一、穩定性第一。
  2. 多語言多平臺支援,其服務端可以用包括Java、C++、C#、Objective-C、Python等主流語言協同開發,而客戶端支援7中主流語言協同開發(除服務端的5中,還支援JavaScript、PHP)。
  3. ICE已經成為目前業界最成熟、穩定、拓展性好、功能完備的企業級微服務架構平臺,國內外很多大型專案都採用了基於ICE的微服務架構。

4、從RPC到服務治理框架

與一般的HTTP REST框架不同,一個可用的RPC框架不僅解決了遠端呼叫的問題,也提供了用於服務註冊和服務發現的基礎設施,比如RMI裡的RMI Registry,如下圖所示:

這裡寫圖片描述

使用RMI時,我們所開發的“遠端物件(Remote Object)”要註冊(Binding)到Registry裡,而客戶端(Client)則首先需要通過Registry的介面查詢到遠端物件的訪問地址,然後才能發起對遠端物件的“遠端過程呼叫”。這種模式表達為更抽象的模型,就是如下圖所示的服務註冊和服務發現的通用模型。

這裡寫圖片描述

服務註冊和服務發現的模型在後來的Web Service時代被提到一個很高的境界,Web Service的核心架構一般如下圖所示。

這裡寫圖片描述

在Web Service的技術架構中,用XML定義的程式語言中立的介面描述語言WSDL其實來自COBRA中的IDL,基於Socket的複雜RPC呼叫被簡單和容易掌握的HTTP上的SOAP呼叫所替換。此外,為了防止不同開發商的“互聯互不通”及“以自我為中心”的小農思想,IBM倡導了全球服務註冊中心UDDI Registry的理念,希望各個廠商都能將自己的Web Service註冊到一起,全球互聯,服務無國界,但是這次偉大的嘗試最終以失敗而告終,無數公司不得不重複開發並不是很複雜的軟體系統。

後來出現了SOA這個心概念,雖談業界對SOA這個概念有各種詮釋,但是“面向服務的架構”即以服務為中心的分散式架構深入人心,如下圖所示是一個理想化的大一統的SOA架構藍圖,我們看到服務註冊與服務釋出模型及RPC技術依然是SOA的技術核心。

這裡寫圖片描述

服務註冊和服務釋出模型成為後來通用分散式系統架構的核心和關鍵技術基礎,也被賦予了一個時髦的新概念–“服務治理框架”,最早的說法可能出自國內BAT的一些架構師。服務治理框架這個概念與SOA在本質上屬於同一類,它的一個典型代表是曾經熱門的開源專案–Dubbo。下面給出了Dubbo的原理概念圖,我們可以看出,相對於SOA架構,Dubbo的服務治理框架中最主要的一個亮點是增加了“服務監控”這個必要的運維特性。

這裡寫圖片描述

Dubbo同時提出了很多看起來比較吸引人的新特性,比如服務編排、服務降級、訪問規則控制,但實際上這並不是核心,作為一個分散式系統的重要基礎設施,穩定、高效能的RPC通訊及多語言的支援才是關鍵的核心指標。

5、從單體應用到微服務

我們所說的單體應用指的是服務和應用都執行在同一個Tomcat(其他Web應用伺服器)的應用。單體應用的好處如下:

  1. 通常只建立一個Project即可
  2. 當系統比較小時,開發、部署、測試等工作都更加簡單快捷
  3. 容易實現專案上線目標

但是當隨著系統的快速迭代,就會產生一些難以調和的矛盾與先天缺陷。

  1. 過高耦合的風險:服務越來越多,不停的變化,由於都在一個程序中,所以一個服務的失敗或移除,將導致整個系統無法啟動或正常執行的風險越來越大。
  2. 新語言與新技術的引入阻力:單體應用通常只使用一種語言開發,並且完全使用一種特定的框架,執行在一個程序內,從而導新語言和新技術很難被引進。在網際網路應用時代,多語言協作開發是主流,特別是對於複雜的大系統、大平臺,而各種新技術層出不窮,拒絕新技術就意味著技術上的落後,從而可能會逐步被市場所淘汰。
  3. 水平拓展的問題:單體應用從一開始就沒有考慮分散式的問題,或者即使考慮了但仍然開發稱為單體應用,所以遇到單機效能問題,通常難以水平拓展,往往需要推到重來,代價比較大。
  4. 難以可持續發展:隨著業務範圍的快速拓展,單體應用通常難以複用原有的服務,一個新業務上線,通常需要重新開發新服務、新介面。

而微服務架構的出現,恰恰就是為了彌補“單體應用”所帶來的各種問題及先天缺陷。在這種新的微服務架構下,整個系統被分解為獨立的幾個服務,每個微服務可以獨立部署在多個機器上,前端可以通過負載均衡器來訪問微服務,微服務之間也可以通過同樣的介面進行遠端通訊。

一般而言,如果一個分散式系統具備如下特點,則我們可以稱之為“微服務架構”;

  1. 任何一個服務都由多個獨立的程序提供服務,這些程序可以分佈在多臺物理機上,任何程序宕機,都不會影響系統提供服務。
  2. 整個系統是由多個微服務有機組成的一個分散式系統,微服務架構從某種意義上來說可以看做服務治理框架的進一步延伸。

這裡寫圖片描述

微服務架構背後的思想和頂層設計無疑是一個巨大的進步。 我們說了這麼多年面向服務設計與建模的夢想,終於在分散式時代裡被第一次真正重視和徹底實現,而這一切都源自全新的微服務架構。

總結下來,當前主流的微服務架構可以分為以下幾類。

  1. 基於傳統的高效能RPC技術和服務治理能力的微服務架構,這個領域的王者為ZeroC IceGrid。
  2. 以HTTP REST為通訊機制的通用性微服務架構,最典型的為Spring Cloud。
  3. 基於容器的技術,目標是部署在公有云平臺上的微服務架構基礎平臺,這種微服務架構平臺沒有提供特定的RPC通訊機制,只保證TCP通訊的可達性,所以理論上任何分散式應用都可以執行在微服務架構平臺上,言外之意就是要選擇合適的通訊協議,比如REST、Thrift或者自定義的某種TCP通訊協議。這個領域的王者為Google的Kubernetes。

參考:架構揭祕從分散式到微服務