微软二面:既然有 HTTP 协议,为什么还要有 RPC?

      最后更新:2022-07-29 17:43:21 手机定位技术交流文章

      我记得我在工作时,第一次接触RPC协议,然后我非常困惑,我使用HTTP协议很好,为什么使用RPC协议?

      于是就到网上去搜。

      许多解释似乎非常正式,我相信所有平台的人都见过它们,解释,而不是表面上解释,使用一个我们不知道的概念来解释另一个我们不知道的概念,知道的人不需要看,不知道的人看或者不知道。

      这种看了,又好像没看的感觉,云里雾里的很难受,我懂。

      为了避免强烈的丑闻厌倦感,我们今天将尝试一种不同的讲话方式。

      从 TCP 聊起

      作为一个程序员,假设我们需要向A计算机上的进程发送数据,然后向B计算机上的进程发送数据,我们通常会用代码中的插座程序。

      这时候,我们可选项一般也就TCP和UDP二选一。TCP可靠,UDP不可靠。除非是马总这种神级程序员(早期QQ大量使用UDP),否则,只要稍微对可靠性有些要求,普通人一般无脑选TCP就对了。

      类似下面这样。

      fd = socket(AF_INET,SOCK_STREAM,0);

      其中SOCK_STREAM,是指使用字节流传输数据,说白了就是TCP协议。

      在定义了socket之后,我们就可以愉快的对这个socket进行操作,比如用bind()绑定IP端口,用connect()发起建连。

      9435090e9aaa8176340b34443da0529f.jpeg图片

      握手建立连接流程

      在连接建立之后,我们可以使用 send()来发送数据 andrecv()来接收数据。

      有了如此裸露的TCP连接,你就可以接收和发送数据,这还不够吗?

      不,那会是个问题。

      使用裸体TCP有什么问题?

      TCP具有三个特点:面向连接,可靠,和基于字节。

      149651998f308885c7921bfd7bdf4b7a.jpegTCP是什么

      这些三个特征的确很好地总结, 这些八段我们没有支持.

      每个特征都可以在一个文章中讨论,今天我们需要集中讨论的是基于这个节点流。

      字符流可以理解为数据通过双向通道流动,这些数据实际上我们经常称之为二进制数据,它只是一堆01个字符串。这些纯裸的TCP传输的01字符串之间没有界限,你不知道要从哪里得到完整的信息。

      6623384f827880df7f129ad36084bb80.jpeg01二进制字节流

      因为这没有边界特征,所以当我们选择使用TCP发送**"夏洛"和"特烦恼"的时候,接收器接收了夏洛特的麻烦,这时候接收端没发区分你是想要表达"夏洛"+"特烦恼"还是"夏洛特"+"烦恼"**。

      7095df54acd7f5c21ffec21f33619f31.jpeg消息对比

      这就是所谓的粘贴问题,我曾经写过一篇特别的论文。

      说这个的目的是为了告诉大家,纯裸TCP是不能直接拿来用的,你需要在这个基础上加入一些自定义的规则,用于区分消息边界。

      因此,我们将所有我们想要发送的数据包起来,比如添加一个消息头条,详细说明一个完整的包的长度,根据这个长度数据可以继续接收,然后这些数据就是我们真正想要发送的实体。

      2e8fd39dbd1096392af04ee777456032.jpeg消息边界长度标志

      这里头条提到头条,你可以设置诸如消息体是否压缩和消息体的格式等等,只要所有事情都商定上下,并且每个人都认出对方,这就是所谓的协议。

      每个使用TCP的项目可能定义一套类似的协议分析标准,它们可能不同,但原则是相似的。

      许多协议, 例如HTTP和RPC, 都来自TCP.

      HTTP和RPC

      让我们回顾一下网络的层次结构。

      bbdd418d75b303ea0c4a80b53a9ac6f9.jpeg四层网络协议

      TCP是传输层的协议,而基于TCP造出来的HTTP和各类RPC协议,它们都只是定义了不同消息格式的应用层协议而已。

      HTTP协议(HyperTextTransferProtocol),又叫做超文本传输协议。我们用的比较多,平时上网在浏览器上敲个网址就能访问网页,这里用到的就是HTTP协议。

      6167666be5dc3f4d3db3f590e429b173.jpegHTTP调用

      RPC(RemoteProcedureCall)也称为远程过程调用(RemoteProcedureCall)。

      例如,我们通常称之为这样一种地方方法。

       res = localFunc(req)

      如果现在这不是个本地方法,而是个远端服务器暴露出来的一个方法remoteFunc,如果我们还能像调用本地方法那样去调用它,这样就可以屏蔽掉一些网络细节,用起来更方便,岂不美哉?

       res = remoteFunc(req)

      fcf6f98674a42c44ef7b03153b7bd52f.jpegRPC可以像本地方法那样调用远程方法

      基于这个想法,洋基开发了各种RPC协议,如著名的gRPC,thrift。

      值得注意的是,虽然大部分RPC协议底层使用TCP,但实际上它们不一定非得使用TCP,改用UDP或者HTTP,其实也可以做到类似的功能。

      6421d6f6e7970b23c4899b3e0f4ac76a.jpegHTTP和RPC基于TCP协议

      现在我们回到文章的主题。

      既然有HTTP协议, 为什么有RPC?

      事实上,TCP是1970年代发行的协议,HTTP直到1990年代才流行。 直接使用裸体TCP有问题,你知道有多少自定义的协议已经存在多年,还有一个RPC从1980年代发行。

      所以我们不是问为什么应该有一个RPC,因为有一个HTTP协议,而是问为什么应该有一个HTTP协议和RPC。

      既然有RPC,为什么HTTP呢?

      现在所有的网络软件都安装在计算机上,比如xx管家,xx卫士,它们都作为客户端(client)需要跟服务端(server)建立连接收发消息,当前正在使用应用程序层协议,在这个**客户端/服务器(c/s)**架构下,他们可以使用自己的RPC协议,因为它只管理自己的公司服务器。

      但有个软件不同,浏览器,不管是Chrome还是IE,他们不仅需要能够访问自己的公司服务器,你还需要访问其他公司的网站服务器,所以他们需要统一的标准,不然大家没法交流。于是,HTTP就是那个时代用于统一browser/server (b/s)的协议。

      就是,几年前,HTTP主要用于b/s架构,RPC更用于c/s架构。但现在情况并不那么清楚,b/s和c/s慢慢融合。许多软件同时支持多个目的,比如某度云盘,既要支持网页版,它还支持移动电话和PC终端,如果所有通信协议使用HTTP,这个服务器用同样的组件就足够了。RPC开始在幕后留下,一般用于公司内部集团,不同微型服务之间的通信。

      那都是HTTP, RPC是什么?

      好像我们回到文章的开头了,那从它们之间的差异开始。

      HTTP和RPC之间的区别是什么?

      让我们看看RPC和HTTP之间的一些明显的区别。

      服务发现

      为启动向服务器请求,您必须首先建立连接,建立连接的前提是您知道IP地址和端口。 为该服务找到相应的IP端口的过程实际上是服务发现。

      在HTTP中,您知道该服务的域名,并可以通过DNS服务分析其背后的IP地址,默认为80个端口。

      而RPC的话,就有些区别,通常有一个专门的中间服务存储服务名称和IP信息,例如,领事等,甚至是redis。想要访问某个服务,到这些中间服务获取IP和港口信息。因为dns也是一个被发现的服务,所以还有基于dns的组件来进行服务发现,例如, CoreDNS。

      可以看出,服务发现这幅作品,两者略有不同,但没有太多可以分开。

      底层连接形式

      以主流的HTTP1.1协议为例,其默认在建立底层TCP连接之后会一直保持这个连接(keep alive),之后的请求和响应都会复用这条连接。

      而RPC协议,也跟HTTP类似,通过建立与数据交互的TCP长链路,但不同的地方在于,RPC协议通常重建一个连接池,在请求量大的时候,在池中建立多个连接,当你想发送数据时,你从池中取出一个连接,用完放回去,下次再复用,可以说非常环保。

      888114ca164fe2c12348f27a8bd016ce.jpegconnection_pool

      由于连接池有利于提升网络请求性能,所以不少编程语言的网络库里都会给HTTP加个连接池,比如go就是这么干的。

      可以看出,这幅作品并没有太大的区别,所以这不是关键。

      传输的内容

      基于TCP传输的消息,说到底,无非都是消息头header和消息体body。

      头条用于标记某些特殊信息, 最重要的是消息的长度.

      身体是我们真正需要传递的内容,这些内容只能是二进制01字符串,毕竟, 电脑只知道这个游戏.所以TCP传输字符串和数字并不是问题,因为字符串可以转换为编码和转换为01字符串,数字本身也可以直接转换为二进制。但结构体呢,我们还得找出一种把它转换成二进制01字符串的方法。许多这样的计划已经实施,比如json,protobuf。

      将结构转换成二进制序列的过程称为序列化,而将二进制序列重构成结构的过程则称为逆序列化。

      57242ad937703aadd644ec7c873aaf38.jpeg序列化和反序列化

      对于主流HTTP1.1,虽然现在它被称为超文本协议,支持音频视频,但是HTTP的设计最初是用来显示网页文本的,因此它传输的内容主要是一个字符串。头条和身体是一样的。在body这块,它使用json来序列结构数据。

      我们可以拍一张照片,看看它。

      269756acbf7ea930b997d46062a35d02.jpegHTTP报文

      你可以看到,这里面有很多冗余,显得非常啰嗦。最明显的,如标题中的信息,事实上,如果我们同意第一个数字是内容类型,就不需要每次都真的把"content-type"这个字段都传过来,类似的情况实际上在身体的json结构中尤为明显。

      而RPC,由于高度的定制,它可以用更小的protobuf或其他序列协议存储结构数据。也不需要考虑HTTP等浏览器的行为,例如, 302是跳转的跳跃吗?结果会更好,它还放弃HTTP在公司内部微型服务中,选择使用RPC的主要原因。

      decc5520aac907f7ed58af66d8ec3912.jpegHTTP原理

      6afe3331c891193736bd9fe6602baf68.jpegRPC原理

      当然,上面提到的HTTP,事实上,具体指的是当前主流的HTTP1.1使用,HTTP2基于前者做了大量的改进,因此性能可能比许多RPC协议更好,甚至使用HTTP2直接在gRPC底部。

      那么问题又来了。

      为什么应该有 HTTP2 的 RPC 协议?

      因为HTTP2发布于2015年,当时许多公司内部的RPC协议已经运行多年,而且由于历史原因,它们一般不需要被更换。

      总结

      • 纯裸的TCP可以传输数据,但它是一个无边的数据流,并且顶层需要定义消息格式来定义消息边界。 因此,有各种协议,HTTP和RPC协议都是在TCP上定义的应用程序层协议。
      • RPC基本上不是一项协议,而是一种调用方式,具体实现,例如gRPC和thrift,才是协议,它们是用于RPC调用的实现协议.其目的是使程序员能够调用远程服务方法,如调用本地方法。同时,RPC也有很多实现方法,不一定基于TCP协议。
      • 从发展历史来说,HTTP主要用于b/s架构,RPC更用于c/s架构。但现在情况并不那么清楚,b/s和c/s慢慢融合。许多软件同时支持多个目的,所以外部一般使用HTTP协议,RPC协议用于内部集群的微服务之间的通信。
      • RPC实际上比HTTP更早,比当前主流HTTP更早。 为了更好的性能,大多数公司仍然使用RPC。
      • HTTP2.0在HTTP1中。 基于1的优化,性能可能比许多RPC协议更好,但它不太可能取代RPC,因为它在近几年才发布。

      本文由 在线网速测试 整理编辑,转载请注明出处,原文链接:https://www.wangsu123.cn/news/30822.html

          热门文章

          文章分类