vlambda博客
学习文章列表

grpc教程(二)横向比较与grpc通信模式




01

横向比较


之前一篇讨论了RESTful服务的局限性,因为这些局限性为grpc的诞生奠定了基础。与此同时也诞生了很多其他的新兴进程间通信技术,它们的问世也是为了满足相同的需求。比如thrift和graphQL。


thrift

thrift是和grpc类似的rpc框架,同样可以在定义文件中定义数据类型和服务接口,thrift编译器以服务定义作为输入生成客户端代码和服务器端代码;

thrift为传输层为网络IO提供了抽象,有着自己独立的协议层,把协议解偶出来可以在TCP,http任意传输上实现。比如hadoop大数据的hive传输就是通过thrift开发进程间通信协作。


graphql

graphql是一门针对API的查询语言,并且是基于既有数据满足这些查询的运行时。可以允许客户端定义希望的数据,获取数据的方式以及数据格式。比如如果消费者只需知道关于商品的特定信息而不是整个商品的完整属性,graphql允许消费者使用查询语言来查询服务并获取想要的信息。

grpc教程(二)横向比较与grpc通信模式

在graphql和grpc的大多数使用场景中,graphql用于面向外部的服务或api,支撑api的内部服务则使用grpc实现。


关于学习graphql,建议技术选型的时候关注知乎上的一个问题“GraphQL 为何没有火起来?”,这里有针对graphql实用性的一些讨论,其中我认同的一个观点是

“如果只是聚合现有rest,意义不大,就是gateway;如果替换rest,提供更多灵活性,那成本过高。很多说“你真的不懂graphql“的人也不见得真的利用graphql完全替代了rest写出一个完全暴露给前端的聚合网关。”



02


grpc的通信方式


grpc的通信模式共有4种基础通信模式,一元RPC,服务器端流RPC,客户端流RPC以及双向流RPC。


一元RPC

一元RPC模式也称为简单RPC模式。

grpc教程(二)横向比较与grpc通信模式

一元RPC模式  

在一元RPC模式中,当客户端调用服务器端的远程方法,客户端发送请求至服务器端并获得一个响应,与响应一起发送的还有状态细节以及trailer元数据。这也是grpc最常用的通信方式。


syntax = "proto3";
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
package bilibili.app.interface.v1;
// History 历史记录service History { // 历史记录tab rpc HistoryTab(HistoryTabReq) returns (HistoryTabReply);}
// HistoryTabReq 历史记录列表请求参数message HistoryTabReq { string business = 1; // 查询请求来源 HistorySource source = 2; // 搜索关键词,搜索时需传 string keyword = 3;}
message HistoryTabReply { // 顶部tab repeated CursorTab tab = 1;}

一元RPC模式proto实现例子

代码例子中实现了这种模式,第一步是为history服务及其HistoryTab方法创建服务定义,借助定义的proto文件就可以生成服务端代码并实现HistoryTab的逻辑。客户端比较简单,实现连接以HistoryTabReq定义为参数并远程调用HistoryTab方法从而得到HistoryTabReply的信息。


服务器端流RPC模式


在一元RPC模式中,grpc服务器端和grpc客户端在通信时始终只有一个请求和一个响应相对应。在服务器端流RPC模式,服务器端在接收到请求消息后会发回一个响应的序列,这种多个响应所组成的序列叫做流,将所有服务器端响应发送完毕之后,会以trailer元数据的形式将其状态发送给客户端,从而标记流的结束。

grpc教程(二)横向比较与grpc通信模式

服务器端流RPC模式


这意味着,客户端发出一个请求之后,可能会接收到多条响应消息。

syntax = "proto3";
package bilibili.broadcast.message.fawkes;
import "google/protobuf/empty.proto";
service Module { rpc WatchModule(google.protobuf.Empty) returns (stream ModuleNotifyReply);}
enum Action { UNKNOWN = 0; // 未知 DELETE = 1; // 删除}
message ModuleNotifyReply { Action atcion = 1; string app_key = 2; string pool_name = 3; string module_name = 4;}

服务器端流RPC模式使用stream定义流信息



客户端流RPC模式

客户端流RPC模式

在客户端流RPC模式中,客户端会发送多个请求到服务端,而不是单个请求,服务端则会发送一个回复消息给客户端。

这种处理模式下服务端可以基于自己的业务逻辑,决定是否从客户端接收到所有消息才发送响应。



双向流RPC服务


双向流RPC服务

建立连接之后,客户端和服务器端陆续发送消息实现消息的读取和写入。

在双向流RPC模式中,定义方法参数和返回参数都声明为stream,同样根据proto文件定义生成服务器端代码和客户端stub的代码。服务可在持续读取/传入消息流的同,使用recv/send方法将消息读取/写入同一个流中接收/发送。