很多时候我们要知其然,也要知其所以然,所以知道如何设计一个rpc框架就很重要了。
首先我们要了解一下rpc框架到底是什么?
rpc是指的是远程过程调用,也就是说两台服务器A,B,一个应用部署在A服务器上,一个应用部署在服务器B上,想要调用B服务器上面提供的方法和函数,由于内存空间的不同,所以需要采用网络来进行调用
下面分别介绍核心 RPC 框架的重要组成:
- 客户端(Client):服务调用方。
- 客户端存根(Client Stub):存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息,再通过网络传输发送给服务端。
- 服务端存根(Server Stub):接收客户端发送过来的请求消息并进行解包,然后再调用本地服务进行处理。
- 服务端(Server):服务的真正提供者。
- Network Service:底层传输,可以是 TCP 或 HTTP。
一个完整的rpc调用过程
- 服务消费者(Client 客户端)通过本地调用的方式调用服务。
- 客户端存根(Client Stub)接收到调用请求后负责将方法、入参等信息序列化(组装)成能够进行网络传输的消息体。
- 客户端存根(Client Stub)找到远程的服务地址,并且将消息通过网络发送给服务端。
- 服务端存根(Server Stub)收到消息后进行解码(反序列化操作)。
- 服务端存根(Server Stub)根据解码结果调用本地的服务进行相关处理
- 服务端(Server)本地服务业务处理。
- 处理结果返回给服务端存根(Server Stub)。
- 服务端存根(Server Stub)序列化结果。
- 服务端存根(Server Stub)将结果通过网络发送至消费方。
- 客户端存根(Client Stub)接收到消息,并进行解码(反序列化)。
- 服务消费方得到最终结果。
常见的rpc协议有哪些呢,我们可以参考dubbo的协议?
比如现在流行的dubbo协议,就支持dubbo,rmi,hessian,http,webservice,thrift等协议
然后来简单介绍每种协议的异同点
dubbo协议:dubbo的默认协议,单一长连接nio异步传输,底层依靠tcp,毕竟适合传输小数据,
大并发的调用;不适合传输文件,视频等
rmi协议:和原生rmi类似,基于tcp,多连接短连接同步传输,适合大小包混合的场景
hessian:基于http,多连接短连接同步传输,适合传输文件
http协议:多连接短连接同步传输,大小混合型
webservice:多连接短连接同步传输,适合系统集成类型
我们要设计rpc框架,主要要考虑3块
1.服务寻址---------可以考虑用zookeeper,当作服务的注册中心,把服务端的机器的ip和端口暴露到注册中心,这样子消费端就可以从注册中心拿到找到服务端的地址
2.序列化和反序列化
因为服务端和调用端不在同一片内存空间,需要利用网络来进行传输。所以我们需要使用到序列化和反序列化,把数据转换成二进制流,这个就是序列化,把二进制流转换成对象就是反序列化
3.网络传输
这个主要是依靠网络传输层。主要依赖一些网络协议。很多rpc框架都是依靠tcp,为啥不用udp呢,因为tcp协议的话比udp更加可靠一些。可以长连接也可以短连接,比较方便。
协议的选择可以有tcp,udp,http等
这里再做一个简单的对比。用tcp协议和http协议的话有什么不同呢?
1.使用tcp协议的话,主要就是依靠建立socker来建立连接,并由服务方通过socker把方法和参数传递给提供方,然后服务方通过反序列化来调用方法
2.二使用http的话,更像是restful风格,主要依靠的是GET、POST、PUT、DELETE 等中的一种,主要是依靠utl进行方法调用,方法的参数主要是依靠xml或者json数据
从性能上来看,tcp由于是处于协议的下一层,所以网络开销是更小的,同时支撑更大的吞吐量和并发数量。但是需要更加关注底层的实现细节
而http协议的主要依靠xml和json格式响应数据,开放上面会更加容易点,但是效率上会有所欠缺
这里再做一个对比,关于rpc框架和restful架构?
1.restful主要就是几个点,资源,统一接口,uri和无状态
资源:歌曲,图片等待
2.restful风格对应的几种操作,get(获取资源),post(用来新建资源),put(用来更新资源),
delete(用来更新资源),所以利用这几种状态,就可以完成对于数据所有的增删改查
3.uri(统一资源定位符)每一个uri对应一个资源
4.无状态
rpc框架和restful风格的对比
1.面向对象
rpc比较侧重于动作,http比较侧重于资源
2.效率
rpc底层基于tcp,效率高于restful
3.复杂度
rpc大于restful
4.灵活性
restful大于rpc
双方使用的场景
1.rpc比较使用于公司内部的系统,性能消耗低,传输效率高,复杂
2.http使用于对外的异构环境,浏览器调用,三方接口调用
3.rpc框架对于子系统很多的,接口多的情况很好用。内部使用长连接,不用每次都要进行3次握手,减少网络开销
其实我们要设计一个更加完善的rpc框架,可以参考一下阿里的dubbo框架,有10层的架构
这里找几个重要的层次来说一下
服务注册层(Registry):这一层就是进行服务注册和发现,主要是结合zookeeper进行,把服务的url暴露到zookeeper上面
远程调用层(Protocol):这个是dubbo的核心。主要的思想是利用了代理模式,invoker暴露和以引用的主功能入口,它的invoke方法可以进行方法的调用
数据序列化层(Serialize):序列化层,把对象序列化成二进制流和把二进制流反序列化为对象就在这一层做的
网络传输层(transport):底层主要依靠的是netty和mina作为统一的接口
信息交换层(Exchange):封装请求响应模式,同步转异步,以Request和Response为中心
监控层(Monitor):RPC调用次数和调用时间监控
集群层(Cluster):封装多个提供者的路由及负载均衡,并桥接注册中心
服务代理层(Proxy):服务接口透明代理,生成服务的客户端Stub和服务器端Skeleton,以ServiceProxy为中心,扩展接口为ProxyFactory
配置层(Config):对外配置接口,以ServiceConfig和ReferenceConfig为中心,可以直接new配置类,也可以通过spring解析配置生成配置类。
服务接口层(Service):该层是与实际业务逻辑相关的,根据服务提供方和服务消费方的业务设计对应的接口和实现。
其实整个10层把整个rpc框架都整得明明白白了。我们上面上面说必须要考虑的3块,序列化反序列化,服务寻址,网络传输,分别就对应数据序列化层(Serialize)/服务注册层(Registry)网络传输层(transport)
另外核心调用远程调用层(Protocol)和服务代理层(Proxy)对应的就是具体的rpc调用和对应的客户端存根和服务器端服务端存根
其他的比如服务接口层(Service)信息交换层(Exchange)这个主要是跟业务有关的
配置层(Config)集群层(Cluster)监控层(Monitor)主要是为了rpc框架的高可用容易配置
想必大家看到这里应该对整个rpc框架都有一个较为清晰的认识了