RPC
Kitex 是字节跳动开源的高性能、强可扩展性的 Go RPC 框架。RPC (Remote Procedure Call,远程过程调用)是一种通过网络从远程计算机上请求服务的技术,使得外显地对一个远程服务的调用就像调用本地函数一样。
前置知识
通信模型
与 RPC 相对的、用于微服务间通信的手段还有基于 HTTP 的 RESTful API。RESTful API 通常使用 HTTP 协议,通过 URL 来指定资源,并使用 HTTP 动词(GET、POST、PUT、DELETE)来表示对资源的操作;因此其是面向资源,比较重但耦合度低的。RPC 则基于更高效的二进制协议的 HTTP/2,强调性能和效率,并且它是面向过程但耦合度高的,但可以提升代码的可维护性和可扩展性。
HTTP:慢且重(HTTP 请求复杂),面向资源(基于 URL 的调用且 HTTP 的无状态),耦合度低(controller 的定义灵活)
RPC:快且轻量(二进制协议),面向过程(基于函数调用),耦合度高(接口的参数和服务的定义都是固定的)
-
为什么RPC不使用HTTP/3?
HTTP/3是HTTP协议的最新版本,主要改进在于使用QUIC协议作为传输层协议,QUIC基于UDP而不是TCP,为了保证可靠通信,QUIC需要在应用层实现类似于TCP的机制保证数据传输的可靠性,包括错误检测、流量控制、拥塞控制。
微服务大多是在内网环境中,网络状态良好,使用长连接、连接多路复用也能减少TCP的建连开销,因此在内网微服务场景下HTTP/3的优势并不明显,反而因为应用层可靠机制的引I入,导致性能劣化。
IO 多路复用
-
select:单个进程能够处理的fd 数量有限;需要轮询所有的文件描述符,效率较低
-
poll:没有了fd 的限制,但依然需要遍历所有文件描述符,效率较低
-
epoll:使用事件通知的机制,只有真正准备好进行 I/O 操作的fd 才会被返回,所以 epoll的效率并不随文件描述符数量的增加而降低。支持边缘触发和水平触发两种模式,提供了更多的灵活性。
使用流程
RPC 调用的过程
- 客户端构造请求参数,发起调用
- 客户端通过服务发现、负载均衡等得到服务端实例地址,并建立连接
- 客户端将请求参数序列化成二进制数据,并通过网络发送
- 服务器接受数据,并反序列化出请求参数
- 服务器的 handler(controller) 接收并处理请求,返回响应结果
- 服务器将响应结果序列化成二进制数据,并通过网络发送回复给客户端
- 客户端接受数据,并反序列化出响应结果,得到调用的结果
RPC 服务开发的流程
- 使用 Thrift 作为语言,定义 IDL 服务接口,包括请求参数、响应参数和服务定义
- 使用 Kitex 生成代码,并调用
go mod tidy
导入必要依赖 - 服务端开发者编写服务端的 handler,以处理客户端的请求并返回响应结果
- 服务端开发者运行服务监听端口,等待客户端的连接以应对处理请求
- 客户端开发者编写客户端程序(创建客户端 -> 调用 -> 接收响应),经过服务发现连接上服务端程序,发起请求并接收响应
组成
一般的 RPC 都会被大致分为三个大的部分,一是服务的定义(其中服务可以看作一个类,其中有很多接口,还有请求和响应参数,类似于 controller),二是服务的实现(这是由 Server 服务端实现的,类似于 Service 层),三是服务的调用(这是由 Client 客户端发起的,把暴露出的 RPC 接口当成本地调用一样进行调用即可)。