【基礎】RPC、JSON-RPC和HTTP區別

一. RPC

  1. RPC是什麼

    • RPC(Remote Procedure Call)指的是遠程過程調用,簡單的說,RPC就是從一臺機器上通過參數傳遞的方式調用另一臺機器上的一個函數或方法並得到響應結果。
    • RPC會隱藏底層的通訊細節。
    • RPC是一個請求響應模型,客戶端發起請求,服務器返回響應。
    • RPC在使用形式上像調用本地函數一樣去調用遠程的函數。
  2. 常見的RPC框架

    • dubbo: 阿里巴巴公司開源的一個Java高性能優秀的服務框架,使得應用可通過高性能的RPC實現服務的輸出和輸入功能,可以和Spring框架無縫集成。
    • motan: 新浪微博開源的一個Java 框架。它誕生的比較晚,起於2013年,2016年5月開源。Motan 在微博平臺中已經廣泛應用,每天爲數百個服務完成近千億次的調用。
    • rpcx: Go語言生態圈的Dubbo,比Dubbo更輕量,實現了Dubbo的許多特性,藉助於Go語言優秀的併發特性和簡潔語法,可以使用較少的代碼實現分佈式的RPC服務。
    • gRPC: Google開發的高性能、通用的開源RPC框架,主要面向移動應用開發並基於HTTP2協議標準而設計,基於ProtoBuf(Protocol Buffers)序列化協議開發,且支持衆多開發語言。
    • thrift: Apache的一個跨語言的高性能的服務框架
    • JSON-RPC: JSON-RPC是一個無狀態且輕量級的遠程過程調用(RPC)協議。
  3. 實現RPC框架
    由於RPC使用形式上調用同一個進程內存空間的函數或方法一樣,因此需要解決以下3個問題

    • 尋址: 客戶端調用的時候怎麼告訴服務端調用的是哪個函數或方法,在RPC框架中每個函數都有自己的CallID,所以客戶端在調用的時候需要帶上這個CallID表示調用哪個函數。CallID可以使用函數字符串名稱,也可以使用整數(需要有一個映射表來關聯)。
    • 序列化反序列化: 由於客戶端和服務端不是同一個進程不能通過內存來傳遞參數,因此需要客戶端先把參數序列化成字節流傳給服務端,服務端收到字節流後反序列爲自己能讀取的格式,序列化反序列可以使用Protobuf、JSON等。
    • 網絡傳輸: 客戶端和服務端需要通過網絡連接來傳輸數據,因此需要有一個網絡的傳輸層。網絡傳輸可以使用Socket、TCP、UDP、HTTP、HTTP2等。

二. HTTP

  1. HTTP請求本身也可以看做是RPC的一種具體形式。HTTP請求也一樣是可以從客戶端發一個信號到服務端,服務端上執行某個函數,然後返回一些信息給客戶端。HTTP請求非常常見,如果我們自己想開放自己機器的部分功能給任意的人用,那麼使用HTTP API的形式是非常合適的,因爲HTTP請求是大家都經常使用的方式。而很多時候,對於公司內部的兩臺機器之間,大家會按照實際需要去自定製一套RPC,這樣做的好處是靈活高效,但是壞處就是沒有通用性。

  2. HTTP和RPC異同

    • HTTP請求和RPC的相同點是同樣都具有請求和響應,二者的基本過程是一樣的,首先從客戶端發出請求,服務端收到之後執行某段代碼,然後把運算結果或者是報錯信息作爲響應,返回給客戶端。
    • HTTP請求往往圍繞資源,而RPC的請求往往圍繞一個動作。比如一個常見的HTTP請求有GET indexPOST posts分別表示請求首頁,或者發佈一篇文章。而用RPC執行相同的任務,就是指定一個函數get_index或者create_post
    • HTTP請求的服務器上,一般需要安裝Nginx或者Apache這樣的HTTP服務器軟件,而提供RPC的服務器不一定需要安裝這些軟件。

三. JSON-RPC

  1. JSON-RPC是一個無狀態且輕量級的RPC協議,其傳輸內容以JSON方式,相對於一般的HTTP請求通過URI調用遠程服務器,JSON-RPC直接在內容中定義了要調用的函數名稱(如 {“method”: “getUser”}),對於開發者來說非常的方便。BitcoinEthereum都支持JSON-RPC通過客戶端直接調用節點上的函數或方法。
    注意: 以rpc開頭的方法名預留作爲系統擴展,且必須不能用於其他地方。

  2. JSON-RPC請求
    JSON-RPC 2.0和1.0之間一些差異,我們這裏介紹2.0的使用,一個JSON-RPC的請求必須包含以下4個字段。

    • jsonrpc: 指定JSON-RPC的版本,必須設置爲2.0
    • id: 調用標識符,用於標示一次遠程調用過程,值必須包含一個字符串、數值。
    • method: 所要調用方法名稱的字符串
    • params: 方法傳入的參數,若無參數則傳入空[]
  3. JSON-RPC響應
    當發起一個RPC調用時,除通知之外服務端都必須有響應,響應表示爲一個JSON對象包含以下幾個字段。

    • jsonrpc: 指定JSON-RPC的版本,固定爲爲2.0
    • id: 調用標識符,用於標示一次遠程調用過程,值必須包含一個字符串、數值。
    • result: 如果調用成功則顯示響應結果
    • error: 如果調用失敗則顯示錯誤的信息,error帶有以下幾個字段
      • code: 錯誤類型,必須爲整數 【必須】
      • message: 錯誤的簡單描述字,該描述應儘量簡短 【必須】
      • data: 包含關於錯誤附加信息的基本類型或結構化類型 【可選】
  4. JSON-RPC錯誤碼

    • -32700: Parse error語法解析錯誤 (服務端接收到無效的json。該錯誤發送於服務器嘗試解析json文本)
    • -32600: Invalid Request (發送的json不是一個有效的請求對象)
    • -32601: Method not found (該方法不存在或無效)
    • -32602: Invalid params (無效的方法參數)
    • -32603: Internal error (JSON-RPC內部錯誤)
    • -32000 ~ -32099: Server error (預留用於自定義的服務器錯誤)
    • -32768 ~ -32000: 保留的預定義錯誤代碼, 保留下列以供將來使用
  5. JSON-RPC示例

1. 帶索引數組參數的rpc調用
--> {"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": 1}
<-- {"jsonrpc": "2.0", "result": 19, "id": 1}

2. 帶關聯數組參數的rpc調用
--> {"jsonrpc": "2.0", "method": "subtract", "params": {"subtrahend": 23, "minuend": 42}, "id": 3}
<-- {"jsonrpc": "2.0", "result": 19, "id": 3}

3. rpc批量調用
--> [{"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": "1"},
     {"jsonrpc": "2.0", "method": "notify_hello", "params": [7]},
     {"jsonrpc": "2.0", "method": "subtract", "params": [42,23], "id": "2"},
     {"foo": "boo"},
     {"jsonrpc": "2.0", "method": "foo.get", "params": {"name": "myself"}, "id": "5"},
     {"jsonrpc": "2.0", "method": "get_data", "id": "9"}]
<-- [{"jsonrpc": "2.0", "result": 7, "id": "1"},
     {"jsonrpc": "2.0", "result": 19, "id": "2"},
     {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
     {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "5"},
     {"jsonrpc": "2.0", "result": ["hello", 5], "id": "9"}]

1. 不包含調用方法的rpc調用
--> {"jsonrpc": "2.0", "method": "foobar", "id": "1"}
<-- {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "1"}

2. 包含無效json的rpc調用
--> {"jsonrpc": "2.0", "method": "foobar, "params": "bar", "baz]
<-- {"jsonrpc": "2.0", "error": {"code": -32700, "message": "Parse error"}, "id": null}

3. 無效請求對象的rpc調用
--> {"jsonrpc": "2.0", "method": 1, "params": "bar"}
<-- {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章