当前位置: 首页 > 科技观察

既然有了HTTP协议,为什么还要有RPC

时间:2023-03-17 00:48:00 科技观察

?记得刚开始工作的时候第一次接触到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()发起连接建立。握手建立连接过程连接建立后,我们可以使用send()发送数据,recv()接收数据。就这么一个纯TCP连接就可以收发数据,够了吗?不行,这样使用会有问题。使用纯裸TCP有什么问题?千篇一律的作文往往是死记硬背。TCP具有三个特点,面向连接、可靠、基于字节流。什么是TCP?这三个特点真的是概括的非常淋漓尽致。我们没有记住这种刻板印象。每一个特性扩展都可以讲一篇文章,而我们今天要重点讲的是基于字节流的。字节流可以理解为双向通道中流动的数据。这个数据其实就是我们常说的二进制数据。简单的说就是很多01弦。纯裸TCP发送和接收的这些01字符串之间是没有边界的,你不知道哪里算是完整的报文。01二进制字节流正是因为这个特点没有任何界限,所以当我们选择使用TCP发送“夏洛特”和“特别烦恼”时,接收端收到的是“夏洛特烦恼”。没发帖区分是想表达“夏洛”+“特别麻烦”还是“夏洛”+“麻烦”。新闻对比这就是所谓的粘包问题,我之前专门写过一篇关于这个问题的文章。这么说的目的是告诉大家,纯bareTCP是不能直接用的。需要在此基础上添加一些自定义规则来区分消息边界。所以我们会对每一个要发送的数据进行打包,比如添加一个消息头,明确的规定了一个完整数据包的长度。按照这个长度,我们就可以继续接收数据了。拦截之后,才是我们真正要传输的。邮件正文。这里说的消息边界长度标志和消息头还可以放各种东西,比如消息体是否压缩过,消息体的格式等。这称为协议。每个使用TCP的项目都可能定义一套这样的协议解析标准。它们可能不同,但原理是相似的。所以在TCP的基础上,衍生出了很多协议,比如HTTP,RPC。HTTP和RPC让我们回顾一下网络的分层图。四层网络协议TCP是传输层协议,而HTTP和基于TCP的各种RPC协议只是应用层协议,定义了不同的消息格式。HTTP协议(HyperTextTransferProtocol),又称超文本传输??协议。我们经常使用它。我们通常通过在浏览器中输入URL来访问网页。这里使用的是HTTP协议。HTTP调用和RPC(RemoteProcedureCall),也称为远程过程调用。它本身并不是一个特定的协议,而是一种调用方法。例如,我们通常会像下面这样调用本地方法。res=localFunc(req)如果这不是本地方法,而是远程服务器暴露的方法remoteFunc,如果我们还能像本地方法一样调用它,我们可以屏蔽一些网络细节并使用它不是很好吗更方便?res=remoteFunc(req)RPC可以像调用本地方法一样调用远程方法。基于这个想法,大佬们创造了很多RPC协议,比如比较有名的gRPC和thrift。值得注意的是,虽然大多数RPC协议在底层使用的是TCP,但实际上不一定非要使用TCP,而是使用UDP或者HTTP。其实也可以实现类似的功能。基于TCP协议的HTTP和RPC协议这里,我们回到文章的标题。既然有了HTTP协议,为什么还要RPC呢?实际上,TCP是70年代问世的协议,而HTTP是90年代才开始流行的。直接使用bareTCP会有问题。可想而知这么多年中间有那么多自定义协议,也有1980年代出来的RPC。所以我们应该问的不是既然有HTTP协议为什么还要RPC,而是有了RPC为什么还要HTTP协议。那么既然有了RPC,为什么还需要HTTP呢?现在电脑上安装的各种网络软件,比如xx管家,xx卫士,它们都是作为客户端(client),需要和服务器(server)建立连接,收发消息。这时候就会用到应用层协议。在这种客户端/服务器(c/s)架构下,他们可以使用自己的RPC协议,因为它只需要连接到自己公司的服务器即可。但是在软件上是有区别的,浏览器(browser),不管是chrome还是IE,不仅要能访问自己公司的服务器(server),还需要访问其他公司的web服务器,所以需要一个统一的标准,否则我们无法沟通。因此,HTTP是那个时代用来统一浏览器/服务器(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信息,比如consul或者etcd,甚至redis。如果要访问一个服务,就到这些中间服务去获取IP和端口信息。由于dns也是一种服务发现,所以也有基于dns进行服务发现的组件,比如CoreDNS。可以看出两者在服务发现方面有一些区别,但是无法区分。底层连接形式以主流的HTTP1.1协议为例。默认情况下,底层TCP连接建立后,这个连接会一直保持(keepalive),后续的请求和响应都会重用这个连接。RPC协议也类似于HTTP。它还建立TCP长链接进行数据交互,但不同的是RPC协议一般建立连接池。当请求量较大时,会建立多个连接并放入池中。当你要发送数据的时候,从池中取一个连接,用完再放回去,下次再用,可以说是非常环保了。connection_pool由于连接池有利于提高网络请求的性能,所以很多编程语言的网络库都会给HTTP添加连接池,比如go。可以看出两者在这方面差别不大,所以不是重点。传输的内容以TCP传输的报文为准。毕竟,它只不过是消息头和消息体。头部用来标记一些特殊的信息,其中最重要的就是消息体的长度。body就是放我们真正需要传输的内容,而这些内容只能是二进制的01串,毕竟电脑只知道这玩意儿。所以,TCP传输字符串和数字问题不大,因为字符串可以转成代码再转成01串,而数字本身可以直接转成二进制。但是对于结构体,我们得想办法把它转换成二进制的01字符串。这样的解决方案有很多,比如json和protobuf。将结构体转换为二进制数组的过程称为序列化,将二进制数组恢复为结构体的过程称为反序列化。序列化和反序列化对于主流的HTTP1.1,虽然现在被称为超文本协议,支持音频和视频,但是HTTP最初是为了显示网页文本而设计的,所以它传输的内容主要是字符串。标题和正文都是如此。在正文中,它使用json序列化结构数据。我们直接截屏就可以看到了。在HTTP报文中,我们可以看到内容有很多冗余,非常啰嗦。最明显的,像header里面的信息,其实如果我们约定好header的哪一位是content-type,就没必要每次都真的传“content-type”字段,类似其实,在body的json结构中情况也特别明显。而RPC,因为它的定制化程度更高,可以使用更小的protobuf或者其他序列化协议来保存结构化数据,不需要像HTTP那样去考虑各种浏览器行为,比如302重定向和跳转。因此,性能会更好,这也是公司内部微服务放弃HTTP而选择使用RPC的主要原因。HTTP原理RPC原理当然上面说的HTTP其实是指目前主流使用的HTTP1.1。HTTP2在前者的基础上做了很多改进,所以性能上可能比很多RPC协议要好,甚至gRPC底层也是直接用HTTP2。那么问题又来了。既然有了HTTP2为什么还要有RPC协议呢?这是因为2015年HTTP2就出来了,当时很多公司的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出现得更早,而且性能比现在主流的HTTP1.1要好,所以大部分公司内部还是使用RPC。HTTP2.0在HTTP1.1的基础上进行了优化,其性能可能优于很多RPC协议。但是,由于它是近几年才发布的,所以不太可能取代RPC。最后,留个问题。大家有没有注意到,不管是HTTP还是RPC,都有一个特点,就是消息都是客户端请求,服务器端响应的。客户端不问,服务端肯定不回答,有点生硬,但现实中肯定有下游需要主动向上游发送消息的场景,比如玩网页游戏,站在那里做什么都没有,还会发生奇怪的事情主动攻击我,遇到这种情况我该怎么办?参考https://www.zhihu.com/question/41609070。