【GeeRPC】7天用 Go 从零实现 RPC 框架 GeeRPC
7天用 Go 从零实现 RPC 框架 GeeRPC
这部分内容来自于 Golang 大佬 Geektutu 的七天用 Go 从零实现系列,仅做学习之用,原项目链接在此。
1. 谈谈 RPC 框架
RPC(Remote Procedure Call,远程过程调用)是一种计算机通信协议,允许调用不同进程空间的程序。RPC 的客户端和服务器可以在一台服务器上,也可以在不同的机器上。程序员在使用时,可以像调用本地程序一样使用,而无需关注内部的实现细节。
不同的应用程序之间通信方式有很多,比如浏览器和服务器之间广泛使用的基于 HTTP 协议的 Restful API【来自 DeepSeek:RESTful API 是一种基于 REST(Representative State Transfer,表述性状态转移)架构风格设计的 API。它使用 HTTP 协议进行通信,通常用于 Web 服务开发】。与 RPC 相比,Restful API 有相对统一的标准,因而更加通用,兼容性更好,支持不同的语言(因为它基于 http 协议)。HTTP 协议是基于纯文本的,一般具备更好的可读性。但是缺点也很明显:
- Restful 接口需要额外定义,而 RPC 相当于直接调用;
- 基于 HTTP 协议的 Restful 报文冗余,承载了过多的无效信息,而 RPC 通常使用自定义的协议格式(比如 protobuf),减少报文冗余;
- RPC 可以采用更高效的序列化协议,将文本转为二进制数据(因此需要处理序列化和反序列化),获得更高的性能;
- 因为 RPC 的灵活性,所以更容易扩展和集成诸如注册中心(比如 consul)、负载均衡等功能。
2. 重点:RPC 框架需要解决什么问题?
不如换一个问法:为什么需要 RPC 框架?
首先我们想象两台机器,两个应用程序之间需要通信,那么首先我们需要确定采用何种传输协议。如果这两个程序位于不同的机器,那么一般会选择 TCP 或 HTTP 协议;如果两个应用程序位于相同的机器,也可以采用 Unix Socket 协议【也即,首先需要确定两个应用程序之间的通信方式(通过什么协议)】。传输协议确定之后,还需要确定报文的编码格式,比如 JSON/XML,当报文较大时,还可能会选择 protobuf 等其它编码方式【确定传输协议之后,还需要确定报文的编码格式,JSON 是最常见的编码方式,protobuf 是比较新的编码方式,通常与 gRPC 相结合】。
解决了传输协议和报文编码的问题,接下来还需要解决一系列可用性问题,例如,连接超时了怎么办?是否支持异步请求和并发?【传输协议确定了两个应用程序之间的通信方式,而编码格式确定了两个应用程序之间传递数据的格式。在二者之上,还需要解决连接超时、异步请求、并发等可用性问题】
如果服务器的实例很多。客户端并不关心这些实例的地址和部署位置,只关心自己能否获取到期待的结果,这就引出了注册中心(registry)和负载均衡(load balance)的问题。简单来说,就是客户端和服务端互相感知不到对方的存在,服务端启动时将自己注册到注册中心,客户端调用时从注册中心获取所有可用的实例(这些实例对于客户端而言就像是可以直接调用的函数一样),选择一个来调用。这样客户端和服务端只需要感知注册中心的存在就足够了。注册中心通常还需要实现服务动态添加、删除,使用心跳确保服务处于可用状态等功能。【总结一下,在确定传输协议和报文编码的基础上,一个 RPC 框架还应该具有注册中心和负载均衡,注册中心比较重要,它通常应该进一步实现服务动态添加、删除、使用心跳来确保服务处于可用状态等功能】
再进一步,加入服务端由不同的团队提供,如果没有统一的 RPC 框架,各个团队的服务提供方就需要各自实现一套消息编解码、连接池、收发线程、超时处理等“业务之外”的重复技术劳动,造成整体的低效。因此,“业务之外”的这部分公共能力,是 RPC 框架所需要具备的能力。
3. 关于 GeeRPC
Golang 广泛地应用于云计算和微服务,成熟的 RPC 框架和微服务框架汗牛充栋。grpc
、rpcx
、go-micro
等都是非常成熟的框架。一般地,RPC 是微服务框架的一个子集,微服务框架可以自己实现 RPC 部分,当然,也可以选择不同的 RPC 框架作为通信基座。
考虑性能和功能,上述成熟的框架代码量庞大,且通常与第三方库(最典型的就是 gRPC 和 protobuf 的联合使用)有比较深的耦合。GeeRPC 的目的是以最少的代码,实现 RPC 框架中最重要的部分。
综上,GeeRPC 从零开始以 Golang 官方标准库的 net/rpc
为基础,新增了协议交换(protocol exchange)、注册中心(registry)、服务发现(service discovery)、负载均衡(load balance)、超时处理(timeout processing)等特性。分七天完成,代码量在 1000 行左右。