RPC
RPC(Remote Procedure Call),又叫做远程过程调用。不是协议,是一种调用方式。
- TCP 70年
- RPC 80年
- HTTP 90年代
为什么有 RPC 还要有 HTTP 协议
- RPC适合内部调用,自定义接口标准,多用于 C/S 架构。
- 浏览器访问其他网站需要统一的标准,HTTP 就是那个时代用于统一 Browser/Server (B/S) 的协议。
HTTP 和 RPC 有什么区别
-
服务发现:建立连接的前提是,知道 IP 地址和端口
- HTTP:域名,就可以通过 DNS 服务去解析得到它背后的 IP 地址,默认 80 端口。
- RPC:中间服务去保存服务名和IP信息,比如 Consul 或者 Etcd,甚至是 Redis。
-
底层连接形式:
-
HTTP/1.1 :其默认在建立底层 TCP 连接之后会一直保持这个连接(Keep Alive)复用。
-
RPC 协议:建立 TCP 长链接进行数据交互。还会再建个连接池,在请求量大的时候,建立多条连接放在池内,要发数据的时候就从池里取一条连接出来,用完放回去,下次再复用。
-
由于连接池有利于提升网络请求性能,所以不少编程语言的网络库里都会给 HTTP 加个连接池,比如 Go 就是这么干的。
-
-
传输的内容:基于 TCP 传输的消息,无非都是消息头 Header 和消息体 Body。
-
Header:标记一些特殊信息,其中最重要的是消息体长度。
-
Body:传输的内容,只能是二进制 01 串。将结构体转为二进制数组的过程就叫序列化,反过来将二进制数组复原成结构体的过程叫反序列化。
- HTTP:Body 这块,它使用 Json 来序列化结构体数据。
- RPC:定制化程度更高,采用体积更小的 Protobuf 或其他序列化协议去保存结构体数据。因此性能也会更好一些,这也是在公司内部微服务中抛弃 HTTP,选择使用 RPC 的最主要原因。
-
HTTP/2 在前者的基础上做了很多改进,所以性能可能比很多 RPC 协议还要好,甚至连 gRPC 底层都直接用的 HTTP/2。
为什么既然有了 HTTP/2,还要有 RPC 协议?
HTTP/2 是 2015 年出来的。那时候很多公司内部的 RPC 协议都已经跑了好些年了,基于历史原因,一般也没必要去换了。
WebSocket
如何实现服务器向Web主动推送。
-
前端定时发 HTTP 请求到服务器
- 二维码登录,有明显卡顿
-
长轮询
-
HTTP 请求将超时设置的很大,比如 30 秒,在这 30 秒内只要服务器收到了扫码请求,就立马返回给客户端网页。如果超时,那就立马发起下一次请求。
-
百度云扫码登录、RocketMQ
-
Why?
全双工 TCP,被 HTTP/1.1 用成了半双工。网页游戏这种,客户端和服务器之间都要互相主动发大量数据的场景。
How?
建立连接
-
经历了三次TCP握手之后,利用 HTTP 协议升级为 WebSocket 协议。
-
客户端添加header
-
# 升级协议成 WebSocket,带上一段随机生成的 base64 码 Connection: Upgrade Upgrade: WebSocket Sec-WebSocket-Key: T2a6wZlAwhgQNqruZ2YUyg==\r\n
-
-
HTTP 的响应如下
-
根据客户端生成的 base64 码,用某个公开的算法变成另一段字符串,发回给浏览器。
-
HTTP/1.1 101 Switching Protocols\r\n Sec-WebSocket-Accept: iBJKv/ALIW2DobfoA4dmr3JHBCY=\r\n Upgrade: WebSocket\r\n Connection: Upgrade\r\n
-
消息格式
-
数据包被叫做帧
-
opcode字段:标志这是个什么类型的数据帧。
- 等于 1 ,是指text类型(
string
)的数据包 - 等于 2 ,是二进制数据类型(
[]byte
)的数据包 - 等于 8 ,是关闭连接的信号
- 等于 1 ,是指text类型(
-
payload字段:传输的数据的长度,单位是字节。
- 值是 0~125,它就表示了 payload 全部长度,只读最开始的
7个bit
就完事了。 - 如果是
126(0x7E)
。那它表示payload的长度范围在126~65535
之间,接下来还需要再读16bit。这16bit会包含payload的真实长度。 - 如果是
127(0x7F)
。那它表示payload的长度范围>=65536
,接下来还需要再读64bit。这64bit会包含payload的长度。
- 值是 0~125,它就表示了 payload 全部长度,只读最开始的
-
payload data字段:要传输的数据,在知道了上面的payload长度后,就可以根据这个值去截取对应的数据。
-
使用场景
-
服务器和客户端(浏览器)频繁交互的大部分场景
- 网页/小程序游戏
- 网页聊天室
- 类似飞书这样的网页协同办公软件。
-
服务器主动发送给客户端