• GO学习之 远程过程调用(RPC)


    GO系列

    1、GO学习之Hello World
    2、GO学习之入门语法
    3、GO学习之切片操作
    4、GO学习之 Map 操作
    5、GO学习之 结构体 操作
    6、GO学习之 通道(Channel)
    7、GO学习之 多线程(goroutine)
    8、GO学习之 函数(Function)
    9、GO学习之 接口(Interface)
    10、GO学习之 网络通信(Net/Http)
    11、GO学习之 微框架(Gin)
    12、GO学习之 数据库(mysql)
    13、GO学习之 数据库(Redis)
    14、GO学习之 搜索引擎(ElasticSearch)
    15、GO学习之 消息队列(Kafka)
    16、GO学习之 远程过程调用(RPC)
    17、GO学习之 goroutine的调度原理

    前言

    按照公司目前的任务,go 学习是必经之路了,虽然行业卷,不过技多不压身,依旧努力!!!
    RPC 在许多应用程序中有着广泛应用,尤其是分布式系统和微服务中,一些场景的应用场景包括:

    • 微服务通信: 在微服务框架中,实现各个服务之间的通信使用 RPC 进行通信,以实现服务间的协作和数据传递。
    • 分布式系统: 在分布式系统中,不同节点之间需要进行远程调用。
    • 高性能计算: 在高性能计算环境中,可以使用 RPC 在不同计算机节点上执行计算任务,以加速并行计算。
    • 数据同步: 在不同数据源之间进行数据同步,例如:将数据从一个数据库复制到另一个数据库。

    一、什么是RPC?

    • RPC 是远程过程调用(Remote Procedure Call, RPC)是一个计算机通信协议。
    • RPC 协议允许一台计算机的程序调用另一台计算机的子程序,我程序员无需要额外地为这个交互编程。
    • RPC 允许应用程序调用另一个地址空间(通常是远程服务器)上的函数和方法,就像本地调用一样。
    • RPC 的核心思想就是使远程调用过程对开发者透明,就像本地调用一样。

    二、调用示例

    在Go 标准库中包含了net/rpc包,用于实现 RPC 远程调用,所以不用在引入第三方包了。

    2.1 服务端

    下面代码中,实现了一个 RPC 的服务端,用来提供 RPC 服务,通过 rpc.Register(productService)来注册一个服务,并且通过 net.Listen("tcp", ":8899")监听。

    package main
    
    import (
    	"fmt"
    	"log"
    	"net"
    	"net/rpc"
    )
    
    // 定义一个返回体结构
    type Product struct {
    	Id    int32
    	Name  string
    	Desc  string
    	Price float32
    }
    
    // 定义了一个 RPC 服务,用于返回产品信息
    type ProductService struct{}
    
    // 定义服务的方法, 参数定义需要定义为传递对象的指针
    func (ps *ProductService) FetchProduct(Id *int32, reply *Product) error {
    	p := Product{
    		Id:    *Id,
    		Name:  "钻石王老五",
    		Desc:  "一部手机,能打电话",
    		Price: 5000.00,
    	}
    	// 将产品信息写入 reply 指针
    	*reply = p
    	return nil
    }
    
    func main() {
    	// 实例化产品服务
    	productService := new(ProductService)
    	// 注册ProductService 为 RPC 服务
    	rpc.Register(productService)
    
    	// 启动监听 8899
    	listener, err := net.Listen("tcp", ":8899")
    	if err != nil {
    		log.Fatal("RPC service start fial: ", err)
    		return
    	}
    	defer listener.Close()
    
    	fmt.Println("RPC service is listening on part 8899...")
    	for {
    		// 接受客户端连接
    		conn, err := listener.Accept()
    		if err != nil {
    			fmt.Println("Error accepting connection: ", err)
    			continue
    		}
    		// 启动一个新的 goroutine 处理连接
    		go rpc.ServeConn(conn)
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    运行结果:

    PS D:\workspaceGo\src\rpc> go run .\rpcServer.go
    RPC service is listening on part 8899...
    
    • 1
    • 2

    2.2 客户端

    以下是 RPC 客户端代码,实现调用服务端代码,并且获得返回信息。代码中通过 rpc.Dial("tcp", "127.0.0.1:8899")调用本地端口 8899,通过 client.Call("ProductService.FetchProduct", 1, &result)实现调用,第一个参数为 远程方法名,第二个是方法参数,第三个参数用于接收返回结果。

    package main
    
    import (
    	"fmt"
    	"log"
    	"net/rpc"
    )
    
    // 定义一个结构体用户接受数据
    type Product struct {
    	Id    int32
    	Name  string
    	Desc  string
    	Price float32
    }
    
    func main() {
    	// 连接到远程 RPC 服务
    	client, err := rpc.Dial("tcp", "127.0.0.1:8899")
    	if err != nil {
    		log.Fatal("Connect to server fail: ", err)
    	}
    	defer client.Close()
    
    	var result Product
    	// 调用远程函数 fetchProduct,result 用来获取返回值
    	err = client.Call("ProductService.FetchProduct", 1, &result)
    	if err != nil {
    		log.Fatal("Call remote function fail: ", err)
    		return
    	}
    	fmt.Printf("Result: %v \n", result)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    运行结果:

    PS D:\workspaceGo\src\rpc> go run .\rpcClient.go
    Result: {1 钻石王老五 一部手机,能打电话 5000} 
    PS D:\workspaceGo\src\rpc> 
    
    • 1
    • 2
    • 3

    三、RPC 实际应用中的优缺点

    优点(不限于):

    1. 简化分布式系统开发: RPC 隐藏了底层通信细节,使分布式系统开发更加容易。
    2. 强类型: RPC 使用强类型语言定义接口,可以提前发现类型错误。
    3. 跨语言: 许多 RPC 框架支持多种编程语言,可以使不同语言开发的应用系统之间通信。

    缺点(不限于):

    1. 增加复杂性: 在分布式系统的开发中,RPC 可能会增加系统的复杂性,例如:调用失败、超时和并发问题等。
    2. 性能开销: RPC 引入了额外的开销,比如:序列化、反序列化、网络开销等。

    现阶段还是对 Go 语言的学习阶段,想必有一些地方考虑的不全面,本文示例全部是亲自手敲代码并且执行通过。
    如有问题,还请指教。
    评论去告诉我哦!!!一起学习一起进步!!!

  • 相关阅读:
    使用react-amanda快速搭建管理类型的系统
    封装简单版消息提示组件
    python多线程返回值问题重写Thread类的run方法
    CocosCreator接入wwise的CocosAndroid.mk
    Python3高级特性(四)之生成器(Generator)
    图扑数字孪生屋顶光伏,推进光伏建筑一体化监管
    使用 Verilog 做一个可编程数字延迟定时器 LS7211-7212
    SpringBoot 测试实践 - 2:单元测试与集成测试
    mysql函数
    【前端】前端监控体系
  • 原文地址:https://blog.csdn.net/qq_19283249/article/details/132919380