RPC框架底层原理与gRPC的学习 | 豆包MarsCode AI刷题

74 阅读7分钟

一、RPC概念

1)本地与远程函数调用:

  • 本地函数调用的流程:根据函数指针找到该函数并执行

image-20241114152738296

  • 远程函数调用:主要考虑三个问题

image-20241114153036956

2)RPC概念模型:

  • ==RPC过程的五个模型==:

image-20241114162502275

  • 底层细节:

image-20241114162656775

3)RPC的好处与问题:

  • 好处:单一职责、故障隔离

image-20241114162818131

  • 问题:所以需要RPC框架来解决这些问题

image-20241114162854429

二、RPC的分层设计

1)层次结构:以Thrift为例

image-20241114163317110

2)编解码层:

  • 依赖同一份IDL文件生成代码

image-20241114163405028

  • 生成数据的格式:如二进制编码

image-20241114163504573

  • 例:TLV编码,一种二进制编码

image-20241114163604890

3)协议层:

  • 在编解码时,不单单要考虑元数据,还需要指定协议等其他内容,所以需要协议层

  • 语法规则:以特殊结束符作为协议单元结束 / 在协议单元前规定内容长度

image-20241114163941420

  • 例:变长协议的构造

image-20241114164114133

  • 协议解析的过程:

image-20241114164418367

4)网络通信层:

image-20241114164554659

image-20241114164532769

三、稳定性

1)保障策略:

  • 熔断、限流、超时控制:
image-20241114173138098
  • 负载均衡、重试机制:保障请求成功率

image-20241114173600935

  • 长尾请求:规定响应的时间,超时重试,而不是返回false时重试

image-20241114174324015

2)执行方法:

image-20241114174635933

gRPC的学习:

  • gRPC:

一、基本概念1)介绍gRPC:简介、对比老技术、好处2)细说HTTP协议:1.0、1.1、2.0 <扩展>3)Protocol Buffers:一种中间语言二、protobuf基本语法1)一些概念:版本设定、注释2)与Java相关的语法:一些基本配置3)基本语法:数据类型、枚举、消息三、简单gRPC开发案例1)项目模块:api、server(服务端)、client(客户端)2)①api模块:书写IDL -> 准备编译* 书写IDL:* 安装gRPC插件(一次性):帮助编译为Java并放在IDEA中* 进行编译:执行两个命令生成两个类 <过>* 优化编译:合成两个命令 + 改文件位置* 补充:细说生成的两个java类的构成3)②server(服务端)模块4)③client(客户端)模块* 增加repeated关键字情况:<补充>四、gRPC的四种通信方式1)四种通信方式:2)①简单RPC(一元RPC):最常见3)②服务端流式RPC:* 阻塞方式:不常见* 异步监听方式:4)③客户端流式RPC:5)④双向流式RPC:五、gRPC代理方式:<过>六、整合SpringBoot:<未完待续>1)服务端:


一、基本概念

1)介绍gRPC:简介、对比老技术、好处

  • 一、简介:用的协议是HTTP2协议 -> 二进制的序列化(protobuf)

image-20240627193248655

  • 二、与另一个RPC框架 Thrift 的对比:<过>

image-20240628143730280

  • 三、gRPC的好处:原生Java语言实现

image-20240628144242487

2)细说HTTP协议:1.0、1.1、2.0 <扩展>

  • 一、HTTP1.0协议:
  • 补充:HTTP协议底层是基于TCP协议的,而TCP协议是长连接协议,只是HTTP协议主动切断了连接(因为早期技术和硬件的问题,没有能力支持长连接,在现在不存在这种问题)

image-20240628145646735

  • 二、HTTP1.1协议:实现了有限的长连接 -> 有限地实现双工(本质原因是升级成webSocket的协议)
  • HTTP1.x协议:(更改:图中,第一次应该是html数据,后两次是静态数据即css、js数据)

image-20240628151057132

  • 三、HTTP2.0协议:二进制协议、双工、长连接(stream数据流、message消息、帧frame(frame即请求头、请求体))

image-20240628152153402

image-20240628152424325

3)Protocol Buffers:一种中间语言

  • 一、简介:

image-20240628152912939

  • 二、protobuf编译器的安装:
  • 注意:在github下载,低版本才有适配windows

image-20240628153252027

  • 三、IDEA安装提示protobuf的插件:2021.2版本之后IDEA原生就支持(不用装)

image-20240628153516828

二、protobuf基本语法

1)一些概念:版本设定、注释

  • 写代码之前需要设定版本:2 / 3

image-20240628210846051

2)与Java相关的语法:一些基本配置

  • 一、多个 / 一个源文件、生成包的名字、外部类的名字

image-20240628211759545

  • 二、补充:了解一下逻辑包 <过>

image-20240628211953634

  • 三、导入:import

image-20240628212248939

  • 四、代码示例:IDEA

image-20240628212642041

3)基本语法:数据类型、枚举、消息

  • 一、先回顾一下,gRPC是用来干嘛的:

image-20240628213209858

  • 二、proto类型:
  • 补充:“ uint ”为无符号

image-20240628215156342

  • 三、枚举:

image-20240628221715417

  • 四、消息(类似于C的结构体struct):
  • 1 / 2 / 3:编号,表示在消息中的第几个字段

image-20240628222504556

  • 可以定义多个消息,消息可以嵌套:

image-20240628223351710

  • oneof:<了解>

image-20240628223613966

  • 五、服务:其中有服务的方法

image-20240628224022305

三、简单gRPC开发案例

1)项目模块:api、server(服务端)、client(客户端)

image-20240628224545382

2)①api模块:书写IDL -> 准备编译

* 书写IDL:
  • 思路:写protobuf,然后编译成java

image-20240628225353882

  • 一、环境准备:一些1.架构上的内容

image-20240628224833558

  • 二、定义2.消息message(理解为一个数据结构)和3.服务service(理解为一个方法):

image-20240628225405689

* 安装gRPC插件(一次性):帮助编译为Java并放在IDEA中
  • 在github找到这个项目的源代码,分别导入maven的依赖、插件

image-20240628225636274

image-20240628225657980

* 进行编译:执行两个命令生成两个类 <过>
  • 一、生成message的类:在proto文件中,打开maven:执行相应命令“ 1.compile ”

image-20240628225950462

  • 文件位置:target目录下

image-20240628230147613

  • 看看java类:

image-20240628230544942


  • 二、生成服务接口:“ 2.compile-custon ”

image-20240628230352688

image-20240628230503895

image-20240629111121332

* 优化编译:合成两个命令 + 改文件位置
  • 一、方法:
  • 补充:怎么打开run maven -> Ctrl + Alt + R

image-20240629111643394

image-20240629111719312

image-20240629111738776

  • 二、效果:

image-20240629111808860

  • 三、Ps:以后run maven里面多出了我们新建的goal命令

image-20240629111851680

  • 五、如何删除生成出来的target文件夹:用maven clean命令
  • 六、设置输出位置:在pom中添加两行设置(不设置的话,直接把生成的两个类剪切到相应位置即可)

image-20240629112839909

* 补充:细说生成的两个java类的构成

image-20240629113602049

3)②server(服务端)模块

  • 一、先要导入api模块:

image-20240629113841729

  • 二、在java包下,新建service包,实际上就是实现api中定义的“ hello ”服务

image-20240629113949717

  • 三、完成业务功能的开发:接收参数 -> 业务处理 -> 封装响应后返回
  • 新建类,继承api生成接口类(大类)的xxxImplBase(内部类),重写hello方法
  • 注意:gRPC的数据返回不是通过方法的返回值,而是通过StreamObserver返回的

image-20240629114853077

  • 四、完成服务端的开发

image-20240629115310049

  • 五、启动服务:就是run main()

image-20240629115358391

4)③client(客户端)模块

  • 一、客户端模块:建个包

image-20240629115854599

  • 二、搭建客户端:创建通道 -> 获得代理对象 -> 封装参数 -> 拿到结果 -> 关闭通道

image-20240629121332920

* 增加repeated关键字情况:<补充>
  • api端:

image-20240629121618388

  • server端:*需要通过getXxxList()*方法拿到数据(多个)

image-20240629121839537

  • 补充:server端(注意一定要有这两个方法),即先将数据传出,再通知响应结束

image-20240630154759497

  • client端:传入多个数据

image-20240629122304888

四、gRPC的四种通信方式

1)四种通信方式:

image-20240630160015827

2)①简单RPC(一元RPC):最常见

【实战】:区块链项目-统一上链与认证中心:login部分

  • 实际业务处理95%用到的是一元RPC
  • 特点:阻塞等待

image-20240630160054116

3)②服务端流式RPC:

* 阻塞方式:不常见
  • 介绍:一个请求对象,多个响应结果

  • 使用场景:

image-20240630161508199

  • 语法:加stream

image-20240630161615122

  • 服务端代码示例:多次响应后才onCompleted()

image-20240630162159669

  • 客户端:阻塞等待知道结束响应,然后再使用数据

image-20240630163606755

* 异步监听方式:
  • api部分与服务端部分代码不变,主要变化的是客户端部分:
  • 方法:通过匿名内部类实现StreamObserver接口的三个方法,分别定义接收到消息、接收消息出现异常、接收消息结束的逻辑
  • 注意:这里的builder要通过*newBuilder()*来创建

image-20240707150412123

4)③客户端流式RPC:

  • 概念:客户端多次发消息给服务端
  • 常见场景:车上传感器不断给导航服务端发送位置消息
  • 语法:

image-20240707151030771

  • 服务端:
  • 特点:返回值是一个StreamObserver(之前两种都是void),实现这个接口的三个方法(异步的业务逻辑)
  • 客户端那边,每用onNext()发送过来一条消息,服务端就会执行一次onNext()这个方法
  • 客户端发送onCompleted()告诉服务端发送结束,服务端才会执行onCompleted()这个方法里的逻辑

image-20240707151849576

  • 客户端:用for循环模拟不定时的发送消息
  • 因为要呈现客户端接收响应的数据的过程,所以还要加上awaitTermination()来阻塞客户端

image-20240707152855794

image-20240707153006892

5)④双向流式RPC:

  • 就是:整合客户端流式和服务端流式RPC
  • 常见场景:聊天室
  • 语法:api模块

image-20240707153911489

  • 服务端:

image-20240707154252536

  • 客户端:

image-20240707154428510

五、gRPC代理方式:<过>

  • FutureStub:

www.bilibili.com/video/BV13M…

六、整合SpringBoot:<未完待续>

  • SpringBoot整合gRPC,主要整合的是server端和client端的api
  • 而api端的方法,因为是在.probuf等非java部分完成,所有不会整合

1)服务端:

  • 先导入依赖:这个依赖是github的开源项目,不是官方集成的

image-20240709130732582

  • 因为避免api模块引入的依赖与上面boot依赖冲突,现在api模块要重新做(不能按照之前的方式)