是什么,如何理解
RPC(Remote Procedure Call) 直译就是远程过程调用
HTTP(HyperText Transfer Protorl) 直译就是超文本传输协议
RPC和HTTP都是 请求-响应协议,但是因为出现的时机、设计理念、约定协议、效率、应用范围、使用规则等不同,所以是不同的名字,本质都是为了分布式系统间的通信而生,是一种应用层通信(请求-响应)协议(从OSI网络模型来看)。
RPC是 Bruce Jay Nelson 在1981年创造的术语,HTTP是在1990年左右产生的(可以参看维基百科)
RPC协议 和 RPC,到底叫什么?RPC协议=RPC
HTTP协议、HTTP,到底叫什么?HTTP协议=HTTP
RPC|HTTP只是大家的简称
- HTTP协议不仅仅只有协议,还有超文本,传输,以及很多功能(比如编解码、面试经常背的各种参数的作用)
- RPC协议也不仅仅只有协议,还有 编解码,服务注册发现,负载均衡等
RPC协议本质上定义了一种通信的流程,而具体的实现技术是没有约束的,每一种RPC框架都有自己的实现方式,我认为HTTP也是RPC的一种实现方式。
协议直白来讲是一种约定,rpc和http都是为了服务器间的通信而生,都需要制定一套标准协议来进行通信。不过HTTP比较火,是一个全世界的统一约定,使用比较广泛。但通用也意味着冗余,所以后来又产生了很多RPC框架(自定义协议,具备优秀的性能等)
我们可以自定义RPC请求/响应 包含的消息头和消息体结构,自定义编解码方式,自定义网络通信方式,只要 client和 server消息的发送和解析能对应即可,这些问题确认下来,一个RPC框架就设计出来了。
下面先从请求过程看一下RPC和HTTP都会经历哪些阶段,然后再分阶段去做对比
一次请求的过程
阶段 | 阶段分层 | RPC | HTTP |
---|---|---|---|
client: 业务逻辑xx | 业务逻辑层 | 略 | 略 |
client: 客户端构造请求,发起调用 | 编解码 | thrift|json|protobuf等 | json|图片等 |
client: 根据传输协议构造数据流 | 协议层 | thrift|gRPC|Kitex|dubbo等 | HTTP1 |HTTP1.1|HTTP2|QUIC等 |
client: 服务发现 | 服务发现 | 自定义内部服务发现组件 | DNS |
client: 网络通信:传输数据流 | 网络通信层 | 接口层:netty|netpool,根据OS的API做了一些封装本质:TCP|UDP|HTTP系列 | 接口层:HTTP内部自己实现,目前不清楚咋做的本质:TCP|UDP |
server: 把数据流解析为协议结构 | 协议层 | 略,同上 | 略,同上 |
server: 解析协议中的请求体 | 编解码 | 略,同上 | 略,同上 |
server: 执行业务逻辑xx | 业务逻辑层 | 略,同上 | 略,同上 |
从请求链路可以看到,最核心的只有三层:编解码、协议、网络通信
下面会从这3个角度去对比HTTP和RPC
HTTP VS RPC自定义协议
HTTP和RPC 2个关键词不具备可比较性,因为RPC包含了HTTP。
但是RPC自定义协议(thrift, protobuf, dubbo, kitex-thrift等) 是RPC的具体实现,HTTP也是RPC的具体实现,它们是具备可比较性的
编解码(序列化)
- 序列化: 指将程序运行过程中的动态内存数据(java的class、go的struct)转化为硬盘中静态二进制数据的过程,以方便网络传输。
- 反序列化:指将硬盘中静态二进制数据转化为程序运行过程中的动态内存数据的过程,以方便程序计算。
HTTP/1.1 一般用json
自定义RPC协议 一般用 thrift、protobuf
www.cloudwego.io/zh/docs/kit...
维度 | json(HTTP/1.1) | protobuf(gRPC) |
---|---|---|
优点 | 1. 可读性好、使用简单,学习成本低 | 1. 序列化后的体积比json小 => 传输效率高 |
- 序列化/反序列化速度快 => 性能损耗小 | | 缺点 | 1. JSON 进行序列化的额外空间开销比较大
- JSON 没有类型,比如无法区分整数和浮点1. 1. 像 Java 、Go这种强类型语言,不是很友好,解析速度比较慢(需要通过反射解决) | 1. 不可读,都是二进制 | | 适用场景 | 适用于服务提供者与服务调用者之间传输的数据量要相对较小的情况,否则会严重影响性能 | 追求高性能的场景 |
协议层
编码之后,数据转换成字节流,但是RPC通信时,每次请求发送的数据大小不是固定的,那么为了区分消息的边界,避免粘包、半包等现象,我们需要定义一种协议,来使得接收方能够正确地读出不定长的内容。简单点说,通信协议就是约定客户端和服务器端传输什么数据,以及如何解析数据。
维度 | HTTP/1.1 | kitex-TTHeader |
---|---|---|
优点 | 1. 灵活,可以自定义很多字段 |
- 几乎所有设备都可以支持HTTP协议 | 1. 灵活,通用,可以自定义1. 1. 自定义必要字段即可 => 减小报文体积,提高传输效率2. 性能优秀 | | 缺点 | 1. 包含许多为了适应浏览器的冗余字段,这些是内部服务用不到的
- 性能差 | 1. 部分设备存在不能支持,通用性欠佳 |
可参考
可以思考一下 序列化、传输协议、网络通信的关系,下面以kitex为例进行分析
kitex codec 接口定义,kitex thrift 序列化实现,kitex ttheader协议,kitex 发送请求核心代码
可以发现 Encode中,先根据message构造出header,写入out,然后再把data(实际的业务数据)写到out。
encode函数完全遵守 ttheader协议去构造数据。
最后再把out通过网络库发送出去
网络通信层
网络通信层主要提供一个易用的网络库,封装了操作系统提供的socket api。
维度 | HTTP/1.1 | kitex框架 |
---|---|---|
实现方式 | 一般采用短连接需要3次握手(可以配置长链接添加请求头Keep-Alive: timeout=20)- 长连接,指在一个连接上可以连续发送多个数据包,在连接保持期间,如果没有数据包发送,需要双方发链路检测包 | rpc框架维护一个tcp连接池,每次用完不断开连接,通过心跳检测断开连接(探测服务是否有问题)- 支持短连接、长连接池、连接多路复用以及连接池状态监控。 |
优点 | 1. 几乎所有设备都可以支持HTTP协议 | 1. 不用每次请求都经历三次握手&四次挥手,减少延时 |
缺点 | 1. 每次请求都要新建连接,性能差 | 1. 部分设备存在不能支持,通用性欠佳 |
HTTP的长连接和TCP长连接不是一个东西,需要注意下,TCP Keepalive是操作系统实现的功能,并不是TCP协议的一部分,需要在操作系统下进行相关配置(只能保证网络没问题,不能代表服务没问题)
其中 HTTP2 拥有多路复用、优先级控制、头部压缩等优势
可以参考
kitex:连接类型
RPC自定义协议 和 HTTP的使用场景
公司内部的微服务,对客户端提供的服务 适合用RPC,更好的性能
对外服务、单体服务、为前端提供的服务适合用HTTP
我的思考
rpc在编解码、协议层、网络通信 都比HTTP有更大的优势,那为啥不把HTTP换成RPC呢
-
我认为最核心的是 人的认知,HTTP已经深入人心,并且所有的机器和语言默认都会支持。但是自定义RPC协议 可能很多人都没听过(比如kitex、dubbo等),还让别人支持,根本不可能。
- 需要建设全局的DNS等等,HTTP链路中的组件都需要换成 自定义的那一套,成本极高。
- 但是公司内部可以搞成一套,可以极大提高性能,何乐而不为。
-
RPC框架 可以自定义负载均衡,重试机制,高可用,流量控制等策略。这些是HTTP不能支持的
参考
如何保活主流RPC框架长连接,Dubbo的心跳机制,值得学习_牛客博客