【gRPC】什么是RPC——介绍一下RPC
说起RPC,博主使用CPP手搓了一个RPC项目,RPC简单来说,就是远程过程调用:我们一般在本地传入数据进行执行函数,然后返回一个结果;当我们使用RPC之后,我们可以将函数的执行过程放到另外一个服务器上,而不是在本地创建一个函数栈帧,将函数执行所需要的一些东西压入到栈中。下面,我们来学习RPC!!!
一、远程过程调用带来的问题
在远程调用时,我们需要执行的函数体是在远程的机器上,也就是说,add是在另一个进程中执行的。这就带来了几个问题:
1.1 Caller ID 映射
我们怎么告诉远程机器我们要调用add,而不是sub或者 Foo呢??在本地调用中,直接通过函数指针来指定的,我们调用add,编译器就自动帮我们调用它相应的函数指针。但是在远程调用中,指针是不行的,因为两个进程的地址空间是完全不一样的。所以,在RPC中,所有的函数都必须有自己的一个ID。
这个ID在所有进程中都是唯一确定的。客户端在做远程调用时,必须附上这个ID。然后我们还需要在客户端和服务端中分别维护一个 【函数 <----> Call ID】的对应表。两者的表不一定需要完全相同,但是相同的函数对应的 Call ID 必须相同。当客户端需要进行远程调用时,他就查一下这个表,找出相应的 Call ID ,然后将他传入到服务端,服务端也通过查表来确定客户端需要调用的函数,然后执行相应函数的代码。
1.2 序列化和反序列化
客户端怎么把参数值传给远程的函数呢??在本地调用中,我们只需要把参数压入到栈中,然后让函数自己去栈萝莉读就行。但是在远程过程调用时,客户端根服务端是不同的进程,不能通过内存来传递参数。甚至有时候客户端和服务端使用的都不是同一种语言(比如服务端用C++,客户端使用 Java 或者 python)。这时候就需要客户端把参数先转成一个字节流,传给服务端后,再把字节流转成自己能读取的格式。这个过程叫做序列化和反序列化。同理,从服务端返回的值夜需要通过序列化和反序列化的过程。
1.3 网络传输
远程调用往往用在网络中,客户端和服务端是通过网络连接的。所有的数据都需要通过网络传输,因此就需要有一个网络传输层。网络传输层需要把 Call ID 和序列化后的参数字节流传给服务端,然后再把序列化后的调用结果传回给客户端。只要能完成这两者的,都可以用作为传输层使用。因此,他所使用的协议其实是不限的,只要可以完成传输就行了。尽管大部分RPC框架都使用TCP协议,但是其实UDP也是可以的,而gRPC干脆就使用HTTP2。
二、上述三个机制的解决方法
当我们解决了上述的三个问题,就可以实现RPC了,具体过程如下:
2.1 client 端可以解决的问题
- 将这个调用映射为 Call ID ,这里假设使用最简单的字符串当 Call ID 的方法
- 将 Call ID ,a 和 b序列化。可以直接将他们的值以二进制形式打包
- 将2中得到的数据包发送给 ServerAddr,这就需要使用网络传输层
- 等待服务器调用成功,那么就将结果反序列化,并赋值给total
2.2 server 端可以解决的问题
- 在本地维护一个 Call ID 到函数指针的映射 call_id_map,我们可以使用dict来完成
- 等待请求,包括多线程的并发处理能力
- 得到一个请求后,将其数据包反序列化,得到相应的函数指针
- 将 a 和 rb 反序列化后,在本地调用 add 函数,得到结果
- 将结果序列化后通过网络返回给 Client
在上面的整个流程中,其中:
- Call ID 映射可以直接使用函数字符串,也可以使用整数ID。映射表一般就是一个哈希表
- 序列化和反序列化可以自己写,也可以使用 protobuf 或者 FlatBuffers 之类的
- 网络传输库可以自己写 socket ,或者使用 asio,ZeroMQ、Netty 之类的
实际上真正的开发过程中,除了上面的基本功能之外,还需要更多的细节:网络错误,流量控制,超时和重传。
三、最后,如何将远程的这些过程写出本地函数调用的感觉??
下面,我们可以使用 go 语言来进行实现这个问题,因为在 go 语言中提供的包还是很全的。
我们分为服务端和客户端来进行编写代码:我们先来看一看服务端的代码:
package mainimport ("encoding/json""fmt""net/http""strconv"
)func main() {// http// 返回的格式化为:json{ "data"=3 }// 1. callID 的问题 r.URL.Path 2. 数据的传输协议 url 的参数传递协议 3. 网络传输协议 httphttp.HandleFunc("/add", func(w http.ResponseWriter, r *http.Request) {_ = r.ParseForm() // 解析参数fmt.Println("Path: ", r.URL.Path)a, _ := strconv.Atoi(r.Form["a"][0])b, _ := strconv.Atoi(r.Form["b"][0])w.Header().Set("Content-Type", "application/json; charset=utf-8")jData, _ := json.Marshal(map[string]interface{}{"data": a + b,})_, _ = w.Write(jData)})_ = http.ListenAndServe(":8080", nil)
}
客户端中的代码如下:
package mainimport ("encoding/json""fmt""github.com/kirinlabs/HttpRequest"
)type ResponseData struct {Data int `json:"data"`
}func add(a, b int) int {// 传输协议req := HttpRequest.NewRequest() // 创建一个requestres, _ := req.Get(fmt.Sprintf("http://127.0.0.1:8080/%s?a=%d&b=%d", "add", a, b))body, _ := res.Body()rspData := ResponseData{}_ = json.Unmarshal(body, &rspData)return rspData.Data
}func main() {// 实现 rpcadd(1, 2)
}
四、RPC开发的要素分析
4.1 RPC开发的四大要素
RPC技术在架构设计上有四个部分组成,分别是:客户端,客户端存根,服务端。服务端存根。下面,我们来一一介绍:
- 客户端:服务调用发起方,也称为服务消费者
- 客户端存根:该程序运行在客户端所在的计算机机器上,主要用来存储要调用的服务器的地址,另外,该程序还负责将客户端请求远端服务器程序的数据信息打包成数据包,通过网络发送给服务端Stub程序,其次,还要接受服务器Stub程序发送的调用结果数据包,并解析返回给客户端。
- 服务端:远端的计算机机器上运行的程序,其中有客户端要调用的方法
- 服务端存根:接收客户Stub程序通过网络发送的请求消息数据包,并调用服务端中真正的程序功能方法,完成功能调用,其次,将服务端执行调用的结果进行数据处理打包发送给客户端Stub程序。
了解完了RPC技术的组成结构,我们来看一下具体是如何实现客户端到服务端的调用的。实际上,如果我们想要在网络中的任意两台计算机上实现进程调用进程,需要解决很多问题,比如:
- 两台物理机器在网络中要建立稳定可靠的通信连接
- 两台服务器的通信协议的定义问题,即两台服务器上的程序如何识别对方的请求和返回结果。也就是说两台计算机必须能够识别对方发来的信息,并且能够识别出其中的请求含义和返回含义,然后才能进行处理,这其实就是通信协议要完成的工作。
在上图中,通过10步完成了RPC,下面我们来具体描述一下RPC每一步的调用过程:
- 客户端想要发起一个远程过程调用,首先要通过调用本地客户端Stub程序的方式调用想要使用的功能方法名;
- 客户端Stub程序接收到了客户端的功能调用请求,将客户端请求调用的方法名,携带的参数等信息做序列化,操作,并打包成数据包;
- 客户端Stub查找到远程服务器程序的IP地址,调用Socket通信协议,通过网络发送给服务端
- 服务端Stub程序接收到客户端发送的数据包信息,并通过约定好的协议将数据进行反序列化,得到请求的方法名和请求参数等信息
- 服务端Stub程序准备相关数据,调用本地的Server对应的功能方法进行,并存入相应的参数,进行业务处理
- 服务端程序根据已有的业务逻辑执行调用过程,等到业务执行结束之后,将执行结果返回给服务端Stub程序
- 服务端Stub程序将程序调用结果按照约定的协议进行序列化,并通过网络发送回给客户端Stub程序
- 客户端Stub接收到服务端Server发送返回的数据,对数据进行反序列化的操作,并将调用返回的数据传递给客户端请求发送者
- 客户端请求发起者得到调用结果,整个RPC调用过程结束
五、RPC需要使用到的术语
通过上文一系列的文字描述和讲解,我们已经了解了RPC的由来和整个RPC调用过程。我们可以看到RPC是一系列操作的集合,其中涉及了很多对于数据的操作,以及网络通信。因此,我们对RPC中涉及到的技术做一个总结和分析:
- 动态代理技术:上文中我们提到的Client Stub 和Server Stub 程序,在具体的编码和开发实践的过程中,都是使用动态代理技术自动生成的一段程序
- 序列化和反序列化:在RPC调用的过程中,我们可以看到数据需要在一台机器上传输到另一台机器上。在互联网中,所有的数据都是以字节的形式进行传输的。而我们在编程的过程中,往往都需要使用数据对象,因此想要在网络上将对象和相关变量进行传输,就需要对数据对象做序列化和反序列化的操作。
相关文章:
【gRPC】什么是RPC——介绍一下RPC
说起RPC,博主使用CPP手搓了一个RPC项目,RPC简单来说,就是远程过程调用:我们一般在本地传入数据进行执行函数,然后返回一个结果;当我们使用RPC之后,我们可以将函数的执行过程放到另外一个服务器上…...
谈谈你对AQS的理解
AQS 是多线程同步器,它是 JUC 包中多个组件的底层实现,如 Lock、CountDownLatch、Semaphore等都用到了AQS。 从本质上来说,AQS 提供了两种锁机制,分别是排它锁,和共享锁。 排它锁,就是存在多线程竞争同一…...
Bitcoin全节点搭建
1. wget https://bitcoincore.org/bin/bitcoin-core-0.20.1/bitcoin-0.20.1-x86_64-linux-gnu.tar.gz 2.tar -xzvf bitcoin-0.20.1-x86_64-linux-gnu.tar.gz mv bitcoin-0.20.1 bitcoin 3.创建配置文件(bitcoin.conf) mkdir -p /btc_data mkdir ~/.b…...
【mysql进阶】4-6. InnoDB 磁盘文件
InnoDB 磁盘⽂件 1 InnoDB存储引擎包含哪些磁盘⽂件? 🔍 分析过程 ✅ 解答问题 InnoDB的磁盘⽂件主要是表空间⽂件和其他⽂件,表空间包括:系统表空间、独⽴表空间、通⽤表空间、临时表空间和撤销表空间;其他⽂件有重做…...
HexForge:一款用于扩展安全汇编和十六进制视图的IDA插件
关于HexForge HexForge是一款用于扩展安全汇编和十六进制视图的IDA插件,在该工具的帮助下,广大研究人员可以方便地直接从 IDA Pro 界面数据解码、解密或执行安全数据审计任务。 功能介绍 1、从 IDA 的反汇编或十六进制视图复制原始十六进制;…...
WORFBENCH:一个创新的评估基准,目的是全面测试大型语言模型在生成复杂工作流 方面的性能。
2024-10-10,由浙江大学和阿里巴巴集团联合创建的WORFBENCH,一个用于评估大型语言模型(LLMs)生成工作流能力的基准测试。它包含了一系列的测试和评估协议,用于量化和分析LLMs在处理复杂任务时分解问题和规划执行步骤的能力。WORFBE…...
SpringBoot 集成 Activiti 7 工作流引擎
一. 版本信息 IntelliJ IDEA 2023.3.6JDK 17Activiti 7 二. IDEA依赖插件安装 安装BPM流程图插件,如果IDEA的版本超过2020,则不支持actiBPM插件。我的IDEA是2023版本我装的是 Activiti BPMN visualizer 插件。 在Plugins 搜索 Activiti BPMN visualizer 安装创建…...
UVM初学篇 -(22)UVM field_automation 域的自动化机制
field_automation机制是域的自动化的机制,这个机制的最大的优点是可以对一些变量进行批量的处理,比如对象拷贝、克隆、打印之类的变量。 一、 成员变量的注册 使用field_automation机制首先要用uvm_field 系列宏完成变量的注册,类中的成员变…...
STL二分查找
本课主要介绍容器部分里面的二分查找函数。涉及的函数有 3 个,这 3 个函数的强两个输入参数都和迭代器有关,或者说参数是可以迭代的,而第三个参数则是你要查找的值。 1. binary_search binary_search 的返回结果是 bool 值,如果找…...
啤酒游戏—企业经营决策沙盘
感谢黄浦区文华学院的邀请,今年是为南房集团开展系统思考培训的第二年。我们现在为客户设计的一整年系统思考训练中,会将系统环路结构图与真实议题研讨作为前置内容,让大家在理解整体框架后,再体验麻省理工学院系统动力学著名的“…...
尚硅谷-react教程-求和案例-@redux-devtools/extension 开发者工具使用-笔记
## 7.求和案例_react-redux开发者工具的使用(1).npm install redux-devtools/extension(2).store中进行配置import { composeWithDevTools } from redux-devtools/extension;export default createStore(allReducer,composeWithDevTools(applyMiddleware(thunk))) src/redux/s…...
【动手学强化学习】part2-动态规划算法
阐述、总结【动手学强化学习】章节内容的学习情况,复现并理解代码。 文章目录 一、什么是动态规划?1.1概念1.2适用条件 二、算法示例2.1问题建模2.2策略迭代(policyiteration)算法2.2.1伪代码2.2.2完整代码2.2.3运行结果2.2.4代码…...
【python爬虫实战】爬取全年天气数据并做数据可视化分析!附源码
由于篇幅限制,无法展示完整代码,需要的朋友可在下方获取!100%免费。 一、主题式网络爬虫设计方案 1. 主题式网络爬虫名称:天气预报爬取数据与可视化数据 2. 主题式网络爬虫爬取的内容与数据特征分析: - 爬取内容&am…...
初识Linux · 动静态库(incomplete)
目录 前言: 静态库 动态库 前言: 继上文,我们从磁盘的理解,到了文件系统框架的基本搭建,再到软硬链接部分,我们开始逐渐理解了为什么运行程序需要./a.out了,这个前面的.是什么我们也知道了。…...
华为OD机试 - 匿名信(Java 2024 E卷 100分)
华为OD机试 2024E卷题库疯狂收录中,刷题点这里 专栏导读 本专栏收录于《华为OD机试(JAVA)真题(E卷D卷A卷B卷C卷)》。 刷的越多,抽中的概率越大,私信哪吒,备注华为OD,加…...
通过rancher2.7管理k8s1.24及1.24以上版本的k8s集群
目录 初始化实验环境 安装Rancher 登录Rancher平台 通过Rancher2.7管理已存在的k8s最新版集群 文档中的YAML文件配置直接复制粘贴可能存在格式错误,故实验中所需要的YAML文件以及本地包均打包至网盘. 链接:https://pan.baidu.com/s/1oYX4eGoBtW_R-7i…...
text-align的属性justify
text-align常用的属性是left、center、right,具体的可参考css解释,今天重点记录的对象是justify justify 可以使文本的两端都对齐在两端对齐文本中,文本行的左右两端都放在父元素的内边界上。然后,调整单词和字母间的间隔&#x…...
使用python自制桌面宠物,好玩!——枫原万叶桌宠,可以直接打包成exe去跟朋友炫耀。。。
大家好,我是小黄。 今天我们使用python实现一个桌面宠物。只需要gif动态图片就行。超级简单容易上手。 #完整源代码可在下方图片免费获取 一:下载相关的库文件。 我们本次使用到的库文件为:tkinter和pyautogui 下载命令: pip…...
使用 ASP.NET Core 8.0 创建最小 API
构建最小 API,以创建具有最小依赖项的 HTTP API。 它们非常适合需要在 ASP.NET Core 中仅包括最少文件、功能和依赖项的微服务和应用。 本教程介绍使用 ASP.NET Core 生成最小 API 的基础知识。 在 ASP.NET Core 中创建 API 的另一种方法是使用控制器。 有关在最小 …...
气候服务平台ClimateSERV2.0简介(python)
1 简介 ClimateSERV 2.0允许开发从业者、科学家/研究人员和政府决策者可视化和下载历史降雨数据、植被状况数据以及 180 天的降雨和温度预报,以增进对农业和水资源供应相关问题的理解并做出改进的决策。 这些数据可以通过 Web 应用程序直接访问,也可以…...
Docker | centos7上对docker进行安装和配置
安装docker docker配置条件安装地址安装步骤2. 卸载旧版本3. yum 安装gcc相关4. 安装需要的软件包5. 设置stable镜像仓库6. 更新yum软件包索引7. 安装docker引擎8. 启动测试9. 测试补充:设置国内docker仓库镜像 10. 卸载 centos7安装docker https://docs.docker.com…...
React--》掌握Valtio让状态管理变得轻松优雅
Valtio采用了代理模式,使状态管理变得更加直观和易于使用,同时能够与React等框架无缝集成,本文将深入探讨Valtio的核心概念、使用场景以及其在提升应用性能中的重要作用,帮助你掌握这一强大工具,从而提升开发效率和用户…...
python爬虫百度图片
直接给代码,可直接用,个人需要修改的地方有两处: self.directory 这是本地存储地址,修改为自己电脑的地址,另外,**{}**不要删spider.json_count 10 这是下载的图像组数,一组有30张图像&#x…...
前端开发:Vue中数据绑定原理
Vue 中最大的一个特征就是数据的双向绑定,而这种双向绑定的形式,一方面表现在元数据与衍生数据之间的响应,另一方面表现在元数据与视图之间的响应,而这些响应的实现方式,依赖的是数据链,因此,要…...
CTF-RE 从0到N: TEA
TEA TEA(Tiny Encryption Algorithm,轻量加密算法) 是一种简单、快速的对称加密算法。它是一个分组加密算法,通常用于加密 64 位的数据块,并使用 128 位的密钥。TEA 是一种“费斯妥结构”(Feistel structu…...
python 使用PIL获取图片长宽
在Python中,你可以使用Pillow库(PIL的一个分支和替代品)来获取图片的长和宽。Pillow提供了丰富的图像处理功能,包括获取图像的基本属性,如尺寸。 以下是一个简单的示例,展示了如何使用Pillow库来获取图片的…...
【Nas】X-DOC:搞机之PVE部署All In One(黑群晖NAS 软路由OpenWrt Docker Win10远程桌面)
【Nas】X-DOC:搞机之PVE部署All In One(黑群晖NAS & 软路由OpenWrt & Docker & Win10远程桌面) 1、原硬件配置清单:2、改AIO后增加配置清单:3、虚拟化平台PVE:4、搭建的关键服务: 1…...
linux 驱动源码分析的理解。
首先 , 是linux 驱动,我看网上的老师,在分析源码时 , 不会 所有的函数都分析,而是分析一些比较重要的函数,一些厉害的人,在分析源码时…...
鸿蒙-任务栏右击退出 或 UIAbility窗口关闭,怎么弹框拦截
onPrepareToTerminate 需要配置权限 ohos.permission.PREPARE_APP_TERMINATE 参考链接:文档中心import { emitter } from kit.BasicServicesKit; import { common } from kit.AbilityKit; import { TipsDialog } from kit.ArkUI;// entryAbility.ets 在你的uiabilit…...
【C++进阶篇】——STL的简介
【C进阶篇】——STL的简介 1.什么是STL STL(standard template libaray-标准模板库):是C标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。 2.STL的版本 原始版本 Alexander Stepanov、Meng Lee 在…...
抚顺市城市建设档案馆网站/中国突然宣布一重磅消息
前言 Nodejs目前处境稍显尴尬,很多语言都已经拥有异步非阻塞的能力。阿里的思路是比较合适的,但是必须要注意,绝对不能让node做太多的业务逻辑,他只适合接收生成好的数据,然后或渲染后,或直接发送到客户端。…...
阳曲网站建设推荐咨询/免费的seo网站
原文链接:http://blog.csdn.net/only_wan/article/details/52975760 mvn 创建时在generating project in interactive mode卡住了,怎么解决? 从图中可以看出,为啥卡在generating project in interactive mode, 因为请求…...
怎么看网站有没有被收录/百度知道登录
个人工作中的SSD、Cardreader、Camera、Audio模块文档组织形式如下: RclLib__init__.pyRclLegacy.pymodulesAgilentOp.pyUvcCam.pyUvcCam.dll注:RclLib存放于:C:\Python27\Lib\site-packages(此路径已添加至系统环境变量中&#x…...
wordpress大学主题下载地址/六年级上册数学优化设计答案
#!/bin/sh cd /data001/smallrig/data/basics java -Xms512m -Xmx512m -Xss256k -XX:PermSize64m -XX:MaxPermSize256m -jar smallrig-basics-1.0.0.jar >/dev/null 2>&1 & exit...
h5制作方法/seo网站优化方案摘要
文章目录第一题、01-Number-sequence第二题.02-Number Sequence - Part 2第三题:NUMBER SEQUENCE – PART 3第四题:NUMBER SEQUENCE – PART 4第五题:第六题:17-templer-03-en1.lab2的内容为上次课堂练习的内容,把做过…...
wordpress 做论坛/百度刷自己网站的关键词
我试图写出一些文本,并在可能的情况下将其编码为utf-8,使用以下代码:outf.write((lang_name "," (script_name or "") "\n").encode("utf-8", errorsreplace))我得到以下错误:^{pr2}$…...