1 含义

RPC(remote procedure call 远程过程调用)框架实际是提供了一套机制,使得应用程序之间可以进行通信,而且也遵从server/client模型。使用的时候客户端调用server端提供的接口就像是调用本地的函数一样。

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结构图。

2 定义服务

gRPC 基于如下思想:定义一个服务, 指定其可以被远程调用的方法及其参数和返回类型。gRPC 默认使用 protocol buffers 作为接口定义语言,来描述服务接口和有效载荷消息结构。如果有需要的话,可以使用其他替代方案。

service HelloService {rpc SayHello (HelloRequest) returns (HelloResponse);
}message HelloRequest {required string greeting = 1;
}message HelloResponse {required string reply = 1;
}

2.1 四种定义服务的方法

2.1.1 单项 RPC

  • 客户端发送一个请求给服务端,从服务端获取一个应答,就像一次普通的函数调用。
rpc SayHello(HelloRequest) returns (HelloResponse){
}

2.1.2 服务端流式 RPC

  • 客户端发送一个请求给服务端,可获取一个数据流用来读取一系列消息。客户端从返回的数据流里一直读取直到没有更多消息为止。
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse){
}

2.1.3 客户端流式 RPC

  • 客户端用提供的一个数据流写入并发送一系列消息给服务端。一旦客户端完成消息写入,就等待服务端读取这些消息并返回应答。
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse) {
}

2.1.4 双向流式 RPC

  • 两边都可以分别通过一个读写数据流来发送一系列消息。这两个数据流操作是相互独立的,所以客户端和服务端能按其希望的任意顺序读写,例如:服务端可以在写应答前等待所有的客户端消息,或者它可以先读一个消息再写一个消息,或者是读写相结合的其他方式。每个数据流里消息的顺序会被保持。
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse){
}

2.1.5使用 API 接口

gRPC 提供 protocol buffer 编译插件,能够从一个服务定义的 .proto 文件生成客户端和服务端代码。通常 gRPC 用户可以在服务端实现这些API,并从客户端调用它们。

  • 在服务侧,服务端实现服务接口,运行一个 gRPC 服务器来处理客户端调用。gRPC 底层架构会解码传入的请求,执行服务方法,编码服务应答。
  • 在客户侧,客户端有一个存根实现了服务端同样的方法。客户端可以在本地存根调用这些方法,用合适的 protocol buffer 消息类型封装这些参数— gRPC 来负责发送请求给服务端并返回服务端 protocol buffer 响应。

2.1.6 同步 vs 异步

同步 RPC 调用一直会阻塞直到从服务端获得一个应答,这与 RPC 希望的抽象最为接近。另一方面网络内部是异步的,并且在许多场景下能够在不阻塞当前线程的情况下启动 RPC 是非常有用的。

在多数语言里,gRPC 编程接口同时支持同步和异步的特点。你可以从每个语言教程和参考文档里找到更多内容(很快就会有完整文档)。

2.2 RPC 生命周期

现在让我们来仔细了解一下当 gRPC 客户端调用 gRPC 服务端的方法时到底发生了什么。我们不究其实现细节,关于实现细节的部分,你可以在我们的特定语言页面里找到更为详尽的内容。

2.2.1 单项 RPC

首先我们来了解一下最简单的 RPC 形式:客户端发出单个请求,获得单个响应。

  • 一旦客户端通过桩调用一个方法,服务端会得到相关通知 ,通知包括客户端的元数据,方法名,允许的响应期限(如果可以的话)
  • 服务端既可以在任何响应之前直接发送回初始的元数据,也可以等待客户端的请求信息,到底哪个先发生,取决于具体的应用。
  • 一旦服务端获得客户端的请求信息,就会做所需的任何工作来创建或组装对应的响应。如果成功的话,这个响应会和包含状态码以及可选的状态信息等状态明细及可选的追踪信息返回给客户端 。
  • 假如状态是 OK 的话,客户端会得到应答,这将结束客户端的调用。

2.2.2 服务端流式 RPC

服务端流式 RPC 除了在得到客户端请求信息后发送回一个应答流之外,与我们的简单例子一样。在发送完所有应答后,服务端的状态详情(状态码和可选的状态信息)和可选的跟踪元数据被发送回客户端,以此来完成服务端的工作。客户端在接收到所有服务端的应答后也完成了工作。

2.2.3 客户端流式 RPC

客户端流式 RPC 也基本与我们的简单例子一样,区别在于客户端通过发送一个请求流给服务端,取代了原先发送的单个请求。服务端通常(但并不必须)会在接收到客户端所有的请求后发送回一个应答,其中附带有它的状态详情和可选的跟踪数据。

2.2.4 双向流式 RPC

双向流式 RPC ,调用由客户端调用方法来初始化,而服务端则接收到客户端的元数据,方法名和截止时间。服务端可以选择发送回它的初始元数据或等待客户端发送请求。 下一步怎样发展取决于应用,因为客户端和服务端能在任意顺序上读写 - 这些流的操作是完全独立的。例如服务端可以一直等直到它接收到所有客户端的消息才写应答,或者服务端和客户端可以像"乒乓球"一样:服务端后得到一个请求就回送一个应答,接着客户端根据应答来发送另一个请求,以此类推。

2.2.5 截止时间

gRPC 允许客户端在调用一个远程方法前指定一个最后期限值。这个值指定了在客户端可以等待服务端多长时间来应答,超过这个时间值 RPC 将结束并返回DEADLINE_EXCEEDED错误。在服务端可以查询这个期限值来看是否一个特定的方法已经过期,或者还剩多长时间来完成这个方法。 各语言来指定一个截止时间的方式是不同的 - 比如在 Python 里一个截止时间值总是必须的,但并不是所有语言都有一个默认的截止时间。

2.2.6 RPC 终止

在 gRPC 里,客户端和服务端对调用成功的判断是独立的、本地的,他们的结论可能不一致。这意味着,比如你有一个 RPC 在服务端成功结束(“我已经返回了所有应答!”),到那时在客户端可能是失败的(“应答在最后期限后才来到!”)。也可能在客户端把所有请求发送完前,服务端却判断调用已经完成了。

2.2.7 取消 RPC

无论客户端还是服务端均可以再任何时间取消一个 RPC 。一个取消会立即终止 RPC 这样可以避免更多操作被执行。它不是一个"撤销", 在取消前已经完成的不会被回滚。当然,通过同步调用的 RPC 不能被取消,因为直到 RPC 结束前,程序控制权还没有交还给应用。

2.2.8元数据集

元数据是一个特殊 RPC 调用对应的信息,这些信息以键值对的形式存在,一般键的类型是字符串,值的类型一般也是字符串(当然也可以是二进制数据)。元数据对 gRPC 本事来说是不透明的 - 它让客户端提供调用相关的信息给服务端,反之亦然。 对于元数据的访问是语言相关的。

2.2.9 频道

在创建客户端存根时,一个 gRPC 频道提供一个特定主机和端口服务端的连接。客户端可以通过指定频道参数来修改 gRPC 的默认行为,比如打开关闭消息压缩。一个频道具有状态,包含已连接空闲 。 gRPC 如何处理关闭频道是语言相关的。有些语言可允许询问频道状态。

3 gRPC的优势:

  • gRPC可以通过protobuf来定义接口,从而可以有更加严格的接口约束条件。关于protobuf可以参见笔者之前的小文Google Protobuf简明教程
  • 另外,通过protobuf可以将数据序列化为二进制编码,这会大幅减少需要传输的数据量,从而大幅提高性能。
  • gRPC可以方便地支持流式通信(理论上通过http2.0就可以使用streaming模式, 但是通常web服务的restful api似乎很少这么用,通常的流式数据应用如视频流,一般都会使用专门的协议如HLS,RTMP等,这些就不是我们通常web服务了,而是有专门的服务器应用。)

4 使用场景

  • 需要对接口进行严格约束的情况,比如我们提供了一个公共的服务,很多人,甚至公司外部的人也可以访问这个服务,这时对于接口我们希望有更加严格的约束,我们不希望客户端给我们传递任意的数据,尤其是考虑到安全性的因素,我们通常需要对接口进行更加严格的约束。这时gRPC就可以通过protobuf来提供严格的接口约束。
  • 对于性能有更高的要求时。有时我们的服务需要传递大量的数据,而又希望不影响我们的性能,这个时候也可以考虑gRPC服务,因为通过protobuf我们可以将数据压缩编码转化为二进制格式,通常传递的数据量要小得多,而且通过http2我们可以实现异步的请求,从而大大提高了通信效率。

但是,通常我们不会去单独使用gRPC,而是将gRPC作为一个部件进行使用,这是因为在生产环境,我们面对大并发的情况下,需要使用分布式系统来去处理,而gRPC并没有提供分布式系统相关的一些必要组件。而且,真正的线上服务还需要提供包括负载均衡,限流熔断,监控报警,服务注册和发现等等必要的组件。不过,这就不属于本篇文章讨论的主题了,我们还是先继续看下如何使用gRPC。

5 入门实例

这次试用python代码,实现Hello World入门案例。gRPC的使用通常包括如下几个步骤:

  1. 通过protobuf来定义接口和数据类型
  2. 编写gRPC server端代码
  3. 编写gRPC client端代码

整个工程的目录如下:

5.1 配置gRPC环境

操作系统不同配置环境的方式也不同,我这次试用win10环境。先讲解如何在win10环境下的配置方法。

5.1.1 安装Protobuf

Ubuntu下执行:

pip install protobuf    # 安装protobuf库
sudo apt-get install protobuf-compiler  # 安装protobuf编译器

Win10下:

登录官网:地址,选择win64位的版本。

然后在环境变量,解压下载好的文件,然后将目录写到环境变量。我的在C:\protoc-3.17.3-win64\bin.

然后在CMD中执行:protoc --version。

到这里环境配置完成了,然后在执行:

pip install protobuf    # 安装protobuf库

安装protobuf的python库。

5.1.2 安装gprc的tools库

pip install grpcio-tools

5.1.3 定义接口

通过protobuf定义接口和数据类型。新建protos文件夹,进入里面新建helloworld.proto文件,添加下面的内容:

syntax = "proto3";
package rpc_package;
// define a service
service HelloWorldService {// define the interface and data typerpc SayHello (HelloRequest) returns (HelloReply) {}
}
// define the data type of request
message HelloRequest {string name = 1;
}
// define the data type of response
message HelloReply {string message = 1;
}

新建rpc_package文件夹,然后使用gRPC protobuf生成工具生成对应语言的库函数。生成的目录指定到rpc_package文件夹。

python -m grpc_tools.protoc -I=./protos --python_out=./rpc_package --grpc_python_out=./rpc_package ./protos/helloworld.proto

生成:helloworld_pb2.py和helloworld_pb2_grpc.py两个文件。

在rpc_package文件夹下面建个_init_.py文件,修改helloworld_pb2_grpc.py第五行为:

import rpc_package.helloworld_pb2 as helloworld__pb2

不然会出现找不到库的问题。

5.2 Server端代码和客户端代码

hello_server.py

#!/usr/bin/env python
# -*-coding: utf-8 -*-from concurrent import futures
import grpc
import logging
import time
from rpc_package.helloworld_pb2_grpc import add_HelloWorldServiceServicer_to_server,HelloWorldServiceServicer
from rpc_package.helloworld_pb2 import HelloRequest, HelloReplyclass Hello(HelloWorldServiceServicer):# 这里实现我们定义的接口def SayHello(self, request, context):return HelloReply(message='Hello, %s!' % request.name)def serve():# 这里通过thread pool来并发处理server的任务server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))# 将对应的任务处理函数添加到rpc server中add_HelloWorldServiceServicer_to_server(Hello(), server)# 这里使用的非安全接口,世界gRPC支持TLS/SSL安全连接,以及各种鉴权机制server.add_insecure_port('[::]:50000')server.start()try:while True:time.sleep(60 * 60 * 24)except KeyboardInterrupt:server.stop(0)if __name__ == "__main__":logging.basicConfig()serve()

hello_client.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-from __future__ import print_function
import loggingimport grpc
from rpc_package.helloworld_pb2 import HelloRequest, HelloReply
from rpc_package.helloworld_pb2_grpc import HelloWorldServiceStubdef run():# 使用with语法保证channel自动closewith grpc.insecure_channel('localhost:50000') as channel:# 客户端通过stub来实现rpc通信stub = HelloWorldServiceStub(channel)# 客户端必须使用定义好的类型,这里是HelloRequest类型response = stub.SayHello(HelloRequest(name='AI浩'))print ("hello client received: " + response.message)if __name__ == "__main__":logging.basicConfig()run()

5.3 运行

先执行server端代码

python hello_server.py

然后执行client端

python hello_client.py

运行结果:

hello client received: Hello, AI浩!

参考文章:

gRPC详解 - 简书 (jianshu.com)

高质量通信gRPC入门,有了它,谁还用Socket相关推荐

  1. 【Java从入门到天黑|06】高质量男性SpringBoot入门及原理(基础总结版,强烈建议收藏)

    目录 SpringBoot简介 Spring是为了解决企业级应用开发的复杂性而创建的,简化开发. helloWorld

  2. 劳资蜀道山!6个高质量免费电子书网站!我看谁还不知道

    如今,电子书轻便海量的良好移动式体验受到广大年轻读者的喜爱.但是很多人也发现,有些电子书网站很贵,某些书籍还搜不到.今天,就给大家推荐6个电子书网站,不仅免费,而且品类丰富,能帮你找到99%的电子书. ...

  3. SEO网络优化三招教你高质量外链的技巧

    网站就是企业品牌的形象,无论是大型还是小型企业网站都是想让网站获取更多的用户流量,进而转化为效益.很多网络优化小白在这方面很容易忽略掉外链的建设,更不理解外链到底有什么作用.但是对于网站来说,打造高质 ...

  4. 浅析SEO网站优化的三点高质量外链优化技巧

    网站就是企业品牌的形象,无论是大型还是小型企业网站都是想让网站获取更多的用户流量,进而转化为效益.很多网络优化小白在这方面很容易忽略掉外链的建设,更不理解外链到底有什么作用.但是对于网站来说,打造高质 ...

  5. 深兰科技机器人商丘制造基地正式投产,助力商丘经济高质量发展

    2月9日,深兰科技机器人商丘制造基地投产仪式在商丘市梁园区北航创新园隆重举行. 商丘市人大常委会副主任.梁园区委书记张兵,梁园区区长薛天江.河南省装备制造业协会会长张桦,河南省机器人行业协会会长王济昌 ...

  6. 林锐 高质量c语言编程下载,新年献礼:Go语言深度入门手册

    (文末的阅读原文,效果最佳!) 作者:李佶澳 微信:lijiaocn Go 语言深度入门手册,帮你更好的理解 Go 语言,写出更高效.更规范.更不易出错的代码. Go 在 2012 年发布 1.0 版 ...

  7. [技术发展-28]:信息通信网大全、新的技术形态、信息通信行业高质量发展概览

    目录 前言: 第1章 什么是信息与通信 第2章 为啥要编制信息与通信发展规划 第3章 信息与通信如何高质量发展(重点) 3.0 发展目标​编辑 3.1 建设新型数字基础设施 3.1.1 移动通信网(无 ...

  8. Midjourney入门指南:简单提示词,搞定高质量应用设计

    Midjourney是一款文本到图像的AI工具,可以根据纯文本描述生成图片,例如UI屏幕.应用程序图标.产品图片.标志和吉祥物等.虽然它不能替代UI设计师,但它可以在产品设计和视觉探索的早期阶段成为有 ...

  9. 【C语言快速入门】三万字+高质量教学

    写在前面: 简单介绍一下本篇文章的主要目的: 是让新手玩家快速认识并了解C语言基础内容和语法结构,并没有深入去探究,让大家对C语言有个大概且全面的认识. 相信我,这篇文章虽然很长,但不会让你从入门到入 ...

  10. 《大数据》入选2020年度《信息通信领域高质量科技期刊分级目录》

    点击上方蓝字关注我们 在中国科协的统一部署下,中国通信学会开展2020年度<信息通信领域高质量科技期刊分级目录>(以下简称"期刊目录")的认定与发布工作,面向对象为国内 ...

最新文章

  1. Windows 7 状态栏图标消失恢复
  2. Linux下SVN服务器同时支持Apache的http和https及svnserve独立服务器三种模式且使用相同的访问权限账号...
  3. 蛋花花:互联网正在告别青春期
  4. GC DevKit 快速入门 -- 游戏概览(三)
  5. CentOS 7 + Hadoop3 伪分布式集群配置
  6. linux 设置中文版man手册
  7. VMware Workstation虚拟机“”繁忙——解决方案
  8. linux 管道 top,linux IPC总结——管道
  9. 【Elasticsearch】Elasticsearch mapping 映射对象
  10. AE “每用户订阅上的所有人SID 不存在”
  11. 互联网企业:如何建设数据安全体系?
  12. 1500页,40万字,阿里淘系技术2020技术年货来了!
  13. Eclipse汉化教程2021新版
  14. 陶教授,我记不住定理的证明该怎么办?(我看到陶哲轩在博客上与学生一则有意思的互动,就翻译过来了)...
  15. python 解决transform.rescale操作,本应得到彩色图像,然而所得图像为灰色图像问题
  16. matlab 画三维图像
  17. java定时器Scheduled,可动态设置定时器执行时间
  18. 图片采集-输入关键词批量收集图片免费
  19. 头歌HTML实训笔录
  20. 利用vlan交换机(网管交换机)打trunk实现单线复用

热门文章

  1. 成功解决FAT32 No GRLDR问题
  2. 中国工程院院士倪光南:拥抱开源 与世界协同创新
  3. hadoop中HDFS的NameNode原理
  4. winxp笔记本和有线路由器通过网线连接情况下的设置方法
  5. n维线性空间上的几何:直线与平面的方程
  6. php设置北京时间(时区)
  7. 2021中国科技大学计算机博士招生,中国科学技术大学2021年拟录取博士研究生名单公示,2661人!...
  8. pandas按条件筛选数据
  9. uniapp 无法获取动态dom节点,解决方案
  10. 如何用亿图软件绘制甘特图