Web服務實現方案對比: RPC、SOAP、gRPC、REST


知乎: 淺談 RPC 和 REST: SOAP, gRPC, REST

三種主流的Web服務實現方案(REST+SOAP+XML-RPC)簡述及比較

StackOverflow: XML-RPC vs REST

目前知道的三種主流的Web服務實現方案為:

  • REST:表象化狀態轉變 (軟件架構風格)
  • SOAP:簡單對象訪問協議
  • XML-RPC:遠程過程調用協議

1. RPC

XML-RPC:一個遠程過程調用(remote procedure call,RPC) 的分布式計算協議,通過XML將調用函數封裝,並使用HTTP協議作為傳送機制。后來在新的功能不斷被引入下,這個標准慢慢演變成為今日的SOAP協定。XML-RPC協定是已登記的專利項目。XML-RPC透過向裝置了這個協定的服務器發出HTTP請求。發出請求的用戶端一般都是需要向遠端系統要求呼叫的軟件。

RPC的目的,是讓用戶在本地調用遠程的方法。對用戶來說這個調用是透明的,並不需要關心這個調用的方法是部署哪里。

1.1. 通訊原理

怎么實現遠程調用像本地調用一樣呢?RPC 模式分為三層,RPCRuntime 負責最底層的網絡傳輸,Stub 處理客戶端和服務端約定好的語法、語義的封裝和解封裝,這些調用遠程的細節都被這兩層搞定了,用戶和服務器這層就只要負責處理業務邏輯,調用本地 Stub 就可以調用遠程。

  1. 遠程服務之間建立通訊協議
  2. 尋址:服務器(如主機或IP地址)以及特定的端口,方法的名稱名稱是什么
  3. 通過序列化和反序列化進行數據傳遞
  4. 將傳遞過來的數據通過java反射原理定位接口方法和參數
  5. 暴露服務:用map將尋址的信息暴露給遠方服務(提供一個endpoint URI或者一個前端展示頁面)
  6. 多線程並發請求業務

1.2. 設計模式:ServerProxy

使用代理模式解決,生成一個代理對象,而這個代理對象的內部,就是通過httpClient來實現RPC遠程過程調用的。以此方式來屏蔽對http的操作,而外觀上看上去就像是本地功能調用類似。

1.3. 多種實現方案

RPC是一種模式,http也是RPC實現的一種方式。

論復雜度,dubbo/hessian用起來是超級簡單的。

  1. 調用簡單,真正提供了類似於調用本地方法一樣調用接口的功能 。
  2. 參數返回值簡單明了 參數和返回值都是直接定義在jar包里的,不需要二次解析。
  3. 輕量,沒有多余的信息。
  4. 便於管理,基於dubbo的注冊中心。

所以,常常有人抱怨,XML-RPC的效率太低,XML書寫或轉換都太復雜,性能不行。但實際上,單就性能而論,有JSON-RPC,它比XML-RPC輕。且RPC可以直接使用socket通訊而不是http,性能反而更優。

2. SOAP(不推薦)

1998 年 XML 1.0 發布,被 W3C (World Wide Web Consortium) 推薦為標准的描述語言。同年,SOAP 也完成了初版設計。SOAP (Simple Object Access Protocol) 簡單對象訪問協議,在 1998 年因為微軟 XML-RPC 的原因,還沒有公之於眾,一直到 2003 年 6 月的 SOAP 1.2 版本發布,才被 W3C 推薦。

SOAP 是基於文本 XML 的 一種應用協議。隨着當年 SOA (Service Oriented Architecture) 的走紅,提倡將一個大的軟件拆分成多個不同的小的服務,SOAP 在服務之間的遠程調用大有用武之地。

2.1. 協議約定

SOAP 的協議約定用的是 WSDL (Web Service Description Language) ,這是一種 Web 服務描述語言,在服務的客戶端和服務端開發者不用面對面交流,只要用的是 WSDL 定義的格式,客戶端知道了 WSDL 文件,就知道怎么去封裝請求,調用服務。

<wsdl:types>
 <xsd:schema targetNamespace="http://www.task.io/management">
  <xsd:complexType name="task">
   <xsd:element name="name" type="xsd:string"></xsd:element>
  <xsd:element name="type" type="xsd:string"></xsd:element>
   <xsd:element name="priority" type="xsd:int"></xsd:element>
  </xsd:complexType>
 </xsd:schema>
</wsdl:types>

這只是一個對象類型的定義,一套完整的 WSDL 還會有消息結構體的定義,然后將信息綁定到 SOAP 請求的 body 里,然后編寫成 service,具體這里就不展開了。

WSDL 有可以自動生成 Stub 的工具,客戶端可以直接通過自動生成的 Stub 去調用服務端。

2.2. 傳輸協議

SOAP 是用 HTTP 進行傳輸的,有個信封的概念,信息就像是一封信,有 Header 和 Body,SOAP 的請求和回復都放在信封里,進行傳遞。

POST /addTask HTTP/1.1
Host: www.task.io
Content-Type: application/soap+xml; charset=utf-8
Content-Length: nnn

<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2001/12/soap-envelope"
soap:encodingStyle="http://www.w3.org/2001/12/soap-encoding">
    <soap:Header>
        <m:Trans xmlns:m="http://www.w3schools.com/transaction/"
          soap:mustUnderstand="1">1234
        </m:Trans>
    </soap:Header>
    <soap:Body xmlns:m="http://www.task.io/management">
        <m:addTask>
            <task>
                <name>Write a blog article</name>
                <type>Writing</type>
                <priority>1</priority>
            </task>
        </m:addTask>
    </soap:Body>
</soap:Envelope>

2.3. 服務發現

SOAP 的服務發現用的是 UDDI(Universal Description, Discovery, Integration) 統一描述發現集成,相當於一個注冊中心,服務提供方將 WSDL 文件發布到注冊中心,使用方可以到這個注冊中心查找。


SOAP 在當時也是風靡一時,主要有這些優點:

  1. 協議約定面向對象,更貼合業務邏輯的應用場景。
  2. 服務定義清楚,在 WSDL 能清楚了解到所有服務。
  3. 格式不用完全一致,比如上面那個請求里 name, type, priority 的順序不用完全跟服務端的 WSDL 對應。版本更新上,客戶端可以先增加新的項,服務端可以之后再更新。
  4. 使用 WS Security 所為安全標准,安全性較高。
  5. SOAP 是 面向動作 的,支持比較復雜的動作,比如 ADDMINUS

當然,現在新的軟件開發,用到 SOAP 的越來越少了,可見 SOAP 也有很多不足:

  1. 遠程調用速度慢,效率低。

    因為以 XML 作為數據格式,除了主要傳輸的數據之外,有較多冗余用在定義格式上,占用帶寬,並且對於 XML 的序列化和解析的速度也比較慢。

  2. 協議約定 WSDL 比較復雜,要經過好幾個環節才能搞定。

  3. SOAP 多數用的是POST,通常是 POST 加上動作,比如 POST CreateTask, POST DeleteTask。而多數用 POST 的原因是 GET 請求最大長度限制較多,而 SOAP 需要把數據加上 SOAP 標准化的格式,請求數據比較大,超過 GET 的限制。

  4. SOAP 的業務狀態大多是維護在服務端的,比如說分頁,服務端會記住用戶在哪個頁面上,在企業軟件中,客戶端和服務端比較平衡的情況下是沒有問題的,但是在失衡情況下,比如說客戶端請求大大超過服務端時,服務端維護所有狀態的成本太高,影響並發量。

可以說,SOAP是基於 XML-RPC 進行的二次封裝。所以,XML-RPC 的缺點全部被SOAP繼承了(且無法修改),反而,本意的優勢(簡化服務端開發所做的封裝),隨着技術的更新,越來越被新的技術替代掉了。

3. gRPC

像 SOAP 這類基於文本類的 RPC 框架,速度上都是有先天不足的。為了有比較好的性能,還是得用二進制的方式進行遠程調用。gRPC 是現在最流行的二進制 RPC 框架之一。2015 年由 Google 開源,在發布后迅速得到廣泛關注。

3.1. 協議約定

gRPC 的協議是 Protocol Buffers,是一種壓縮率極高的序列化協議,效率甩 XML,JSON 好幾條街。Google 在 2008 年開源了 Protocol Buffers,支持多種編程語言,所以 gRPC 支持客戶端與服務端可以用不同語言實現。

3.2. 傳輸協議

在 JAVA 技術棧中,gRPC 的數據傳輸用的是 Netty Channel(注意不是http), Netty 是一個高效的基於異步 IO 的網絡傳輸架構。Netty Channel 中,每個 gRPC 請求封裝成 HTTP 2.0 的 Stream。

基於 HTTP 2.0 是 gRPC 一個很大的優勢,可以定義四種不同的服務方法:單向 RPC,客戶端流式 RPC,服務端流式 RPC,雙向流式 RPC。

3.3. 服務發現

gRPC 本身沒有提供服務發現的機制,需要通過其他組件。一個比較高性能的服務發現和負載均衡器是 Envoy,可以靈活配置轉發規則,有興趣的可以去了解下。

4. RESTful

gRPC 更多的是用在微服務集群內部,服務與服務之間的通信,服務與客戶端之間的通信,REST 可以說是現在的主流。

REST:表征狀態轉移(Representational State Transfer),采用Web服務使用標准的 HTTP 方法 (GET/PUT/POST/DELETE) 將所有 Web 系統的服務抽象為資源,REST從資源的角度來觀察整個網絡,分布在各處的資源由URI確定,而客戶端的應用通過URI來獲取資源的表征。

Http協議所抽象的get,post,put,delete就好比數據庫中最基本的增刪改查,而互聯網上的各種資源就好比數據庫中的記錄(可能這么比喻不是很好),對於各種資源的操作最后總是能抽象成為這四種基本操作,在定義了定位資源的規則以后,對於資源的操作通過標准的Http協議就可以實現,開發者也會受益於這種輕量級的協議。

REST是一種軟件架構風格而非協議也非規范,是一種針對網絡應用的開發方式,可以降低開發的復雜性,提高系統的可伸縮性。

4.1. 常見的設計錯誤

4.1.1. 最常見的一種設計錯誤,就是URI包含動詞

因為"資源"表示一種實體,所以應該是名詞,URI不應該有動詞,動詞應該放在HTTP協議中。

最常見的一種設計錯誤,就是URI包含動詞。因為"資源"表示一種實體,所以應該是名詞,URI不應該有動詞,動詞應該放在HTTP協議中。

舉例來說,某個URI是/posts/show/1,其中show是動詞,這個URI就設計錯了,正確的寫法應該是/posts/1,然后用GET方法表示show。

如果某些動作是HTTP動詞表示不了的,你就應該把動作做成一種資源。比如網上匯款,從賬戶1向賬戶2匯款500元,錯誤的URI是:

POST /accounts/1/transfer/500/to/2

正確的寫法是把動詞transfer改成名詞transaction,資源不能是動詞,但是可以是一種服務:

POST /transaction HTTP/1.1
Host: 127.0.0.1
from=1&to=2&amount=500.00

4.1.2. 另一個設計誤區,就是在URI中加入版本號

http://www.example.com/app/1.0/foo
http://www.example.com/app/1.1/foo
http://www.example.com/app/2.0/foo

因為不同的版本,可以理解成同一種資源的不同表現形式,所以應該采用同一個URI。版本號可以在HTTP請求頭信息的Accept字段中進行區分:

Accept: vnd.example-com.foo+json; version=1.0
Accept: vnd.example-com.foo+json; version=1.1
Accept: vnd.example-com.foo+json; version=2.0

4.1.3. 避免多級 URL

常見的情況是,資源需要多級分類,因此很容易寫出多級的 URL,比如獲取某個作者的某一類文章。

GET /authors/12/categories/2

這種 URL 不利於擴展,語義也不明確,往往要想一會,才能明白含義。更好的做法是,除了第一級,其他級別都用查詢字符串表達。

GET /authors/12?categories=2

下面是另一個例子,查詢已發布的文章。你可能會設計成下面的 URL。

GET /articles/published

查詢字符串的寫法明顯更好。

GET /articles?published=true

4.2. 傳輸協議

REST 是基於 HTTP 的文本類傳輸方式,與 SOAP 的 XML 相比,REST 用的是 Json,格式更加簡單易懂。

4.3. 服務發現

RESTful API 的服務發現有很多組件,比如說 Eureka,可以作為服務注冊中心,也能用來做負載均衡和容錯。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM