RPC和HTTP
概述
RPC(即Remote Procedure Call,远程过程调用),主要是基于TCP/IP协议;而HTTP服务主要是基于HTTP协议的。我们都知道HTTP协议是在传输层协议TCP之上的,所以效率来看的话,RPC当然是要更胜一筹啦!下面来具体说一说RPC服务和HTTP服务。
架构设计
一个完整的RPC架构里面包含了四个核心的组件,分别是Client 、Server、Client Stub、Server Stub,这个Stub大家可以理解为存根。分别说说这几个组件:
- 客户端(Client),服务的调用方。
- 服务端(Server),真正的服务提供者。
- 客户端存根(Client Stub),存放服务端的地址消息,再将客户端的请求参数打包成网络消息,然后通过网络远程发送给服务方。
- 服务端存根(Server Stub),接收客户端发送过来的消息,将消息解包,并调用本地的方法。
RPC主要是用在大型企业里面,因为大型企业里面系统繁多,业务线复杂,而且效率优势非常重要的一块,这个时候RPC的优势就比较明显了。实际的开发当中是这么做的,项目一般使用maven来管理。比如我们有一个处理订单的系统服务,先声明它的所有的接口(这里就是具体指Java中的interface),然后将整个项目打包为一个jar包,服务端这边引入这个二方库,然后实现相应的功能,客户端这边也只需要引入这个二方库即可调用了。为什么这么做?主要是为了减少客户端这边的jar包大小,因为每一次打包发布的时候,jar包太多总是会影响效率。另外也是将客户端和服务端解耦,提高代码的可移植性。
API
public interface loginService { |
Service
dubbo配置文件,通过RPC传输
|
引入api,并实现接口中的方法。
public class loginServiceImpl implements loginService{ |
Client
dubbo配置文件,通过RPC传输
|
引入api,通过RPC调用服务端方法。
public class Application { |
调用过程
客户端(client)以本地调用方式(即以接口的方式)调用服务;
客户端存根(client stub)接收到调用后,负责将方法、参数等组装成能够进行网络传输的消息体(将消息体对象序列化为二进制);
客户端通过sockets将消息发送到服务端;
服务端存根( server stub)收到消息后进行解码(将消息对象反序列化);
服务端存根( server stub)根据解码结果调用本地的服务;
本地服务执行并将结果返回给服务端存根( server stub);
服务端存根( server stub)将返回结果打包成消息(将结果消息对象序列化);
服务端(server)通过sockets将消息发送到客户端;
客户端存根(client stub)接收到结果消息,并进行解码(将结果消息发序列化);
客户端(client)得到最终结果。
RPC的目标是要把2、3、4、7、8、9这些步骤都封装起来。
注意:无论是何种类型的数据,最终都需要转换成二进制流在网络上进行传输,数据的发送方需要将对象转换为二进制流,而数据的接收方则需要把二进制流再恢复为对象。
同步与异步
什么是同步调用?什么是异步调用?同步调用就是客户端等待调用执行完成并返回结果。异步调用就是客户端不等待调用执行完成返回结果,不过依然可以通过回调函数等接收到返回结果的通知。如果客户端并不关心结果,则可以变成一个单向的调用。
这个过程有点类似于Java中的callable和runnable接口,我们进行异步执行的时候,如果需要知道执行的结果,就可以使用callable接口,并且可以通过Future类获取到异步执行的结果信息。如果不关心执行的结果,直接使用runnable接口就可以了,因为它不返回结果,当然啦,callable也是可以的,我们不去获取Future就可以了。
线程异步实例
public class TestFutureTask { |
运行结果如下:
线程1:洗茶壶 |
常见的RPC框架
gRPC:Google公布的开源软件,基于最新的HTTP2.0协议,并支持常见的众多编程语言。 我们知道HTTP2.0是基于二进制的HTTP协议升级版本,目前各大浏览器都在快马加鞭的加以支持。 这个RPC框架是基于HTTP协议实现的,底层使用到了Netty框架的支持。
- 优点
- 基于 HTTP2 的协议足够简单,用户学习成本低,天然有 server push/ 多路复用 / 流量控制能力
- 基于 Protobuf 的多语言跨平台二进制兼容能力,提供强大的统一跨语言能力
- 基于协议本身的生态比较丰富,k8s/etcd 等组件的天然支持协议,云原生的事实协议标准
- 缺点
- 对服务治理的支持比较基础,更偏向于基础的 RPC 功能,协议层缺少必要的统一定义,对于用户而言直接用起来并不容易。
- 强绑定 protobuf 的序列化方式,需要较高的学习成本和改造成本,对于现有的偏单语言的用户而言,迁移成本不可忽视
- 优点
Thrift:Facebook的一个开源项目,主要是一个跨语言的服务开发框架。它有一个代码生成器来对它所定义的IDL定义文件自动生成服务代码框架。用户只要在其之前进行二次开发就行,对于底层的RPC通讯等都是透明的。不过这个对于用户来说的话需要学习特定领域语言这个特性,还是有一定成本的。
Dubbo:阿里集团开源的一个极为出名的RPC框架,在很多互联网公司和企业应用中广泛使用。协议和序列化框架都可以插拔是及其鲜明的特色。同样的远程接口是基于Java Interface,并且依托于spring框架方便开发。可以方便的打包成单一文件,独立进程运行,和现在的微服务概念一致。
Triple协议
最终我们选择了兼容 gRPC ,以 HTTP2 作为传输层构建新的协议,也就是 Triple。
- 相较于其他协议的优势
- 性能上: Triple 协议采取了 metadata 和 payload 分离的策略,这样就可以避免中间设备,如网关进行 payload 的解析和反序列化,从而降低响应时间。
- 路由支持上,由于 metadata 支持用户添加自定义 header ,用户可以根据 header 更方便的划分集群或者进行路由,这样发布的时候切流灰度或容灾都有了更高的灵活性。
- 安全性上,支持双向TLS认证(mTLS)等加密传输能力。
- 易用性上,gRPC 强行绑定了protobuf 的序列化方式,需要较高的学习成本和改造成本;Triple 除了支持原生 gRPC 所推荐的 Protobuf 序列化外,使用通用的方式支持了 Hessian / JSON 等其他序列化,能让用户更方便的升级到 Triple 协议。对原有的 Dubbo 服务而言,修改或增加 Triple 协议 只需要在声明服务的代码块添加一行协议配置即可,改造成本几乎为 0。
- 现状
- 完整兼容grpc、客户端/服务端可以与原生grpc客户端打通
- 目前已经经过大规模生产实践验证,达到生产级别
- 特点与优势
- 具备跨语言互通的能力,传统的多语言多 SDK 模式和 Mesh 化跨语言模式都需要一种更通用易扩展的数据传输格式。
- 提供更完善的请求模型,除了 Request/Response 模型,还应该支持 Streaming 和 Bidirectional。
- 易扩展、穿透性高,包括但不限于 Tracing / Monitoring 等支持,也应该能被各层设备识别,网关设施等可以识别数据报文,对 Service Mesh 部署友好,降低用户理解难度。
- 多种序列化方式支持、平滑升级
- 支持 Java 用户无感知升级,不需要定义繁琐的 IDL 文件,仅需要简单的修改协议名便可以轻松升级到 Triple 协议
- 相较于其他协议的优势
自定义一个RPC框架
rpc-sample-client相当于client-functions,通过接口方法发起请求;
rpc-client相当于client-stub,负责把方法和参数序列化并发送给查找到的服务器;
rpc-server相当于server stub,负责把客户端发送过来的消息反序列化,并通过反射调用本地服务,再把本地服务返回的结果序列化发送给客户端;
rpc-sample-server则相当于server-functions,提供本地服务并返回得出的结果给rpc-server;
rpc-client等待接收rpc-server返回的结果,并将结果反序列化,再把反序列化最终得到的结果返回给rpc-sample-client。
rpc-common提供基于netty的序列化与反序列化方法,并封装rpc请求和rpc响应,序列化和反序列的对象就是封装好的RpcRequest和RpcResponse;
rpc-registry则是基于zookeeper设计的分布式服务器动态上下线通知的应用程序,通过rpc-registry可以查找服务器或者注册服务器,用于均衡负载;
rpc-client与rpc-server之间的通信是基于netty的,netty底层也是sockets设计,但是效率比sockets高。
HTTP
其实在很久以前,企业开发的模式一直定性为HTTP接口开发,也就是我们常说的restful风格的服务接口。对于在接口不多、系统与系统交互较少的情况下,解决信息孤岛初期常使用的一种通信手段;优点就是简单、直接、开发方便。利用现成的http协议进行传输。
接口可能返回一个JSON字符串或者是XML文档。然后客户端再去处理这个返回的信息,从而可以比较快速地进行开发。但是对于大型企业来说,内部子系统较多、接口非常多的情况下,RPC框架的好处就显示出来了,首先就是长链接,不必每次通信都要像http一样去3次握手什么的,减少了网络开销;其次就是RPC框架一般都有注册中心,有丰富的监控管理;发布、下线接口、动态扩展等,对调用方来说是无感知、统一化的操作。
二者区别
功能侧重点不同
SpringCloud:Spring公司开源的微服务框架,SpirngCloud 定位为微服务架构下的一站式解决方案。
Dubbo:阿里巴巴开源的RPC框架,Dubbo 是 SOA 时代的产物,它的关注点主要在于服务的调用和治理,流量分发、流量监控和熔断。
生态环境不同
SpringCloud生态丰富,功能完善,更像是品牌机;
Dubbo则相对灵活,可定制性强,更像是组装机。
调用方式不同
SpringCloud是采用Http协议做远程调用,接口一般是Rest风格,比较灵活;
Dubbo是采用Dubbo协议,接口一般是Java的Service接口,格式固定。但调用时采用Netty的NIO方式,性能较好。
使用场景
- RPC服务主要是针对大型企业的;
- HTTP服务主要是针对小企业的,因为虽然RPC效率和性能更高,但是HTTP服务开发迭代会更快;
- 在接口不多、系统与系统交互较少的情况下,Http通信是常使用的一种通信手段;优点就是简单、直接、开发方便。利用现成的http协议就可以进行服务间的数据传输。可以比较快速地进行开发;
- 对于大型企业来说,内部子系统较多、接口非常多的情况下,RPC框架的好处就显示出来了。首先是长链接,不必每次通信都要像http一样去3次握手,减少了网络开销;其次,RPC框架一般都有注册中心,有丰富的监控管理;发布、下线接口、动态扩展等,对调用方来说是无感知、统一化的操作。
总结
- RPC 本身是一种框架,而http 是应用层的协议。RPC可以通过HTTP来实现,也可以通过Socket自己实现一套协议来实现。
- http接口是在接口不多、系统与系统交互较少的情况下,解决信息孤岛初期常使用的一种通信手段;优点就是简单、直接、开发方便。利用现成的http协议 进行传输。但是如果是一个大型的网站,内部子系统较多、接口非常多的情况下,RPC框架的好处就显示出来了。
- 首先就是长链接,不必每次通信都要像http 一样去3次握手什么的,减少了网络开销;
- 其次就是RPC框架一般都有注册中心,有丰富的监控管理、发布、下线接口、动态扩展等,对调用方来说是无感知、统 一化的操作。
- 最后就是安全性。最后就是最近流行的服务化架构、服务化治理,RPC框架是一个强力的支撑。
- rpc是一种概念,http也是rpc实现的一种方式。论复杂度,dubbo/hessian用起来是超级简单的。最近用dubbo和hessian比较多,http的几乎都被废弃了。
- RPC的核心并不在于使用什么协议。RPC的目的是让你在本地调用远程的方法,而对你来说这个调用是透明的,你并不知道这个调用的方法是部署哪里。通过RPC能解耦服务,这才是使用RPC的真正目的。RPC的原理主要用到了动态代理模式,至于http协议,只是传输协议而已。