Golang學習之初識RPC


RPC 簡介

RPC(Remote Procedure Call):遠程過程調用,它是一種通過網絡從遠程計算機程序上請求服務,而不需要了解底層網絡技術的思想。

 

RPC 是一種技術思想而非一種規范或協議,常見 RPC 技術和框架有:

  • 應用級的服務框架:阿里的 Dubbo/Dubbox、Google gRPC、Spring Boot/Spring Cloud。
  • 遠程通信協議:RMI、Socket、SOAP(HTTP XML)、REST(HTTP JSON)。
  • 通信框架:MINA 和 Netty。

 

目前流行的開源 RPC 框架還是比較多的,有阿里巴巴的 Dubbo、Facebook 的 Thrift、Google 的 gRPC、Twitter 的 Finagle 等。

 

完整的 RPC 框架

在一個典型 RPC 的使用場景中,包含了服務發現、負載、容錯、網絡傳輸、序列化等組件,其中“RPC 協議”就指明了程序如何進行網絡傳輸和序列化。

圖 1:完整 RPC 架構圖

 

如下是 Dubbo 的設計架構圖,分層清晰,功能復雜:

圖 2:Dubbo 架構圖

 

 

 

RPC 核心功能

RPC 的核心功能是指實現一個 RPC 最重要的功能模塊,就是上圖中的”RPC 協議”部分:

圖 3:RPC 核心功能

 

一個 RPC 的核心功能主要有 5 個部分組成,分別是:客戶端、客戶端 Stub、網絡傳輸模塊、服務端 Stub、服務端等。

圖 4:RPC 核心功能圖

 

下面分別介紹核心 RPC 框架的重要組成:

  • 客戶端(Client):服務調用方。
  • 客戶端存根(Client Stub):存放服務端地址信息,將客戶端的請求參數數據信息打包成網絡消息,再通過網絡傳輸發送給服務端。
  • 服務端存根(Server Stub):接收客戶端發送過來的請求消息並進行解包,然后再調用本地服務進行處理。
  • 服務端(Server):服務的真正提供者。
  • Network Service:底層傳輸,可以是 TCP 或 HTTP。

 

Golang RPC Demo

JSON-RPC

JSON-RPC是一個輕量級的遠程調用協議,簡單易用。本章節通過該協議進行演示。

 

請求數據體

1 {
2     "id": 1,  //本次請求的標識碼,遠程返回時數據的標識碼應與本次請求的標識碼相同
3     "method": "getName",  //遠端的方法名
4     "params": ["1"]  //遠程方法接收的參數列表
5 }

 

返回數據體

1 {
2     "id": 1,  //調用時所傳來的id
3     "result": {"id": 1, "name": "name1"}  //遠程方法返回值
4     "error": null  //錯誤信息
5 }

 

 

Go 的 RPC 包

net/rpc 包實現了最基本的rpc調用,它默認通過HTTP協議傳輸gob數據來實現遠程調用。

 

服務端實現了一個HTTP server,接收客戶端的請求,在收到調用請求后,會反序列化客戶端傳來的gob數據,獲取要調用的方法名,並通過反射來調用我們自己實現的處理方法,這個處理方法傳入固定的兩個參數,並返回一個error對象,參數分別為客戶端的請求內容以及要返回給客戶端的數據體的指針。

 

net/rpc/jsonrpc 包實現了JSON-RPC協議,即實現了net/rpc包的ClientCodec接口與ServerCodec,增加了對json數據的序列化與反序列化。

 

Demo

代碼目錄結構

 

Demo代碼

service.go

 1 package service
 2 
 3 import "errors"
 4 
 5 // 需要傳輸的對象
 6 type DemoService struct {
 7 }
 8 
 9 // 需要傳輸的參數
10 type Args struct {
11     A, B int
12 }
13 
14 // 普通的數學除法服務 如果被除數是0 則返回錯誤
15 func (s DemoService) Div(args Args, result *float64) error {
16     if args.B == 0 {
17         return errors.New("division by zero")
18     }
19     *result = float64(args.A) / float64(args.B)
20     return nil
21 }

 

 

server.go

 1 package main
 2 
 3 import (
 4     "RPC/service"
 5     "log"
 6     "net"
 7     "net/rpc"
 8     "net/rpc/jsonrpc"
 9 )
10 
11 func main() {
12     // 注冊一個服務
13     err := rpc.Register(service.DemoService{})
14     if err != nil {
15         panic(err)
16     }
17 
18     // 開始監聽 使用 1234 端口
19     listener, err := net.Listen("tcp", ":1234")
20     if err != nil {
21         panic(err)
22     }
23 
24     // 等待並處理連接
25     for {
26         conn, err := listener.Accept()
27         if err != nil {
28             log.Printf("accept error: %v", err)
29             continue
30         }
31         // 使用協程 goroutine 異步處理連接請求
32         go jsonrpc.ServeConn(conn)
33     }
34 }

 

 

client.go

 1 package main
 2 
 3 import (
 4     "RPC/service"
 5     "fmt"
 6     "net"
 7     "net/rpc"
 8     "net/rpc/jsonrpc"
 9 )
10 
11 func main() {
12     // 創建連接
13     conn, err := net.Dial("tcp", ":1234")
14     if err != nil {
15         panic(err)
16     }
17 
18     // 建立 json-rpc 協議 客戶端 通信管道
19     client := jsonrpc.NewClient(conn)
20 
21     // 發送請求數據
22     SendData(client, service.Args{
23         A: 10,
24         B: 3,
25     })
26     SendData(client, service.Args{
27         A: 10,
28         B: 0,
29     })
30 }
31 
32 func SendData(client *rpc.Client, args service.Args) {
33     var result float64
34     err := client.Call("DemoService.Div", args, &result)
35     if err != nil {
36         fmt.Println(err)
37     } else {
38         fmt.Println(result)
39     }
40 }

 

 

流程復現

  1. 運行 server.go 啟動 RPC 服務器

 

  1. 通過 window 自帶的 telnet 服務 手工發送請求測試

如果連接成功 會出現一片空白

此時鍵入 Ctrl + ] 進入 Microsoft Telnet 命令行模式 輸入

1 send {"id":1,"method":"DemoService.Div","params":[{"A":10,"B":3}]}

 

發送數據后 再按一下回車鍵 退出 Microsoft Telnet 命令行模式

由結果可以知道 調用除法服務成功 結果:10 / 3 = 3.3333333333333335

 

再發送一組錯誤參數

1 send {"id":1,"method":"DemoService.Div","params":[{"A":10,"B":0}]}

 

得到正確的錯誤返回 說明我們的Demo服務正確執行了

 

  1. 運行 client.go 通過客戶端模式 發送請求

得到的結果跟預期一樣 Demo演示結束


免責聲明!

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



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