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