Go GRPC 实战入门系列


在前面这么多篇的介绍中,相信你已经对 GRPC 已经有一定的了解了,并且也已经能够应用到现实的业务中了。但是,前面因为着重于介绍 GRPC 的功能,对于一些细枝末节的东西没有展开来描述,所以这一篇收尾文章就对一些细枝末节的东西进行一个总结,希望能够有所帮助。

1. 一定要用 Protobuf 吗

这个问题其实是可以拆解为两个问题来回答,分别是:

  1. 为什么要用 Protobuf?
  2. 使用 GRPC 一定要用 Protobuf 吗?

接触过一些相对比较旧的系统的同学可能知道以前有个东西叫 WSDL,这是一种通过 XML 定义服务的接口和参数,并且可以用于客户端和服务器通信的一个完整的 SOAP 协议。但是,因为它的语法不叫冗余,并且通信使用 XML,多语言支持并不完善等因素逐渐被人们抛弃;还有另外一个现在和 GRPC 是竞争关系的 RPC 协议 Thrift 也被广泛使用,它就不使用 Protobuf,而是使用 Facebook 的 Thrift 数据格式。

在前边讲示例的时候也说过,即使用 GRPC 也不一定非要写 proto,如果你可以构造出 proto 对应的 struct 的话,proto 是可以省略的,但是这意味着一大堆工作:

这些都是比较麻烦的,所以定义 Proto 不是必须的,而是强烈推荐的。

2. 什么时候该用 Simple RPC

我们已经知道,GRPC 有两种大类,分别是 Unary 和 Stream 的,那么什么时候改用 Unary,什么时候又不该用呢?这个我们得了解 Unary 的优势和不足说起:通过 Unary,我们可以和普通的函数一样执行 Request-Response 的代码模型;但是,这就会有一个请求体大小的问题,在单体应用中,可能因为分配内存太大而 OOM,在网络中也类似,可能因为请求体过大,而导致网络阻塞,服务器阻塞或者异常,从而导致请求响应模型出现异常,例如超时错误等;

因此,Unary 一般会用于请求体和响应体都不大,并且响应是有时间保证的场景下,对于特殊的场景,需要根据实际情况做一些调整;

3. 为什么要用 Streaming RPC

正如 Unary 的不足中所述,如果请求体过大,或者响应体过多,那么我们需要考虑引入 Stream,通过 Stream,我们可以处理大规模数据包的情况,将一次性的大包分解为多次的小包;并且可以让对端根据小包实时得返回处理结果。

一个简单的例子就是大数据中的数据清洗,假设发起端每次传递一行记录,而服务器就对应这行记录进行清洗,分割成格式统一的记录,并且返回给客户端,通过 Stream,客户端和服务器都可以源源不断得以小数据的方式进行处理,从而避免一次性的大数据传输;然而,在使用 Stream 的时候,还需要注意到这是 RPC,会有时延和额外的消耗,所以,对于 Stream 的频率和大小需要做一些测试和验证。