gRPC介绍

酱橙

简介

gRPC 是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提供 C、Java 和 Go 语言版本,分别是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHP 和 C# 支持。

gRPC 基于 HTTP/2 标准设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。

gRPC 是什么?

在 gRPC 里 客户端 应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法,使得您能够更容易地创建分布式应用和服务。与许多 RPC 系统类似,gRPC 也是基于以下理念:定义一个服务,指定其能够被远程调用的方法(包含参数和返回类型)。在服务端实现这个接口,并运行一个 gRPC 服务器来处理客户端调用。在客户端拥有一个 stub(存根)能够像服务端一样的方法。

图1

gRPC 客户端和服务端可以在多种环境中运行和交互 - 从 google 内部的服务器到你自己的笔记本,并且可以用任何 gRPC 支持的语言来编写。所以,你可以很容易地用 Java 创建一个 gRPC 服务端,用 Go、Python、Ruby 来创建客户端。此外,Google 最新 API 将有 gRPC 版本的接口,使你很容易地将 Google 的功能集成到你的应用里。

使用 protocol buffers

gRPC 默认使用 protocol buffers,这是 Google 开源的一套成熟的结构数据序列化机制(当然也可以使用其他数据格式如 JSON)。正如你将在下方例子里所看到的,你用 proto files 创建 gRPC 服务,用 protocol buffers 消息类型来定义方法参数和返回类型。你可以在 框架协议篇章 中找到更多关于 Protocol Buffers 的资料。

下面是 protobuf 的一个简单的例子:

message Person {
  string name = 1;
  int32 id = 2;
  bool has_ponycopter = 3;
}

当我们调用命令行来将上面的 protobuf 文件转化为 Python 代码后,此时将会生成一个 Person 类,然后对其进行实例化和字段的填充。

注意:

这里最好使用 proto3 版本,相对于 proto2, 新版本的 protobuf 定义更加简单,并且支持性更加完善。

参考文档:gRPC 官方文档中文版

gRPC 的定义

gRPC 通过 Protocol Buffer 来规定客户端调用服务端的接口数据结构和发送的消息内容:

service HelloService {
  rpc SayHello (HelloRequest) returns (HelloResponse);
}

message HelloRequest {
  string greeting = 1;
}

message HelloResponse {
  string reply = 1;
}

gRPC 的定义有以下几种方式:

  • 一元 RPC,类似于普通的方法调用,发送一个请求,然后服务端返回一个响应:
rpc SayHello(HelloRequest) returns (HelloResponse);
  • 服务端流式 RPCs:客户端发送一个请求,并获得一个流式响应的信息,客户端不停的进行读取,直到全部读取完毕。gRPC 通过单独的调用实现了保证了消息的排序。
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);
  • 客户端流式 RPCs:客户端发送一个流式的消息请求,当客户端完成所有字节流的发送后,等待服务端完成消息的读取并返回响应信息。同样的,也是通过单独的调用来保证消息的顺序。
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);
  • 双向流式 RPCs:客户端和服务端都通过读取和发送字节流来发送消息序列。两个字节流的操作都是独立的,因此客户端和服务器可以自定义消息顺序。而服务端对于消息的收发也可以交替执行。每个消息的顺序在底层都进行了保存。
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);

RPC 的生命周期

不同类型的 RPC 流程

一元 RPC

首先我们先看看 最简单的 RPC 流程是如何的:

1. 当客户端调用了 stub 方法时,通知服务端对指定接口的调用,告诉服务端对应的方法名并指定过期时间(非必要)。

2. 服务端此时可以发送响应数据前发送的 metadata(该数据必须在 response 之前被发送),或者等待所有的消息都被接收到了。对于该流程的指定,我们可以通过程序来进行自定义。

3. 当服务端获取了所有的请求信息,若调用的整个过程没有抛出异常,此时将返回 response,并根据程序设定,返回尾部 metadata。

服务端流式 RPC

类似于上述的 一元RPC,不同点是服务端返回的消息为流式响应。在发送完所有的响应信息与状态信息(状态码以及其它相关信息)之后,会返回尾部 metadata。此时服务端完成响应。而客户端的响应完成需要在其接收完所有的响应信息。

客户端流式 RPC

客户端流式 RPC 也类似于 一元 RPC,不同点就是客户端通过发送流式消息来进行请求。而服务端通过返回单一形式的消息来完成响应。

双端流式 RPC

双端流式 RPC 中,客户端和服务端都采用流式的消息进行收发。

此时客户端和服务端对于消息的处理需要程序自身进行指定。两个流式 message 相互独立,因此可以自定义消息处理流程。例如,服务端可以在接收完所有的流式信息后再去返回响应信息;或者服务端和客户端都进行 ping-pong 的响应:服务端在接收到流式请求的时候马上进行响应,然后客户端在接收到响应后再继续逻辑上的处理并继续发送请求。

目前来说,这个看起来比较好使

RPC 的结束阶段

截止时间和超时响应

gRPC 允许客户端指定响应的超时时间,并在超时的时候抛出DEADLINE_EXCEEDED的异常。对于 server 端方面,服务端可以查询指定的 RPC 是否超时响应,或者是说离超时响应的时间还有多久。

RPC 的 termination 情况

当我们完成了一个响应的时候,服务端表示:我已经完成了所有字节流的发送,但是客户端却说自己没有成功接收到响应信息。这可能是因为客户端还没发送完毕,服务端已经认为整个请求的流程已经结束了。

取消 RPC 流程

我们也可以在任何不开心的时候,直接把这个流程给关了。o(* ̄▽ ̄*)ブ

相关概念说明

Metadata

Metadata 是针对特定某个 RPC 的响应信息(例如 安全认证信息),该字段以 key-value 作为自身的数据结构。

Chanels

gRPC 通过管道来进行服务端和客户端的连接。客户端可以指定参数来对 gRPC 的默认行为进行更改,例如是否对消息进行压缩。管道同样有其对应的状态: connected(正在连接中)或 idle(空闲状态)。

阅读 334

爱唠嗑的程序员

1 声望
0 粉丝
0 条评论
你知道吗?

爱唠嗑的程序员

1 声望
0 粉丝
文章目录
宣传栏