RPC协议

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

假设我们需要在 A 电脑的进程发一段数据到 B 电脑的进程,我们一般会在代码里使用 Socket 进行编程。

这时候,我们可选项一般也就 TCP 和 UDP 二选一。TCP 可靠,UDP 不可靠。

类似下面这样。

复制代码
fd = socket(AF_INET,SOCK_STREAM,0);

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

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

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

光这样一个纯裸的 TCP 连接,就可以做到收发数据了,那是不是就够了?

不行,这么用会有问题

纯裸TCP问题

TCP是面向连接、基于字节流、可靠的连接

字节流可以理解为一个双向的通道里流淌的数据,这个数据 其实就是我们常说的二进制数据,简单来说就是一大堆 01 串 。纯裸 TCP 收发的这些 01 串之间是没有任何边界的,你根本不知道到哪个地方才算一条完整消息。

正因为这个没有任何边界的特点,所以当我们选择使用 TCP 发送"夏洛"和"特烦恼"的时候,接收端收到的就是"夏洛特烦恼",这时候接收端没发区分你是想要表达"夏洛"+"特烦恼"还是"夏洛特"+"烦恼"。

这就是所谓的粘包问题

故纯裸TCP是不能直接拿来用的,要在这个基础上加入一些自定义的规则,用于区分消息边界

比如加入消息头消息头里写清楚一个完整的包长度是多少 ,根据这个长度可以继续接收数据,截取出来后它们就是我们真正要传输的消息体

而这里头提到的消息头 ,还可以放各种东西,比如消息体是否被压缩过和消息体格式之类的,只要上下游都约定好了,互相都认就可以了,这就是所谓的协议。

每个使用 TCP 的项目都可能会定义一套类似这样的协议解析标准,他们可能有区别,但原理都类似

于是基于 TCP,就衍生了非常多的协议,比如 HTTP 和 RPC

HTTP 和 RPC

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

RPCR emote P rocedure C all),又叫做远程过程调用 。它本身并不是一个具体的协议,而是一种调用方式

例如平时调用一个本地方法就像下面这样:

复制代码
 res = localFunc(req)

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

复制代码
 res = remoteFunc(req)

基于这个思路,大佬们造出了非常多款式的 RPC 协议,比如比较有名的gRPCthrift

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

TCP70年 代出来的协议,RPC是80年代提出的,HTTP是90年代流行的。

既然有 RPC 了,为什么还要有 HTTP 呢?

现在电脑上装的各种联网 软件,它们都作为客户端(Client)需要跟服务端(Server)建立连接收发消息,此时都会用到应用层协议,在这种 Client/Server (C/S) 架构下,它们可以使用自家造的 RPC 协议,因为它只管连自己公司的服务器就 ok 了

但有个软件不同,浏览器(Browser) ,不管是 Chrome 还是 IE,它们不仅要能访问自家公司的服务器(Server) ,还需要访问其他公司的网站服务器,因此它们需要有个统一的标准,不然大家没法交流。于是,HTTP 就是那个时代用于统一 Browser/Server (B/S) 的协议

也就是说在多年以前,HTTP 主要用于 B/S 架构,而 RPC 更多用于 C/S 架构。但现在其实已经没分那么清了,B/S 和 C/S 在慢慢融合。*很多软件同时支持多端,比如某度云盘,既要支持*网页版 ,还要支持手机端和 PC 端**

HTTP和RPC区别

服务发现

首先要向某个服务器发起请求,你得先建立连接,而建立连接的前提是,你得知道 IP 地址和端口 。这个找到服务对应的 IP 端口的过程,其实就是服务发现

HTTP 中,你知道服务的域名,就可以通过 DNS 服务 去解析得到它背后的 IP 地址,默认 80 端口

RPC 的话,就有些区别,一般会有专门的中间服务 去保存服务名和IP信息,比如 Consul 或者 Etcd,甚至是 Redis 。想要访问某个服务,就去这些中间服务去获得 IP 和端口信息。由于 DNS 也是服务发现的一种,所以也有基于 DNS 去做服务发现的组件,比如CoreDNS

底层连接形式

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

RPC 协议,也跟 HTTP 类似,也是通过建立 TCP 长链接进行数据交互,但不同的地方在于,RPC 协议一般还会再建个连接池 ,在请求量大的时候,建立多条连接放在池内,要发数据的时候就从池里取一条连接出来,用完放回去,下次再复用

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

传输的内容

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

Header 是用于标记一些特殊信息,其中最重要的是消息体长度

Body 则是放我们真正需要传输的内容,而这些内容只能是二进制 01 串,毕竟计算机只认识这玩意。所以 TCP 传字符串和数字都问题不大,因为字符串可以转成编码再变成 01 串,而数字本身也能直接转为二进制。但结构体呢,我们得想个办法将它也转为二进制 01 串,这样的方案现在也有很多现成的,比如 Json,Protobuf。

这个将结构体转为二进制数组的过程就叫序列化 ,反过来将二进制数组复原成结构体的过程叫反序列化

对于主流的 HTTP/1.1,虽然它现在叫超文本 协议,支持音频视频,但 HTTP 设计初是用于做网页文本 展示的,所以它传的内容以字符串为主。Header 和 Body 都是如此。在 Body 这块,它使用 Json序列化结构体数据。例如:

可以看到这里面的内容非常多的冗余 ,显得非常啰嗦 。最明显的,像 Header 里的那些信息,其实如果我们约定好头部的第几位是 Content-Type,就不需要每次都真的把"Content-Type"这个字段都传过来 ,类似的情况其实在 body 的 Json 结构里也特别明显。

而 RPC,因为它定制化程度更高,可以采用体积更小的 Protobuf 或其他序列化协议去保存结构体数据,同时也不需要像 HTTP 那样考虑各种浏览器行为,比如 302 重定向跳转啥的。因此性能也会更好一些,这也是在公司内部微服务中抛弃 HTTP,选择使用 RPC 的最主要原因

上面说的 HTTP,其实特指的是现在主流使用的 HTTP/1.1HTTP/2 在前者的基础上做了很多改进,所以性能可能比很多 RPC 协议还要好 ,甚至连 gRPC 底层都直接用的 HTTP/2

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

由于 HTTP/2 是 2015 年出来的。那时候很多公司内部的 RPC 协议都已经跑了好些年了,基于历史原因,一般也没必要去换了

相关推荐
速盾cdn2 小时前
速盾:CDN是否支持屏蔽IP?
网络·网络协议·tcp/ip
yaoxin5211232 小时前
第二十七章 TCP 客户端 服务器通信 - 连接管理
服务器·网络·tcp/ip
内核程序员kevin2 小时前
TCP Listen 队列详解与优化指南
linux·网络·tcp/ip
PersistJiao3 小时前
Spark 分布式计算中网络传输和序列化的关系(一)
大数据·网络·spark
黑客Ash6 小时前
【D01】网络安全概论
网络·安全·web安全·php
->yjy6 小时前
计算机网络(第一章)
网络·计算机网络·php
摘星星ʕ•̫͡•ʔ7 小时前
计算机网络 第三章:数据链路层(关于争用期的超详细内容)
网络·计算机网络
.Ayang8 小时前
SSRF漏洞利用
网络·安全·web安全·网络安全·系统安全·网络攻击模型·安全架构
好想打kuo碎8 小时前
1、HCIP之RSTP协议与STP相关安全配置
网络·安全