RPC简介

article/2025/9/21 18:00:29

1. 概述

RPC(Remote Procedure Call),即远程过程调用,是一种通过网络从远程计算机程序上请求服务、而不需要了解底层网络技术的协议。RPC协议假定某些传输协议(如TCP或UDP)的存在,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发应用程序(包括网络分布式多程序在内)更加容易。

例如,有两台服务器A和B,一个应用部署在服务器A上,想要调用服务器B上的应用提供的函数/方法,由于服务器A和服务器B的应用程序不在一个内存空间,不能直接调用,就需要通过网络来传达调用的语义和调用的数据,这就是RPC协议。

2. 背景

在单机时代,一台电脑上运行多个进程,为了实现进程之间的通信,就出现了IPC(Inter-process communication,单机中运行的进程之间的相互通信)。

而到了网络时代,大家的电脑都互相连起来了,以前程序只能调用自己电脑上的进程,能不能调用其他机器上的进程呢?为了实现这个目的,把IPC扩展到网络上,就是RPC(远程过程调用)了。

3. 原理

本节通过本地过程调用和远程过程调用来介绍RPC的原理。

3.1. 本地过程调用

在研究RPC前,我们先看看本地调用是怎么调的。

假设我们要调用函数Multiply来计算lvalue * rvalue的结果,代码如下:

1 int Multiply(int l, int r) {
2    int y = l * r;
3    return y;
4 }
5 
6 int lvalue = 10;
7 int rvalue = 20;
8 int l_times_r = Multiply(lvalue, rvalue);

在程序执行到第8行时,实际上执行了以下操作:

1)将 lvalue 和 rvalue 的值压栈;
2)进入Multiply函数,取出栈中的值10和20,将其赋予l和r;
3)执行第2行代码,计算 l * r ,并将结果存在y;
4)将 y 的值压栈,然后从Multiply返回;

5)回到第8行,从栈中取出返回值200,并赋值给 l_times_r。

上述5步就是执行本地调用的过程。

3.2 远程过程调用(RPC)

实际上RPC就是要像调用本地的函数一样去调远程函数。

在进行远程过程调用时,我们需要执行的函数体是在远程的机器上的,也就是说,3.1节中提到的Multiply函数是在另一个机器上的进程中执行的。这就带来了下面几个问题。

1)我们怎么告诉远程机器我们要调用Multiply,而不是Add或者其他函数呢?

解决方法:Call ID映射。

在本地调用中,函数体是直接通过函数指针来指定的,我们调用Multiply,编译器就自动帮我们调用它对应的函数指针。但是在远程调用中,调用函数指针的方法是行不通的,因为两个机器的两个进程的地址空间是完全不一样的,所以,在RPC中,所有的函数都必须有自己的一个ID,这个ID在所有进程中都是唯一确定的。客户端在做远程过程调用时,必须附上这个ID。同时,我们还需要在客户端和服务端分别维护一个“函数与Call ID”的对应表,客户端和服务端上的对应表不一定需要完全相同,但相同的函数对应的Call ID必须相同。当客户端需要进行远程过程调用时,它就查一下这个表,找出想要调用的函数相应的Call ID,然后把它(Call ID)传给服务端,服务端也通过查表,来确定客户端需要调用的函数,然后执行相应函数的代码。

2)客户端怎么把参数值传给远程的函数呢?

解决方法:序列化和反序列化。

在本地调用中,我们只需要把参数压到栈里,然后让函数自己去栈里读就行。但是在远程过程调用时,客户端跟服务端是不同的(机器的)进程,不能通过内存来传递参数,甚至有时候客户端和服务端使用的都不是同一种语言(比如服务端用C++,客户端用Java或者Python),这时候就需要客户端把参数先转成一个字节流,传给服务端后,服务端再把这个字节流转成自己能读取的格式,这个过程叫序列化和反序列化。同理,从服务端返回的值也需要序列化反序列化的过程。

3)网络传输问题。

远程过程调用往往用在网络上,客户端和服务端是通过网络连接的。所有的数据都需要通过网络传输,因此就需要有一个网络传输层。网络传输层需要把“Call ID”和“序列化后的参数字节流”传给服务端,然后再把“序列化后的调用结果”传回客户端,只要能完成这两个功能的,都可以作为传输层使用。因此,RPC所使用的协议其实是不限的,只要能完成传输就行。尽管大部分RPC框架都使用TCP协议,但其实UDP也可以,而gRPC干脆就用了HTTP2。

综上所述,要实现一个RPC框架,其实只需要把以上三点实现了就基本完成了。Call ID映射可以直接使用函数字符串,也可以使用整数ID,映射表一般就是一个哈希表;序列化反序列化可以自己写,也可以使用Protobuf或者FlatBuffers之类的;网络传输库可以自己写socket,或者用asio,ZeroMQ,Netty之类。

4. 简要流程

一次远程过程调用的简要流程如下(对照流程图理解下列的具体流程):

1)首先,要解决通信的问题,主要是通过在客户端和服务器之间建立连接(如tcp连接),远程过程调用的所有数据都在这个连接中传输。此连接可以是按需连接,调用结束后就断掉,即短连接;也可以是长连接,多个远程过程共享同一个连接;
2)其次,要解决寻址问题,也就是说,服务器上的应用怎么告诉底层的RPC框架,如何连接到B服务器(如主机或IP地址)以及特定的端口、方法名称(IP+端口+方法名),这样才能完成调用;

3)然后,client上的应用发起远程过程调用时,方法的参数需要通过底层的网络协议(如tcp)传递到server上,由于网络协议是基于二进制的,内存中的参数也要序列化成二进制的形式,这就是序列化过程(Serizlize),通过连接寻址,将序列化的二进制发送给server;
4)再然后,server收到请求后,需要对参数进行反序列化,恢复为内存中的表达形式,然后找到对应的方法(根据CALL ID与函数的对应表),进行本地调用,然后得到函数的返回值;
5)最后,server需要将函数返回值发送给client上的应用,该返回值也需要经过序列化后发送,client接到server发送的消息后,再对该消息进行反序列化,恢复为内存中的表达形式,交给client上的应用。


http://chatgpt.dhexx.cn/article/LSMl8d6g.shtml

相关文章

【OS笔记 28】处理死锁的四种方法——预防死锁(破坏四个必要条件之一)

前面讲过预防死锁是通过破坏死锁的四个必要条件,所以就有四个预防死锁的方法吗?错!只有三种,因为互斥条件是必须的,不仅不能改变,还应该加以保证。因此只能破坏后三个条件。 一、破坏请求和保持条件 • 方…

什么是死锁,产生死锁的必要条件,以及避免死锁的方法

一、死锁的定义 死锁是指,有两个或两个以上的线程在执行的过程中,由于竞争的资源或者彼此通信而造成的一种阻塞状态,若无外力作用,他们将都无法进行下去,从而形成一直阻塞的状态叫死锁。 简单来说就是…

死锁产生的四个必要条件?如何避免和预防死锁产生?

一、什么是死锁? 两个线程或两个以上线程都在等待对方执行完毕才能继续往下执行的时候就发生了死锁。结果就是这些线程都陷入了无限的等待中,这就是死锁。 举个例子:如果线程1锁住了A,然后尝试对B进行加锁,同时线程2已…

死锁产生的原因和必要条件详解

3.5 产生死锁的原因和必要条件 在多道程序系统中,虽借助于多个进程的并发执行,改善了系统的资源利用率,提高了系统的吞吐量,但可能发生一种危险——死锁。 死锁(deadlock): 是指多个进程在运…

死锁概念,死锁产生的四个必要条件,如何避免和预防死锁

一、死锁概念 死锁是指两个或多个进程在执行的过程中,因为竞争资源而造成互相等待的现象,若无外力作用,它们都无法推进下去。 1.在等待对方时占有不可抢占的资源 举个例子,假设有P1,P2两个进程,都需要A和…

关于死锁,死锁的四个必要条件的总结

什么是死锁? 死锁,指的是多个进程再运行期间因争夺资源而产生的一种僵局,若无外力作用(破坏死锁),程序将无法运行。 死锁产生的四个必要条件 互斥条件: 进程要求对所分配的资源(如…

死锁产生的四个必要条件

一、死锁产生的四个必要条件 互斥条件:资源是独占的且排他使用,进程互斥使用资源,即任意时刻一个资源只能给一个进程使用,其他进程若申请一个资源,而该资源被另一进程占有时,则申请者等待直到资源被占有者…

什么是死锁?死锁发生的四个必要条件是什么?如何避免和预防死锁产生?

什么是死锁? 死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程…

死锁和产生死锁的四个必要条件以及如何避免和预防死锁

什么是死锁 如果一组进程中的每一个进程都在等待仅由该组进程中的其它进程才能引发的事件,那么该组进程就是死锁的。 死锁出现的场景 (1)多个线程:彼此申请对方资源而导致的死锁。A申请B的资源时,因为资源被占用&am…

理解死锁产生的四个必要条件

死锁的定义 死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进…

死锁,死锁的四个必要条件以及处理策略

一、什么是死锁二、死锁与饥饿三、资源的类型 3.1 可重用资源和消耗性资源 3.1.1 可重用资源(永久性资源)3.1.2 消耗性资源(临时性资源) 3.2 可抢占资源和不可抢占资源 3.2.1 可抢占资源3.2.2 不可抢占资源 四、死锁产生的原因 4…

死锁产生的四个必要条件(缺一不可)

死锁产生必须同时满足四个条件,只要其中任意一条不成立,死锁就不会发生。 1、互斥条件:进程要求对所分配的资源进行排他性控制,即在一段时间内某项资源只被 一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。如图一 2、非抢占:进程所获得的额资源在未使…

死锁的四个必要条件

死锁在高并发中是一个常见的名词。产生的四个必要条件如下: 互斥条件:一个资源同一时间能且只能被一个线程访问; 不可掠夺:当资源被一个线程占用时,其他线程不可抢夺该资源; 请求与等待:当资源被…

div在html垂直居中,div 垂直居中(css div水平垂直居中六种方法)

div垂直居中 div垂直居中代码示例如下: 前台效果如下图所示: 如图所示,div中的文字垂直居中。其中主要的属性就是line-height。 line-height属性设置行间的间隔(行高即垂直方向)。 line-height属性会影响行框的规划。在应用到一个块级元素时&…

使用css3将一个div水平和垂直居中显示

使用css3将一个div水平和垂直居中显示 方案一: div绝对定位水平垂直居中【margin:auto实现绝对定位元素的居中】, 代码两个关键点:1.上下左右均0位置定位; 2.margin: auto; 其width、height如何更改都是居中显示的,兼容…

CSS 实现DIV水平垂直居中(二)

CSS 实现DIV垂直居中 上期介绍了CSS实现div水平居中的五种方法,下面介绍CSS实现div垂直居中的几种方法。上篇:CSS 实现DIV水平居中 首先还是和上期同样的两个div盒子,以下方法实现div垂直居中,效果如图: 1.通过padding上下留白实…

div中的内容水平垂直居中

1. div高度自适应的情况 div在不设置高度的时候,会被里面的内容撑开,内容自动填充在div中,无论是一行内容还是多行内容,此时不需要设置垂直居中,内容自动在中间的, 想要看的更直观些,只需要加上…

Div水平垂直居中

(1)父元素设置弹性盒子display:flex; 再加上justify-content:center;align-items:center; 推荐 (2)使用top:50% left:50% 以及margin-top 和 margin-left 来进行定位 注意: 必须知道盒子的具体的宽和高,否…

html 中div垂直居中的三种方式

1、第一种&#xff1a; <style type"text/css"> <!-- .con_div{ width:400px; height:300px; border:1px solid #777; text-align:center; display:table-cell; vertical-align:middle; background:red; color:#fff; lin…

如何让一个div水平垂直居中

在工作中 经常会碰到让一个div框针对某个模块水平垂直居中 针对这种情况 有多种方法 现在一一实现一下 一. div绝对定位水平垂直居中 margin 负间距 代码: .box {width: 200px;height: 200px;background: yellow;position: absolute;left: 50%;top: 50%;margin-left: -100px;m…