Golang 提供了一个开箱即用的RPC服务,实现方式简约而不简单。本文对net/rpc 包做深度解读和学习实战。

RPC 简单介绍

远程过程调用 (Remote Procedure Call,RPC) 是一种计算机通信协议。允许运行在一台计算机的程序调用另一个地址空间的子程序(一般是开放网络中的一台计算机),而程序员就像调用调用本地程序一样,无需额外做交互编程。RPC 是一种 CS (Client-Server) 架构的模式,通过发送请求-接收响应的方式进行信息的交互。

net/rpc

Golang 的实现

rpc 是 cs 架构,所以既有客户端,又有服务端。下面,我们先分析通信的编码,之后从服务端、客户端角度分析RPC的实现。

通信编码

golang 在rpc 实现中,抽象了协议层,我们可以自定义协议实现我们自己的接口。如下是协议的接口:

// 服务端
type ServerCodec interface {
  ReadRequestHeader(*Request) error
  ReadRequestBody(interface{}) error
  WriteResponse(*Response, interface{}) error

  // Close can be called multiple times and must be idempotent.
  Close() error
}
// 客户端
type ClientCodec interface {
  WriteRequest(*Request, interface{}) error
  ReadResponseHeader(*Response) error
  ReadResponseBody(interface{}) error

  Close() error
}

而包中提供了基于gob 二进制编码的编解码实现。当然我们也可以实现自己想要的编解码方式。

Server 端实现

结构定义

type Server struct {
    
  serviceMap sync.Map   // 保存Service
  reqLock    sync.Mutex // 读请求的锁
  freeReq    *Request
  respLock   sync.Mutex // 写响应的锁
  freeResp   *Response
}

server端通过互斥锁的方式支持了并发执行。由于每个请求和响应都需要定义Request/Response 对象,为了减少内存的分配,这里使用了一个freeReq/freeResp 链表实现了两个对象池。当需要Request 对象时,从 freeReq 链表中获取,当使用完毕后,再放回链表中。

服务的注册<