部分内容来源:JavaGuide
RPC是什么
RPC是远程调用
RPC的原理
RPC的五个部分
为了能够帮助小伙伴们理解 RPC 原理,我们可以将整个 RPC 的核心功能看作是下面 5 个部分实现的:
- 客户端(服务消费端):调用远程方法的一端。
- 客户端 Stub(桩):这其实就是一代理类。代理类主要做的事情很简单,就是把你调用方法、类、方法参数等信息传递到服务端。
- 网络传输:网络传输就是你要把你调用的方法的信息比如说参数啊这些东西传输到服务端,然后服务端执行完之后再把返回结果通过网络传输给你传输回来。网络传输的实现方式有很多种比如最基本的 Socket 或者性能以及封装更加优秀的 Netty(推荐)。
- 服务端 Stub(桩):这个桩就不是代理类了。我觉得理解为桩实际不太好,大家注意一下就好。这里的服务端 Stub 实际指的就是接收到客户端执行方法的请求后,去执行对应的方法然后返回结果给客户端的类。
- 服务端(服务提供端):提供远程方法的一端
RPC原理图
服务端(client):以本地调用方式调用远程服务
客户端Stub(client stub):接收到调用后负责将方法,参数等封装成网络信息传输的消息体(序列化):RpcRequest
客户端Stub(clint stub):找到远程服务的地址,并将信息发送到服务提供端
服务端Stub(桩):收到信息后将消息反序列化成Java对象:RpcRequest
服务端Stub(桩):根据RpcRequest中的类,方法,方法参数等信息调用本地的方法
服务端Stub(桩):将结果封装成网络传输的消息体:RpcResponse(序列化)发送到消费端
客户端Stub(clint stub):接收到消息并将消息反序列化成Java对象:RpcResponse,这样就得到了最终结果
RPC理解误区
我们总是会把RPC想成是目前的协议减重,例如HTTP里面减少一些东西实现我们的轻量级调用
但是其实我们也可以往协议里面新增一些东西
因为RPC只是一个远程调用,并不一定说是轻量级的远程调用吗,我们可以往调用协议里面添加多一些自己的东西
有什么常见的RPC框架
Dubbo:作为一款高性能且轻量级的开源 RPC 框架,在国内互联网领域应用广泛,拥有完善的服务治理体系。
Motan:适用于 Java 的高性能 RPC 框架,具备良好的扩展性与稳定性,能满足多种业务场景需求。
gRPC:由 Google 开发的开源跨语言 RPC 框架,基于 HTTP/2 标准构建,在性能和效率上表现卓越。
Thrift:Facebook 推出的开源跨语言 RPC 框架,借助其多语言代码生成器,轻松实现不同语言间的服务调用。
OpenFeign:Spring Cloud 生态中的声明式 Web 服务客户端,简化了微服务间的调用,与 Spring Cloud 组件高度集成
HTTP和RPC
RPC属于网络协议的哪一层
四层网络协议:应用层,传输层,网络层,网络接口层
我们一般会在传输层指定我们是用TCP传输还是UDP传输
TCP是传输层的协议,而基于TCP造出来的HTTP和各类RPC协议
定义了不同消息格式的应用层协议
RPC本身并不是一个具体的协议,而是一种调用方式
而 RPC(Remote Procedure Call)又叫做远程过程调用,它本身并不是一个具体的协议,而是一种调用方式
举个例子,我们平时调用一个本地方法就像下面这样
res = localFunc(req)
如果现在这不是个本地方法,而是个远端服务器暴露出来的一个方法 remoteFunc,如果我们还能像调用本地方法那样去调用它,这样就可以屏蔽掉一些网络细节,用起来更方便,岂不美哉?
res = remoteFunc(req)
RPC 可以像调用本地方法那样调用远端方法
虽然大部分的RPC底层协议使用了TCP,然实际上不一定要使用TCP,改用UDP或者HTTP也可以实现类似的功能
纯裸TCP会有什么问题
TCP的三个特点
面向连接
可靠
基于字节流
字节流
纯裸TCP是没有任何边界的,你根本不知道到哪个地方才算是一条完整的消息
这个就是所谓的黏包问题
纯裸TCP是不能拿来直接使用的
我们需要加入一些自定义规则,用来区分边界
消息头和消息体
我们在消息头里面写清楚一个完整的包的长度是多少,然后根据这个长度接收数据,
截取出来后他们就是我们真正要传输的消息体
消息头里面还可以放一些其他东西,例如消息体是否被压缩过,或者消息体的格式之类的
这就是所谓的协议
所以基于TCP就衍生了非常多的协议,比如HTTP和RPC
既然有了RPC,那么为什么还要有HTTP呢
因为HTTP其实是一种规定的,通用的协议,是一个统一的标准
如果是一些自己研发的软件,那么就可以自家造的RPC协议,连上自己公司服务器就OK了
例如某个软件又要支持网页,又要支持pc和手机,如果我们通信协议都用RPC,那是不现实的
所以我们的HTTP协议相当于我们的一个统一的规范
HTTP和RPC的区别
服务发现
服务发现:找到IP地址和端口
HTTP中,你知道域名,就可以通过DNS服务去解析得到它背后的IP地址,默认80端口
RPC:需要一些中间服务区保存服务名和IP信息
例如Consul,Etcd,Nacos,Zookeeper甚至是Redis
由于DNS也是服务发现的一种,所以也有基于DNS去做服务发现的组件,比如CoreDNS
底层连接形式
HTTP1.1在底层TCP连接之后,会一直保持这个连接,以后的请求和响应都会复用这条连接
RPC,也是通过TCP长连接进行数据交互,不同的地方在于,RPC协议一般还会再创建一个线程池
请求量大的时候,建立多条连接放到池内,要发数据的时候就从池里取一条连接出来,用完放回去,下次再复用
一个是复用连接,一个是使用连接池
连接池有利于提升网络请求性能
传输的内容
序列化:结构体转为二进制数组
反序列化:二进制数组转为结构体
HTTP1.1叫超文本协议,支持音频视频
但HTTP设计初是用于做页面文本展示的,所以传的内容以字符串为主
Body这块,它使用JSON来序列化结构体数据
传输的内容冗余,例如我们都规定好了头部的第几位是Content-Type,就不需要每次都把这个字段传过来
为啥大部分公司内部微服务中抛弃了HTTP,选择使用RPC
1. 可以使用体积更小的Protobuf或者其他序列化协议,去保存结构体数据
2.不需要像HTTP那样考虑各种服务器的行为,例如302重定向(没有定义非常多的标准和规则,因为公司内部软件,遇到的情况没那么多)
所以性能会更好一些
为什么有了HTTP2还要有RPC协议
HTTP2的性能比大部分RPC协议都好,那为什么还有RPC协议呢?
因为HTTP2是2015年出来的,在这之前为了优化和避免一些HTTP1的问题,我们就有了RPC
后面HTTP2,HTTP3等出现后大部分公司用RPC的就少了一点
总结
HTTP和各类RPC协议就是在TCP协议上定义的应用层协议
RPC本质上不算是协议,而是一种调用方式
RPC比HTTP出现的要早,所以大部分公司内部还在使用RPC
HTTP2.0在HTTP1.1的基础上做了优化,性能比很多的RPC协议要好,但是由于近几年才出来,所以也不太可能取代掉RPC