RPC

128 阅读5分钟

简介

RPC(Remote Procedure Call),即远程过程调用或者远程方法调用。它允许像调用本地方法一样调用远程方法

RPC是CS(Client/Server)模式,client发送RPC请求,server进行响应。

为啥要用RPC,HTTP不香吗?使用RPC的目的是啥?

  1. 使调用远程方法像调用本地方法一样简单
  2. 性能高

我的理解

RPC核心就三点:

  1. 网络通信。因为是远程调用,肯定需要网络通信,那就需要有client和server,client发送RPC请求,server进行响应。涉及的问题就有:拆包、解包、序列化和反序列化
  2. 约定协议。
    1. server端需要告诉client端它提供了哪些远程方法,client才知道它能调用哪些方法,以及做某件事时要调用哪个方法。(类似http接口文档)
    2. server端还需要告诉client端每个方法的参数列表,client才知道调用方法时如何传参。
    3. server端还需要告诉client端每个方法的返回结果是啥,client才知道如何解析返回结果。
    4. client和server端要约定消息格式(RPC请求和响应的消息格式)、序列化和反序列化方式等,只有这样:client端发送RPC请求时才知道怎样构造请求体、如何序列化;server端收到RPC请求时才知道如何反序列化、如何处理请求体;server端返回响应时才知道如何构造响应体、如何序列化;client端收到RPC响应时才知道如何反序列、如何处理响应体......
    5. server端收到RPC请求,根据协议解析请求体(解析出方法标识、方法参数等),然后路由到本地方法进行本地方法调用。
  3. 本地方法调用。包括client端的本地调用和server端的本地调用。client端进行本地方法调用后,然后发送RPC请求;server端收到RPC请求,需要路由到本地方法进行本地调用。涉及的问题就有:server如何解析RPC请求、如何路由到本地方法进行本地调用,如何解析还得看client如何传参,所以双方肯定要有个约定、有个协议。

其实,方法签名(方法名+入参列表+返回结果)本身就可以作为一个协议了,根据方法签名client就能知道该方法的标识符是啥、如何传参、如何解析返回结果,根据方法签名server就能知道如何解析参数进行本地方法调用。


RPC如何做到像调用本地方法一样调用远程方法?
其实就是client和server依赖相同的接口,server端实现接口提供真正的服务,client端本地调用接口从而调用远程方法(即调用远程方法就像调用本地方法一样),接口就作为双方约定的协议(这个接口就能告诉client端:server端提供了哪些远程方法、每个方法如何传参、每个方法返回值如何解析)。
至于底层的网络通信、client本地调用后如何发送RPC请求、server收到RPC请求如何进行本地方法调用就是个通用的问题了,可以实现一个框架解决这个通用问题。


RPC调用的大致过程就是:

  1. client进行本地方法调用
  2. client发送RPC请求
  3. server进行本地方法调用
  4. server返回响应
  5. client处理返回值

总结一下问题(帮助更好理解RPC)

client侧的问题:

  1. client怎么知道它干某件事时需要调用哪个远程方法?以及如何传递方法参数?如何处理这个方法的返回结果?

这就需要server端把它提供的所有远程方法的方法元信息告诉client方法元信息即方法标识符、参数列表、返回结果,方法标识符告诉client该方法是干啥的,参数列表告诉client如何传参,返回结果告诉client如何处理返回值。那如何告诉呢?常见的解决方案是:client和server依赖相同的接口

  1. client怎么知道发送RPC请求时需要传哪些请求参数、如何构造请求体、采用何种序列化协议?
  2. client怎么知道收到RPC响应时采用何种反序列化协议、如何解析响应结果?

server端问题:

  1. server端收到RPC请求时采用何种反序列化协议、如何解析请求体?
  2. server端如何将RPC请求路由到对应的本地方法上进行本地调用?
  3. server端怎么知道返回RPC响应时需要返回哪些信息、如何构造响应体、采用何种序列化协议?

这些问题都需要双方约定好协议!!!

RPC框架就解决了这些通用问题。可以研究下各个RPC框架如何解决这些问题的。


RPC大致原理

image.png

RPC框架就负责创建client-stub和server-stub,封装RPC调用过程,开发者只需关注本地方法调用即可,无需关注其他细节。

如下有一张更细节的图(来源于网络):

2f716af9-a30f-4863-ab8e-e0cf661699db.jpeg