什么是 RPC?

如果要学习 GRPC 必须先了解什么是 RPC,因为 GRPC 是 RPC 的一个延伸。

RPC(Remote Procedure Call)远程过程调用,简单的理解是一个节点请求另一个节点提供的服务。

说到远程过程调用,就得提一下本地过程调用,他们两个的区别是什么?

举个例子:

我现在需要添加我的商品库存数量,在程序里面往往会建一个对象来存储这个数量,比如叫 Goods。

本地过程调用:

通常我们会创建一个方法 GoodsAdd() 需要将商品对象 Goods 传入,然后方法里面修改完毕后返回 Goods 对象回去,因为是本地调用,所以通常是使用指针传递 Goods 对象,一般都不会有特别明显的感觉。

20220124072834_jskjg8.png

远程过程调用:

和本地过程最大的区别是,这个 Goods 对象不在本地,通常是在别的服务器。

此时我们需要做的就是告诉这个服务他对应的 ID(Goods 对象) 是多少,然后做什么操作(GoodsAdd 方法及参数),处理完后传回处理结果。

说得再直白点就是远程的去调用方法,并传过去参数。

20220124072844_5x2t8e.png

RPC 的由来

如果是在 N 多年前,流量不大的情况下,大都是单体服务,基本也都能抗住生产使用了,那时基本都是本地过程调用。

但是随着现在的流量越来越大,很明显单体服务是满足不了生产使用的,就开始有了模块分离,微服务产生。

开始把一些业务逻辑放到不同的服务器上来跑,于是服务与服务之间的调用场景,就产生了 RPC。

RPC 与 REST API 的区别

提到服务与服务之间的调用,大家最常见的就是 REST API 了。

服务方提供一个接口文档,调用方按照这个接口文档调用接口就好了,这貌似挺合理的。

但是也有不好的地方:

REST API 更擅长对资源进行 CRUD 操作。

通常 REST API 对一个资源进行增删改查是非常直观的,但是如果要对特定的目的操作就比较不那么直观了。

比如:要给名为张三的学生数学成绩加上 10 分。

虽然 REST API 也能通过更新操作进行操作,但是毕竟不是那么直观。

而 RPC 他是直接把方法抛出去了,直接调用方法为 Student.Increment(Name,Sore) 的方法就完成了,看着是不是更加直观。

RPC 更高效。

RPC 可以通过 TCP 进行长连接,在调用量非常大的时候是非常有优势的。

当然 RESTful 也可以通过 keep-alive 实现长连接,但是它最大的一个问题是它的 request-response 模型是阻塞的 ( http1.0 和 http1.1,http 2.0 没这个问题)。

说得直白点,发送一个请求后只有等到 response 返回才能发送第二个请求,RPC 的实现没有这个限制。

所以在如今大流量的情况下,RPC 更出色。

怎么定义入参和出参?

RPC 是直接把方法给抛出去的,所以客户端和服务器端是紧耦合的。

客户端需要知道调用的这个方法名字,相关的参数以及它们的类型、顺序等。

一旦服务器更改了过程的实现,客户端的实现很容易出问题。

所以这里面该怎么去定义这个入参和出参呢?

如果不规范起来,百花齐放的,到时各个系统对接就非常难。

于是我们的老大哥谷歌就站出来了,说:我定义了一个 GRPC 协议,我不赚钱,我是第三方,一定会公立、公正的定义好协议,于是出了一个 GRPC 协议。

于是大家就听大哥哥的用 GRPC 了,很多第三方库也兼容支持了 GRPC。

那他是怎么做到公正、公立的呢?

思路很简单:

我搞一个编译器,并定义一个规范,你只管按照规范定义传参和出参就行,剩下的我编译器帮你处理。

20220124072858_jzijik.png

所以你就会发现在接入了 GRPC 的项目里面都能看到 .proto 文件的身影,他就是去定义每个请求相关的参数是什么,收到的是什么。

剩下的就不用你管了,是不是感觉有老大带头真爽。

所以一个完整的 GRPC 系统,都需要哪些支持呢?

1、client 和 service 肯定是需要有谷歌的解析依赖库,这个你可以不用关注,只管导入就好了。

2、定义出参、入参的规范 proto 文件。