gRPC知识归档

文章目录

  • gRPC知识归档
    • gRPC原理
      • 什么是gRPC
      • gRPC的特性
      • gRPC支持语言
      • gRPC使用场景
      • gRPC设计的动机和原则
    • 数据封装和数据传输问题
      • 网络传输中的内容封装和数据体积问题
      • JSON
      • Protobuf(微服务之间的服务器调用,一般采用二进制序列化,比如protobuf)
      • 网络传输效率问题
    • gRPC的4种模式
      • 一元RPC模式
      • 服务端流RPC模式
      • 客户端流RPC
      • 双向流RPC模式
    • gRPC同步异步
      • gRPC调用关系图
      • proto文件
      • Client
      • server
      • 异步相关概念
        • 异步Client
        • 异步Server
        • 关系图

gRPC知识归档

gRPC原理

什么是gRPC

RPC是远程调用协议(Remote Procedure Call Protocol),可以让我们像调用本地对象一样发起远程调用。RPC凭借强大的治理功能,成为解决分布式系统问题的一大利器。
gRPC是一个现代的,高性能的,开源的和语言无关的通用RPC框架,HTTP2协议设计,序列化使用PB(Protocol Buffer)高性能序列化框架,基于HTTP2+PB保证高性能。

在这里插入图片描述

gRPC的Server和Client工作流程大致如下:

在这里插入图片描述

  • tars兼容grpc
  • brpc也兼容grpc
  • grpc不兼容tars和brpc

gRPC的特性

  1. gRPC基于服务的思想:定义一个服务,描述这个服务的方法和出入参数,服务端有这个服务的具体实现,客户端保有一个存根,提供与服务端相同的服务。
  2. gRPC默认采用protobuf作为IDL(Interface Description)接口描述语言,服务之间通信数据序列化和反序列化也是基于protocol buffer的,因为protocol buffer的特殊性,所以gRPC框架是跨语言的通信框架,可就是说用jave开发的gRPC服务,可以用GoLang,C++等语言调用。
  3. gRPC同时支持同步和异步调用,同步RPC调用会一直阻塞到服务端处完成返回数据,异步RPC是客户端调用服务端时不等待服务端处理完成返回结果,而是服务端处理完成后主动回调客户端高速客户端处理完成。
  4. gRPC是基于HTTP2.0协议实现的,http2提供了很多新特性,并且在性能上相比http1提高了许多,所以gRPC的性能是非常好的。
  5. gRPC并没有直接实现负载均衡和服务发现的功能,但是已经提供了自己的设计思路。已经为命名解析和负载均衡提供了接口。
  6. 基于http2的协议特性,gRPC允许自定义4类服务方法
    • 一元RPC
    • 服务端流式RPC
    • 客户端流式RPC
    • 双向流式RPC

gRPC支持语言

C++,Java(包括安卓),OC,Python,Ruby,Go,C#,Node.js。

gRPC使用场景

  1. 低延迟,高可扩展性的分布式系统
  2. 开发与云服务器的客户端
  3. 设计一个准确,高效,与语言无关的新协议
  4. 分层设计,实现扩展,例如:身份验证,负载平衡,日志记录和监控。

gRPC设计的动机和原则

  1. 自由,开放:所有人,所有平台都可以使用,开源,跨平台,跨语言
  2. 协议可插拔:不同的服务需要使用不同的消息类型和编码机制,例如,JSON,XML和Thirft,所以协议应允许可插拔机制,还有负载均衡,日志,监控等都支持可插拔机制。
  3. 阻塞和非阻塞:支持客户端和服务器交换的消息序列的异步和同步处理。
  4. 取消和超时:一次RPC操作可能是持久并且昂贵的,应该允许客户设置取消RPC通信和对这次通信加上超时时间。
  5. 拒绝:必须允许服务器通过在继续处理请求的同时拒绝新请求的到来并且优雅地关闭
  6. 流处理:存储系统依靠流和流控制来表达大型数据集,其他服务,如语音到文本或者股票行情,依赖流来表达与时间相关的消息序列。
  7. 流控制:计算能力和网络容量在客户端和服务器之间通常是不平衡的。流控制允许更好的缓冲区管理,以及过度活跃的对等提供DOS保护。
  8. 元数据交换:认证或跟踪常见的跨领域问题依赖于不属于服务器的接口数据交换。依赖他们的将这些特性演进到服务,暴露API来提供能力。
  9. 标准化状态骂:客户端通常以有限的方式相应API调用返回的错误。应约束状态码名称空间,以使这些错误处理决策更加清晰。如果需要更加丰富的特定领域的状态,则可以使用元数据交换机制来提供状态。
  10. 互通性:报文协议必须遵循普通互联网服务基础框架

数据封装和数据传输问题

网络传输中的内容封装和数据体积问题

早期的RPCJSON的方式,目前的RPC基本上都采用类似的Protobuf的二进制序列化方式。
其差别在于:json的设计是给人看的,protobuf的设计是给机器看的

JSON

优点:在body中对JSON内容编码,极易跨语言,不需要约定特定的复杂编码格式和Stub文件。在版本兼容性上很好,扩展容易。
缺点:JSON难以表达复杂的参数类型,如结构体等;数据冗余和低压缩率使得传输特性能差。

Protobuf(微服务之间的服务器调用,一般采用二进制序列化,比如protobuf)

// XXXX.proto
// rpc服务的类 service关键字, Test服务类名
service Test {
// rpc 关键字,rpc的接口
	rpc HowRpcDefine (Request) returns (Response) ; // 定义一个RPC方法
}
// message 类,c++ class
message Request {
//类型 | 字段名字| 标号
	int64 user_id = 1;
	string name = 2;
}
message Response {
	repeated int64 ids = 1; // repeated 表示数组
	Value info = 2; // 可嵌套对象
	map<int, Value> values = 3; // 可输出map映射
}
message Value {
	bool is_man = 1;
	int age = 2;
}

网络传输效率问题

grpc采用HTTP2.0,相对于HTTP1.0在更快的传输更低的成本上做了改进。有一下几个基本点:

  1. HTTP2未改变HTTP的语义(如GET/POST等),只是在传输上优化
  2. 引入帧,流的概念,在TCP连接中,可以区分多个request和response
  3. 一个域名只会有一个TCP连接,借助帧,流可以实现多路复用,降低资源消耗
  4. 引入二进制编码,降低header带来的空间占用
  • HTTP1.1核心问题在于:在同一个TCP连接中,没办法区分response是属于哪个请求,一旦多个请求返回的文本内容混在一起,则没法区分数据归属于哪个请求,所以请求只能一个个串行排队发送。这直接导致了TCP资源的闲置。
  • HTTP2为了解决这个问题,提出了 流 的概念,每一次请求对应一个流,有一个唯一ID,用来区分不同的请求。基于流的概念,进一步提出了 帧 ,一个请求的数据会被分成多个帧,方便进行数据分割传输,每个帧都唯一属于某一个流ID,将帧按照流ID进行分组,即可分离出不同的请求。这样同一个TCP连接中就可以同时并发多个请求,不同请求的帧数据可穿插在一起,根据流ID分组即可。HTTP2.0基于这种二进制协议的乱序模式 (Duplexing),直接解决了HTTP1.1的核心痛点,通过这种复用TCP连接的方式,不用再同时建多个连接,提升了TCP的利用效率。

在这里插入图片描述

gRPC的4种模式

一元RPC模式

一元RPC模式也被称为简单RPC模式,当客户端调用服务端的远程方法时,客户端发送请求到服务端并且获取一个响应,与响应一起发送的还有状态细节以及trailer元数据。

在这里插入图片描述

服务端流RPC模式

在服务器端流RPC模式中,服务器端在接受到客户端额请求消息后,会发回一个响应的序列。这种多个响应所组成的序列被称为。在将所有的服务器端响应发送完毕之后,服务器端会以trailer元数据的形式将其状态发送给客户端,从而标记流结束。

在这里插入图片描述

客户端流RPC

在客户端流 RPC 模式中,客户端会发送多个请求给服务器端,而不再是单个请求。服务器端则会发送一个响应给客户端。但是,服务器端不一定要等到从客户端接收到所有消息后才发送响应。基于这样的逻辑,我们可以在接收到流中的一条消息或几条消息之后就发送响应,也可以在读取完流中的所有消息之后再发送响应。

在这里插入图片描述

双向流RPC模式

在双向流RPC模式中,客户端以消息流的形式发请求给服务端,服务端也以消息流的形式响应。调用必须有客户端发起,但在此之后,通信完全基于gRPC客户端和服务端的应用程序逻辑。

在这里插入图片描述

gRPC同步异步

gRPC调用关系图

在这里插入图片描述

上图列出了gRPC基础概念及其关系图。其中包括:Service(定义)、RPC、API、Client、Stub、Channel、Server、Service(实现)、ServiceBuilder等。

接下来,以官方提供的example/helloworld为例说明。

proto文件

syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";

package helloworld;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

Client

class GreeterclientClient,是对Stub封装;通过Stub可以真正调用RPC请求。

class GreeterClient {
 public:
  GreeterClient(std::shared_ptr<Channel> channel)
      : stub_(Greeter::NewStub(channel)) {}

  // Assembles the client's payload, sends it and presents the response back
  // from the server.
  std::string SayHello(const std::string& user) {
    // Data we are sending to the server.
    HelloRequest request;
    request.set_name(user);

    // Container for the data we expect from the server.
    HelloReply reply;

    // Context for the client. It could be used to convey extra information to
    // the server and/or tweak certain RPC behaviors.
    ClientContext context;

    // The actual RPC.
    Status status = stub_->SayHello(&context, request, &reply);

    // Act upon its status.
    if (status.ok()) {
      return reply.message();
    } else {
      std::cout << status.error_code() << ": " << status.error_message()
                << std::endl;
      return "RPC failed";
    }
  }

 private:
  std::unique_ptr<Greeter::Stub> stub_;
};

Channel提供一个特定gRPC server的主机和端口简历的连接。
Stub就是在Channel的基础上创建而成。

target_str = "localhost:50051";
auto channel = 
	grpc::CreateChannel(target_str, grpc::InsecureChannelCredentials());
GreeterClient greeter(channel);
std::string user("world");
std::string reply = greeter.SayHello(user);

server

Server端需要实现对应的RPC,所有的RPC组成了Sevice

// Logic and data behind the server's behavior.
class GreeterServiceImpl final : public Greeter::Service {
  Status SayHello(ServerContext* context, const HelloRequest* request,
                  HelloReply* reply) override {
    std::string prefix("Hello ");
    reply->set_message(prefix + request->name());
    return Status::OK;
  }
};

Server的创建需要一个Builder,添加上监听的地址和端口,注册上该端口上绑定的服务,最后构建出Server并且启动。

ServerBuilder builder;
  // Listen on the given address without any authentication mechanism.
  builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
  // Register "service" as the instance through which we'll communicate with
  // clients. In this case it corresponds to an *synchronous* service.
  builder.RegisterService(&service);
  // Finally assemble the server.
  std::unique_ptr<Server> server(builder.BuildAndStart());

RPC和API的区别:RPC(Remote Procedure Call)是一次远程过程调用的整个动作,而API(Application Programming Interface)是不同语言实现RPC中的具体接口。一个RPC可能对应多种API,比如同步的,异步的,回调的。

异步相关概念

不管Client还是Server,异步gRPC都是利用CompletionQueue API进行异步操作。基本流程:
- 绑定一个CompletionQueue到一个RPC调用
- 利用唯一的void* Tag进行读写
- 调用CompletionQueue::Next()等待操作完成,完成后通过唯一的Tag来判断对应什么请求/返回进行后续操作

异步Client

greeter_async_client.cc中是异步Client的Demo,其中只有一次请求,逻辑简单

  • 创建CompletionQueue
  • 创建RPC(即clientAsyncResponseReader<HelloReply>),这里有两种方式:
    • stub_->PrepareAsyncSayHello() + rpc->StartCall()
    • stub_->AsyncSayHello()
  • 调用rpc->Finish()设置请求消息reply和唯一的tag关联,将请求发送出去。
  • 使用cq.Next()等待Completion Queue返回响应消息体,通过tag关联对应请求。
异步Server

RequestSayHello()这个函数没有任何说明。只是说:“we request that the system start processing SayHello requset.”也没有说和cq_->Next(&tag, &ok);的关系。我来说一下流程:
- 创建一个CallData,初始构造列表中将状态设置为CREATE
- 构造函数中,调用Process()成员函数,调用service_->RequestSayHello()后,状态变更为PROCESS:
- 传入ServerContext ctx_
- 传入HelloRequest request_
- 传入ServerAsyncResponsewriter<HelloReply> responder_
- 传入ServerCompletionQueue* cq_
- 将对象自身的地址作为tag传入
- 该动作,能将事件加入事件循环,可以在CompletionQueue中等待
- 收到请求,cp->Next()的阻塞结束并且返回,得到tag,即上次传入的CallData对象
- 调用tag对应CallData对象Process(),此时状态Process
- 创建新的CallData对象以接受新请求
- 处理消息并且设置reply_
- 将状态设置为FINISH
- 调用responder_.Finish()将返回发送给客户端
- 该动作,能将事件加入到循环,可以将CompletionQueue中等待
- 发送完毕,cp->Next()的阻塞结束并且返回,得到tag。现实中,如果发送有异常应当有其他处理。
- 调用tag对应的CallData对象proceed,此时状态为FINISHdelete this清理自己,一条消息处理完成。

关系图

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/418088.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

TVM 和模型优化的概述(1)

文章目录 1. 从 Tensorflow、PyTorch 或 Onnx 等框架导入模型&#xff08;model&#xff09;。2.翻译成 Relay3. lower 到 张量表达式。4. 使用 auto-tuning 模块 AutoTVM 或 AutoScheduler 搜索最佳 schedule。5. 选择最佳配置进行模型编译。6. lower 到 TIR。7. 编译成机器码…

计算机网络:数据链路层知识点汇总

文章目录 一、数据链路层功能概述二、封装成帧和透明传输三、差错控制&#xff08;检错编码&#xff09;四、差错控制&#xff08;纠错编码&#xff09;五、流量控制与可靠传输机制六、停止-等待协议七、后退N帧协议&#xff08;GBN&#xff09;八、选择重传协议&#xff08;SR…

SAP PP学习笔记04 - BOM1 - BOM创建,用途,形式,默认值,群组BOM等

本章开始讲BOM的内容。 1&#xff0c;BOM的定义 &#xff08;Bill of Materials&#xff09; 物料清单&#xff08;Bill of Materials&#xff0c;简称BOM&#xff09;是描述企业产品组成的技术文件。在加工资本式行业&#xff0c;它表明了产品的总装件、分装件、组件、部件、…

小程序固定头部实现:van-nav-bar插件

用的是Vant的NavBar插件&#xff1a; https://youzan.github.io/vant-weapp/#/nav-bar#wai-bu-yang-shi-lei 效果图 页面使用&#xff0c;放开注释的地方就可以显示左边按钮 <van-nav-bar title"精益成本核算" fixed"true" placeholder"true&qu…

Vmware Esxi 部署Mac OS虚拟机

Vmware Esxi在创建虚拟机的时候是有Mac OS选项的&#xff0c;但是实际创建时&#xff0c;选择ISO开机后一直反复引导&#xff0c;是有问题的&#xff0c;原因是需要先解锁&#xff0c;需要在ESXI主机上修改配置并重启。 首先找到管理-服务-TSM-ssh&#xff0c;点击启动&#x…

SecureCRT for Mac/win:保障数据安全的专业终端SSH工具软件

SecureCRT for Mac/win是一款广受欢迎的专业终端SSH工具软件&#xff0c;为用户提供了强大的加密通信和数据安全功能&#xff0c;使其成为网络管理人员、系统管理员和开发人员的首选工具。无论是在Mac还是Windows操作系统下&#xff0c;SecureCRT都能够帮助用户轻松地进行远程访…

数字生活的未来:Web3如何改变我们的日常

随着技术的飞速发展&#xff0c;我们的生活正变得日益数字化。而Web3作为一种新型的互联网模式&#xff0c;正以前所未有的方式改变着我们的日常生活。在本文中&#xff0c;我们将深入探讨Web3技术的特点以及它如何改变我们的数字生活。 1. Web3的特点 Web3是基于区块链技术和…

uniapp 部署h5,pdf预览

1.hubuilderx 打包h5。 2.上传部署包到服务器。 解压部署包&#xff1a;unzip h5.zip 。 3.nginx配置。 user root; worker_processes 1; #worker_cpu_affinity 0001 0010 0100 1000; #error_log logs/error.log; #error_log logs/error.log notice; error_log /var/l…

ChatGPT-4 AI 绘图魔力释放

最近刚开通了 ChatGPT4&#xff0c;正好要设计一个网站图标&#xff0c;想测试一下它AI绘图的能力&#xff0c;让它根据文字描述生成一个想象中的图标 &#xff08;PS&#xff1a;如果想体验 GPT4 文生图&#xff0c;可以看这个教程 如何升级 ChatGPT 4.0&#xff09; 第1次交…

nginx使用详解--动静分离

什么是动静分离&#xff1f; 为了提高网站的响应速度&#xff0c;减轻程序服务器&#xff08;Tomcat&#xff0c;Jboss等&#xff09;的负载&#xff0c;对于静态资源&#xff0c;如图片、js、css等文件&#xff0c;可以在反向代理服务器中进行缓存&#xff0c;这样浏览器在请…

react使用@reduxjs/toolkit和react-redux实现store状态管理

一、概述 reduxjs/toolkit和react-redux是用于在React应用中管理全局状态的工具库 1、reduxjs/toolkit&#xff1a; reduxjs/toolkit是Redux官方推荐的工具库&#xff0c;是对 Redux 的二次封装&#xff0c;它提供了一些便捷的API和工具&#xff0c;帮助开发者更快速地编写R…

喜迎乔迁,开启新章 ▏易我科技新办公区乔迁庆典隆重举行

2024年1月18日&#xff0c;易我科技新办公区乔迁庆典在热烈而喜庆的氛围中隆重举行。新办公区的投入使用&#xff0c;标志着易我科技将以崭新姿态迈向新的发展阶段。 ▲ 易我科技新办公区 随着公司业务的不断发展和壮大&#xff0c;为了更好地适应公司发展的需要&#xff0c;…

mysql python学习笔记

mysql 基础概念 1.一个表格一般包含一个主建 2.可有多个主见,叫组合主见 3.可以有foreign key 用于链接外部表格的主建 外键目的&#xff1a; 这个约束的目的是确保当前表中的外键列&#xff08;JNO列&#xff09;的值必须存在于另一个表&#xff08;J’表&#xff09;的主键…

kswapd0挖矿病毒攻击记录

文章目录 一、起因与病毒分析1、起因2、阿里云告警2.1 恶意脚本代码执行12.2 恶意脚本代码执行22.3恶意脚本代码执行32.4 恶意脚本代码执行4 3、病毒简单分析3.1 病毒的初始化3.2 病毒本体执行 4、总结 二、ubuntu自救指南1、病毒清理2、如何防御 一、起因与病毒分析 1、起因 …

蓝桥杯 信号覆盖

遍历每一个坐标轴上的点&#xff0c;带入圆的方程&#xff0c;看是否在圆内或圆上 #include<bits/stdc.h> using namespace std; int main() {int w,h,n,r,i,j,k,s,ans0;cin>>w>>h>>n>>r;int x[n1],y[n1];for(i0;i<n;i){cin>>x[i]>&…

什么是前端框架中的数据绑定(data binding)?有哪些类型的数据绑定?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

Linux读写锁相关函数及操作

读写锁&#xff1a; 概念&#xff1a;读写锁也叫共享-独占锁。当读写锁以读模式锁住时&#xff0c;它是以共享模式锁住的&#xff1b;当它以写模式锁住时&#xff0c;它是以独占模式锁住的。&#xff08;写独占&#xff0c;读共享&#xff09;。 读写锁使用场所&#xff1a; …

基于PHP的在线英语学习平台

有需要请加文章底部Q哦 可远程调试 基于PHP的在线英语学习平台 一 介绍 此在线英语学习平台基于原生PHP开发&#xff0c;数据库mysql。系统角色分为学生&#xff0c;教师和管理员。(附带参考设计文档) 技术栈&#xff1a;phpmysqlphpstudyvscode 二 功能 学生 1 注册/登录/…

编译 qsqlmysql.dll QMYSQL driver not loaded

Qt 连接MySQL数据库&#xff0c;没有匹配的qsqlmysql.dll, 需要我们跟进自己Mysql 以及QT版本自行编译的。异常如下图&#xff1a; 安装环境为 VS2019 Qt5.12.12&#xff08;msvc2017_64、以及源码&#xff09; 我的安装地址&#xff1a;D:\Qt\Qt5.12.12 Mysql 8.1.0 默认安…

【Kotlin】函数

1 常规函数 1.1 无参函数 fun main() {myFun() }fun myFun() {println("myFun") // 打印: myFun } 1.2 有参函数 1&#xff09;常规调用 fun main() {myFun("myFun") // 打印: myFun }fun myFun(str: String) {println(str) } 2&#xff09;形参指定默…