RPC(一)

正文共:4454 字 9 图
预计阅读时间:12 分钟

每日分享

The past has no power over the present moment.

过去无权掌控当下。

小闫语录:

时过境迁,过去终是过去,活在当下,赢在当下,争取未来。

1.RPC介绍

1.1什么是RPC?

我们来看一下维基百科的释义,RPC(Remote Procedure Call的缩写)叫做远程过程调用,也叫做远程程序调用。它是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。如果涉及的软件采用面向对象编程,那么远程过程调用亦可称作远程调用或者远程方法调用

我们举个例子来理解一下,有两台计算机A和B,它们之间可以进行网络通讯,计算机A中的程序1如果可以调用计算机B中的程序2。这样一个调用过程我们就叫做远程过程调用。之所以叫做远程,是因为程序2和程序1不在同一计算机中,而是在不同计算机。

1.2背景

在单台计算机中,我们可以通过程序调用来传递控制和数据。换一种说法就是,我们通过程序调用,可以将多个程序组成一个整体实现某个功能。

后来就有人想,既然一台计算机可以实现,那么多台计算机可不可以来实现这一过程呢?然后就有了远程过程调用。

那么怎么实现多台计算机中的多个程序组成一个整体来实现某个功能呢?下面来简单描述一下这个过程。

调用的一方发起远程过程调用,然后调用这方的环境挂起,参数通过网络传递给被调用的一方,被调用的一方执行程序。当程序执行完成后,产生的结果再通过网络回传给调用的一方,调用的一方恢复继续执行。完成整个远程过程调用。

RPC这种思想最早可以追溯到1976年,发展至今已有40余年了。

1.3为什么要使用RPC?

答:如今的计算机应用中,单机性能上很难承受住产品的压力,需要不断扩充多台机器来提升整体的性能。同时为了充分利用这些集群里的计算机,需要对其从架构上进行划分,以提供不同的服务,服务间相互调用完成整个产品的功能。RPC就能帮助我们解决这些服务间的信息传递和调用。

1.4RPC广义的概念

我们可以将所有通过网络来进行通讯调用的实现统称为RPC。看完这个概念,你也许会想,HTTP难道也是一种RPC实现咯?没错,可以这样理解。我们通过一个HTTP通讯过程探秘,看答案是否属实。

客户端将一些请求数据打包成一个HTTP协议报文,然后通过TCP传输给服务器。服务器接收到请求报文后,会进行过程调用。如果是静态服务器,会传递给客户端一个静态页面;如果是动态服务器,就会执行一段程序,将结果作为响应值通过TCP返回给客户端。客户端收到响应报文后,进行解析。解析之后再执行下面的过程。

这样一个过程是不是有些眼熟?对,和上面RPC的思想一样。

1.5RPC狭义的概念

看了广义的概念之后,你是不是觉得,有了HTTP,我们直接使用它不就好了,省得那么麻烦。我只能说,您想多了,我们是需要自己实现的。What?Why?How?震惊三联......

RPC的思想就是实现类似本地过程调用,当然要无限接近这个过程。那么就需要提高远程过程调用的执行速度,让其性能接近本地。这才是目的。HTTP的请求报文分为请求行,请求头和请求体,这里面会包含一些没有意义的数据,网络传输的数据量增大,减弱了传输性能,因此这种方式不可取。那么怎么办呢?我们可以自定义一种通讯数据的格式以及控制网络传输过程。这也是我们常用的方式。

我们常说的RPC是从狭义的概念上理解的,而狭义的RPC也剔除掉了HTTP通讯方式。统一采用自定义的流程控制,性能高的RPC。也就是自己定义数据格式,自己实现数据的接收等。

1.6RPC的优缺点

相比与传统HTTP的实现而言,优点就是效率高;发起RPC调用的一方,在编写代码时可忽略RPC的具体实现,如同编写本地函数调用一样。缺点就是通用性不怎么好。因为传输的数据不是HTTP协议格式,所以调用双方需要专门实现的通信库,对于不同的编程语言都要有相关实现。而HTTP作为一个标准协议,大部分的语言都已经有相关的实现,通用性要好的多。

HTTP更多的是面向用户和产品服务器的通讯,RPC更多的是面向产品内部服务器间的通讯。

2.RPC结构和调用流程

首先我们看一下流程:

1.调用者(Caller,也叫客户端Client)以本地调用的方式发起调用。

2.Client stub(客户端存根,可理解为辅助助手)收到调用后,负责将被调用的方法名,参数等打包编码成特定格式的能进行网络传输的消息体。

3.Client stub将消息体通过网络发送给对端(服务端)。

4.Server stub(服务端存根,同样可理解为辅助助手)收到通过网络接收到消息后按照相应格式进行拆包解码,获取方法名和参数。

5.Server stub根据方法名和参数进行本地调用。

6.将被调用者(Callee,也叫Server)本地调用执行后将结果返回给server stub。

7.Server stub将返回值打包编码成消息,并通过网络发送给对端(客户端)。

8.Client stub收到消息后,进行拆包解码,返回给Client。

9.Client得到本次RPC调用的最终结果。

RPC的目标就是要将2~8这些步骤封装起来,让使用者对这些细节透明。

在了解了RPC的流程之后,为了实现RPC,还需要关注两点:

消息协议

客户端调用的参数和服务端的返回值这些在网络上传输的数据以何种方法打包编码和拆包解码。

我们可以使用HTTP协议中关于报文格式的规定(如此一来,就变成了HTTP通讯),也可以自己定义某种格式,让客户端与服务端双方都遵循此种格式。

传输控制

在网络中数据的收发传输控制具体如何实现。

2.1消息协议

上面我们了解到消息协议考虑的就是如何将调用的参数和返回值之类的数据发送和接收,数据如何编码和解码。

在实现RPC调用时,通讯双方传输的数据(消息)如何表达描述,设计时一般会考虑两个目标。

2.1.1目标

性能高

1.将原始数据转换为消息数据的速度快。

2.转换后的消息数据体积小。

跨语言

RPC调用没有要求调用双方的编程语言必须相同,如果能做到跨语言调用,这样最好,会方便产品开发中不同的功能服务以最合适的语言实现,然后使用RPC实现彼此调用。因此RPC调用中传输的消息数据应该尽量能让更多的语言支持。

2.1.2消息边界问题

假如客户端有两个消息数据,那么客户端一定是一个一个消息数据进行发送与接收的吗?答案是否定的。比如每个消息数据特别的小,使用TCP完成数据传输。TCP协议在传输的时候,会将两个消息数据打包成一个数据包,一次性的发送给服务端。那么在服务端接收到了这个数据包时,如何分辨哪一个是客户端想要发送的第一个消息数据呢?消息数据的边界是如何划分的呢?

再来考虑一种情况,假如客户端在给服务端发送数据的时候,这个数据太大了,利用TCP无法一次性发送过去。那么TCP会将其拆分成两个或者多个数据包进行传输,服务端接收到数据包之后,又是如何判断这个数据是否完整呢?

像上面这两种情况就是消息边界问题,解决此问题有两种较为常用的方法:分隔符法长度声明法

分隔符法:就是在每条消息的结尾放置一种特殊的分隔符(一种常用的分隔符就是 \r\n),表示已达到本条消息的末尾。

长度声明法:就是在消息的起始位置,用一个固定长度的整数值(通常为4个字节)声明本消息的长度,接收者先读取出长度声明,再按照声明的长度读取出相应大小的数据即可。

有人会说,你举个例子呗,好嘞!HTTP协议同时运用了这两种方法:

HTTP/1.0 200 OK\r\n
Server: Nginx\r\n
Content-Type: text/html; charset=utf-8\r\n
Content-Length: 5096\r\n
\r\n
# 此处就是那5096个字节的数据了

你也许看到了 \r\n这个换行符,没找到长度声明法的运用,我来帮你找一下。在HTTP中它没有在请求体前声明,而是在请求头中加了一个 Content-Length这样的头。这个头的值就是长度。消息的接收者一读取到5096,就开始从请求体计算长度。

2.1.3消息内容问题

在具体消息内容的表现形式上,可以使用文本,也可以使用二进制。

文本:

我们可以将数据转换为具备某种格式的字符串(如JSON),将字符串作为消息内容发送。为什么使用JSON呢?因为大多数语言都对JSON数据有相应的处理方法,通用性好。

比如一个RPC调用请求,方法名为divide,参数为200和100,我们用JSON字符串的形式来表示一下:

{
    "name": "divide",
    "params": {
        "num1": 200,
        "num2": 100
    }
}

虽然它足够的方便,但是如你所见,它不够精简。因为实际有效数据只有 divide、200、100这三个。其他的符号都是无意义数据,在传输过程中造成浪费,影响性能。

二进制:

二进制是数据在内存中保存的最原始的形式。我们这次不采用文本了,而是在网络传输过程中,让这些数据以最原始的二进制内容直接发送。

8位(bit)= 1字节(Byte)

你也许会问,文本最后不也是二进制数据吗?那么他们有什么区别呢?请看下图:

我们能够看到,采用原始二进制传递,可以省去中间转换的环节,而且数据量也会大大减少,效率会更高。

文本形式会将整数转换成字符串的128,然后发送这个字符串,最后在服务端接收后进行转换,形成整数128。

如果使用二进制的方式来传递上面举例的RPC调用请求,该如何组织数据呢?这就需要实现RPC机制的设计人员来制定一个调用双方都遵守的协议规则,不同的设计人员可能有不同的想法。在后面的文章,我们会根据小案例给大家进行讲解,先留一个小悬念。

二进制传输也是我们常用的传输格式。

2.1.4压缩问题

尽管我们上面已经精简了数据,但是只是剔除了冗余无意义数据。如果消息数据过大,为了减轻网络带宽的压力,仍需要进一步处理,那么就用到压缩了。

就如同我们平时对一些文件、视频等使用压缩软件进行压缩来减小体积一样。我们可以在构造好数据准备发送前,先用算法将数据进行压缩处理,然后通过网络发送到对端,对端接收数据后,先进行解压缩处理,然后得到原体积数据后再进行解析。

即使是比文本数据小的二进制数据,我们仍可以进行压缩处理。

但是需要注意的是,压缩处理是一把双刃剑,虽然能减少数据量从而减轻带宽压力,但是同时额外增加了压缩和解压缩的过程,压缩和解压缩在处理的时候会有时间的消耗,会导致操作系统的负担加重。有时压缩的成本可能比减少数据量带来的收益还高,就得不偿失了。所以是否采用压缩处理,要根据具体情况权衡利弊。

优质文章推荐:

redis操作命令总结

MySQL相关操作

SQL查询语句

前端中那些让你头疼的英文单词

Flask框架重点知识总结回顾

团队开发注意事项

浅谈密码加密

Django框架中的英文单词

Django中数据库的相关操作

DRF框架中的英文单词

DRF框架

Django相关知识点回顾

python技术面试题-腾讯

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值