0
点赞
收藏
分享

微信扫一扫

Go微服务:基于net/rpc模块实现微服务远程调用

西曲风 03-08 06:30 阅读 3

基于RPC协议实现微服务

  • 基于rpc实现跨语言调用,不限定服务提供方使用的语言
  • 在微服务架构中,每个微服务都被封装成了进程,相互独立
  • 在这里提供了客户端和服务端演示调用示例

1 )服务端

  • 新建 server/msg 目录,后执行 $ go mod init msg
  • 编辑 server/msg/main.go 文件
    package main
    
    // net 模块 gin框架内置
    import (
    	"fmt"
    	"net"
    	"net/rpc"
    )
    
    // 定义一个可供远程调用的struct
    type Msg struct {}
    
    // 为Msg这个struct添加被调用函数 GetReplay
    func (this Msg) GetReplay(req string, res *string) error {
    	fmt.Println(req) // 服务端输出日志:请求参数
    	*res = "这是服务端返回的信息:已收到客户端的请求参数,参数为:" + req // 这是返回信息
    	return nil
    }
    
    func main() {
    	// 1. 注册RPC服务
    	err1 := rpc.RegisterName("msg", new(Msg))
    	// 错误处理
    	if err1 != nil {
    		fmt.Println(err1)
    	}
    	// 2、监听端口
    	listener, err2 := net.Listen("tcp", "127.0.0.1:3000")
    	if err2 != nil {
    		fmt.Println(err2)
    	}
    	// 3、应用退出的时候关闭监听端口
    	defer listener.Close()
    	for {
    		// 4、建立链接
    		conn, err3 := listener.Accept()
    		// 错误处理
    		if err3 != nil {
    			fmt.Println(err3)
    		}
    		fmt.Print("客户端参数为: ");
    		// 5. 绑定服务
    		rpc.ServeConn(conn)
    	}
    }
    
  • net包是一个 go 内置的一个模块
  • 准备调用函数 Msg.GetReplay
    • 此方法只能有两个可序列化的参数,注意第二个参数是指针类型
      • req 表示获取客户端传过来的数据
      • res 表示给客户端返回数据 (指针类型)
    • 方法要返回一个 error 类型,同时必须是公开的方法
    • req 和 res的类型不能是 channel(通道)、func(函数)
    • 因为它们均不能进行序列化
  • 整个流程如下:
    • 1 )通过 rpc.RegisterName 注册 rpc 服务,注意这里的 name 后期被客户端调用
    • 2 )通过 net.Listen 监听rpc服务,得到 listener 对象
    • 3 )通过 defer listener.Close() 应用退出时关闭监听端口
    • 4 )基于无限循环做响应处理,这里有两个环节
      • 4.1 )通过 listener.Accept() 接收连接信息,得到 conn 连接对象
      • 4.2 )通过 rpc.ServeConn(conn) 绑定服务

3 )客户端

  • 新建 client 目录,后执行 $ go mod init client

  • 这里在 client 项目目录中,新建一个 main.go 文件

  • 编辑 client/main.go 文件

    package main
    
    import (
    	"fmt"
    	"net/rpc"
    )
    
    func main() {
    	// 1. 用 rpc.Dial和rpc微服务端建立连接
    	conn, err1 := rpc.Dial("tcp", "127.0.0.1:3000")
    	// 错误处理
    	if err1 != nil {
    		fmt.Println(err1)
    	}
    	// 2、当客户端退出的时候关闭连接
    	defer conn.Close()
    	// 3. 调用远程函数
    	var reply string
    	err2 := conn.Call("msg.GetReplay", "滴滴滴", &reply)
    	// 错误处理
    	if err2 != nil {
    		fmt.Println(err2)
    	}
    	// 4、获取微服务返回的数据
    	fmt.Println(reply)
    }
    
  • 这里是客户端,需要经过以下几个步骤:

  • 1 )要连接的话,首先要建立连接 rpc.Dial 得到 conn 连接对象

  • 2 )添加客户端退出时的关闭连接处理 defer conn.Close()

  • 3 )基于 conn.Call 调用远程函数

    • 第一个参数,服务名.远程方法 的字符串形式
    • 第二个参数,给服务端的参数
    • 第三个参数,服务端返回的数据地址

3 )部署服务

  • 先启动服务端,再启动客户端
  • 当服务端启动的瞬间
    • 服务端接收到客户端的参数打印到服务端
    • 客户端接收到服务端的返回信息

注意

  • 在Golang中实现RPC非常简单,有封装好的官方库和一些第三方库提供支持
  • Go RPC 可以利用tcp或http来传递数据,可以对要传递的数据使用多种类型的编解码方式
  • Golang 官方的 net/rpc 库使用 encoding/gob 进行编解码,支持tcp或http数据传输方式
  • 由于其他语言不支持 gob 编解码方式,所以使用 net/rpc 库实现的 RPC 方法没办法进行跨语言调用
  • 另外,Golang官方还提供了 net/rpc/jsonrpc 库实现RPC方法,JSON RPC采用JSON进行数据编解码
  • 因而支持跨语言调用,但目前的 jsonrpc 库是基于tcp协议实现的,暂时不支持使用http进行数据传输
  • 除了Golang官方提供的rpc库,还有许多第三方库为在 Golang 中实现RPC提供支持
  • 大部分第三方 RPC 库的实现都是使用 protobuf 进行数据编解码
  • 根据 protobuf 声明文件自动生成 RPC 方法定义与服务注册代码
  • 在 Golang 中可以很方便的进行 RPC 服务调用
举报

相关推荐

0 条评论