四层网络协议
TCP是传输层的协议,而基于TCP加上不同头的包装之后,就衍生出了HTTP和各类RPC协议,它们都只是定义了不同消息格式的应用层协议而已。
HTTP协议(Hyper Text Transfer Protocol),又叫做超文本传输协议。我们浏览一个网站,分享一个链接,都是走的这个协议。我们客户端发送一个Request, 服务端就响应一个Response。
HTTP调用
RPC(Remote Procedure Call),远程过程调用。它本身并不是一个具体的协议,而是一种调用方式。
举个例子,我们在一台机器上调用一个本地方法。
res = CallLocalFunc(req)
如果这个方法本地只是一个空壳子,它的真正实现是在另一个台机器上,那咋玩呢?那如果远端服务器暴露出来的一个方法CallremoteFunc,回到我们开篇的IP和端口,如果2台机器都知道彼此的IP和端口,那么我们像调用本地方法那样去调用另外一台机器暴露的函数而屏蔽掉一些网络细节,那岂不美哉?
res = CallremoteFunc(req)
RPC可以像调用本地方法那样调用远端方法
基于这个思路,国内外的几个大牛公司就实现了非常多款式的RPC协议,比如比较有名的Google 的gRPC,Facebook的thrift 还有baidu的brpc
虽然大部分RPC协议底层都使用TCP,但根据我们前文的拆包我们也可以知道不是所有的RPC都需要支持TCP,比如改用UDP或者HTTP,其实也是OK的。
基于TCP协议的HTTP和RPC协议
那么既然有HTTP协议,为什么还要有RPC?
其实历史是不断发展的,70年代提出TCP协议后,90年代才开始流行HTTP。而直接使用裸TCP会有问题,可想而知,这中间这么多年有多少自定义的协议,而这里面就有80年代出来的RPC。
所以我们该问的不是既然有HTTP协议为什么要有RPC,而是为什么有RPC还要有HTTP协议。
那么既然有RPC协议,为什么还要有保留HTTP呢?
现在手机和电脑上装的各种联网软件,比如XX三件套,卡脖子的半导体软件,工程制图软件等等,它们都作为客户端(clIEnt)需要跟服务端(server)建立连接收发消息,此时都会用到应用层协议,在这种client/server (c/s)架构下,它们可以使用自家造的RPC协议,因为它只管连自己公司的服务器就ok了。
但有个大众的软件不同 - 浏览器(browser),这哥们也有很多种内核,比较有名气的就是IE和chrome,不管他们心是蓝色的还是红色的,它们要既能访问自家公司的服务器(server),还需要访问其他公司的网站服务器,因此它们需要有个统一的标准,不然大家没法交流。于是,HTTP就是那个时代用于统一 browser/server (b/s) 的协议。
也就是说在多年以前,HTTP主要用于b/s架构,而RPC更多用于c/s架构。但现在其实已经没分那么清了,b/s和c/s在慢慢融合。很多软件同时支持多端,比如头条、知乎、小红书等等,既要支持网页版,还要支持手机端和PC端,如果通信协议都用HTTP的话,那服务器只用同一套就够了。而这些业务系统的内部,为了让咱们耍玩时,如丝滑般的顺畅,内部通信就要足够的块,不管是表格、图片、还是其他五花八门的数据类型,都要通信,这时RPC就开始退居幕后,再各个微服务之间通信。
那这么说的话,HTTP是不是万能的呢,还用什么RPC?它们区别是啥?
要说区别,就得掂量下他们的能力啦
服务注册和发现
如果要向某个服务器发起请求,你得先建立一条连接(socket),而建立连接的前提是,你得知道IP地址和端口(我们前文提到的2个东东)。这个找到服务对应的IP端口的过程,其实就是服务发现。
服务发现的实现方式也比较多。在HTTP中,比较知名的就是配置一个DNS路由表,给我一个网址,我就可以通过通过这个表(DNS服务)去解析得到它背后的IP地址,默认80端口,配置表的时候也可以自己定义。
而RPC的话,就有些区别,一般会有专门的中间服务去保存服务名和IP信息,比如consul、istio、k8s-discovery或者etcd等等。想要访问某个服务,就去这些中间服务去获得IP和端口信息。由于dns也是服务发现的一种,所以也有基于dns去做服务发现的组件,比如CoreDNS。
可以看出服务发现这一块,两者是有些区别,但都能支持,棋逢对手。
连接方式
以开山大作的HTTP1.1协议为例,它是一个长连接的(对比的就是断连接,一个请求结束,咱们就Bye-Bye了)其默认在建立底层TCP连接之后会一直保持这个连接(keep-alive, 就是每隔个时间咱们电话私聊下, C:你还在吗?,S: 还在的),之后的请求和响应都会复用这条连接。
而RPC协议,也跟HTTP类似,也是通过建立TCP长链接进行数据交互,但不同的地方在于,RPC协议一般还会在客户端建立一个连接池,在请求量大的时候,建立多条连接放在池内,要发数据的时候就从池里取一条连接出来,用完放回去,下次再复用,可以说非常环保。切记不要占着不用,一直吃着锅里还看着碗里的,这样你就会Game Over了。