基于go分析rpc服务从客户端到服务端的代码结构

213 阅读2分钟

以关键源代码流程的方式分析rpc服务端和客户端代码结构

服务端流程结构

  1. 初始化服务端,通常是一个类或者结构体(init), 类似这样
myserver := server.NewServer()
  1. 服务注册
// 建立服务实体
type Echo struct{}

// 建立服务的方法
func (e *Echo) Say(req string) {
  println("Echo.Say...", req)
}

// 赋值服务实体到变量和设置服务选型
echoService := new(Echo)
opts := server.Options()

/*
@p1: 服务名称
@p2: 服务对象
@p3: 服务选项参数
*/
myserver.register("Echo", echoService, opts) 
  1. 服务运行
addr := "8.8.8.8:6767"
myserver.run(addr)

至此,一个服务端就完成了, 其中要比较关注的点如下:

  • opts可以封装所需的服务选项参数,比如协议(http或者rpc),是否加密,鉴权数据等等
  • 服务的注册和发现机制, 需要支持持久注册, 及时发现其他服务变动的功能,另外不可能每次服务之间的请求都要调用注册中心,这样效率比较低,所以服务启动时,应该把服务信息缓存一份到本地,但是需要有一个机制保证本地注册中心的实时改动要更新到本地的注册信息缓存去,不然会出现服务调用错误

客户端流程结构

  1. 指定服务名、请求的方法、请求的参数
svc := "Echo"
method := "say"
req := "hello"
  1. 初始化客户端、配置选项参数
opts := client.Options()
myclient := client.NewClient(opts)
  1. 调用服务端、取得返回
rsp := myclient.Invoke(svc, method, req)

至此,一个客户端就完成了, 其中要比较关注的点如下:

  • 一般客户端的选项参数都要在第2步完成,关键选项包括请求失败处理机制(重试、立即失败、失败之后降权等)、寻求服务节点算法、注册中心信息等,这几个都是核心逻辑,跟服务的负载,请求的稳定性都息息相关

核心逻辑分析

client invoke内幕