编辑推荐: |
本文将单篇详细介绍
RPC 框架,什么是RPC?RPC原理是什么?常见RPC框架,如何进行选择?等相关内容。
本文来自于腾讯云,由火龙果软件Anna编辑推荐。 |
|
引言
在性能基础之浅谈常见接口性能压测一文中我们有简单介绍常见的 RPC 接口,本文将单篇详细介绍 RPC
框架。
什么是RPC?
RPC( RemoteProcedureCall)—远程过程调用 ,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC
协议假定某些传输协议的存在,如 TCP 或 UDP,为通信程序之间携带信息数据。在 OSI 网络通信模型中,RPC
跨越了传输层和应用层。
其实简单点的说,就是像调用本地的类的方法样来调用服务器端的方法实现。
比如两个不同的服务 A,B 部署在两台不同的机器上,那么服务 A 如果想要调用服务 B 中的某个方法该怎么办呢?使用
HTTP 请求当然可以,但是可能会比较慢而且一些优化做的并不好。 RPC 的出现就是为了解决这个问题。总之,RPC
使得开发分布式程序就像开发本地程序一样简单。
RPC原理是什么?
RPC 采用客户端(服务调用方)/服务器端(服务提供方)模式, 都运行在自己的 JVM 中。客户端只需要引入要使用的接口,接口的实现和运行都在服务器端。RPC
主要依赖的技术包括序列化、反序列化和数据传输协议,这是一种定义与实现相分离的设计。
同时在此处要对 RMI( Remote Method Invoke,远程方法调用)中的 stub (桩)和skeleton
(骨架)的概念有一点了解。RMI 的代理模式是通过代理对象将方法传递给实际对象的。stub 驻留客户端,承担着代理远程对象实现者的角色。skeleton
类帮助远程对象与 stub 连接进行通信。
服务调用方(client)调用以本地调用方式调用服务;
client stub 接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;
client stub 找到服务地址,并将消息发送到服务端;
server stub 收到消息后进行解码;
server stub 根据解码结果调用本地的服务;
本地服务执行并将结果返回给 server stub;
server stub 将返回结果打包成消息并发送至调用方;
client stub 接收到消息,并进行解码;
服务调用方得到最终结果。
主要组成元素:
实体对象和业务接口由客户端和服务端公用。
接口实现是由服务端对定义好的业务接口进行功能实现,并将接口实例注册服务中提供给客户端调用。
常见RPC框架
目前 Java 使用比较多的 RPC 方案主要有RMI(JDK自带)、Hessian、Dubbo、Hprose、Thrift
以及 HTTP 等。
注意: RPC 主要指内部服务之间的调用,RESTful 也可以用于内部服务之间的调用,但其主要用途还在于外部系统提供服务,因此没有将其包含在本知识点内。
RMI
JDK自带的RPC
Java RMI ( RemoteMethodInvocation)- 远程方法调用,能够让客户端像使用本地调用一样调用服务端
Java 虚拟机中的对象方法。RMI 是面向对象语言领域对 RPC (Remote Procedure
Call)的完善,用户无需依靠 IDL 的帮助来完成分布式调用,而是通过依赖接口这种更简单自然的方式。
Java RMI 工作原理
一个典型的 RMI 调用如下图所示:
服务端向 RMI 注册服务绑定自己的地址
客户端通过 RMI 注册服务获取目标地址,
客户端调用本地的 Stub 对象上的方法,和调用本地对象上的方法一致,
本地存根对象将调用信息打包,通过网络发送到服务端,
服务端的 Skeleton 对象收到网络请求之后,将调用信息解包,
然后找到真正的服务对象发起调用,并将返回结果打包通过网络发送回客户端。
Java RMI 基本概念
Java RMI 是 Java 领域创建分布式应用的技术基石。后续的 EJB 技术,以及现代的分布式服务框架,其中的基本理念依旧是
Java RMI 的延续。在 RMI 调用中,有以下几个核心的概念:
通过接口进行远程调用
通过客户端的 Stub 对象和服务端的 Skeleton 对象的帮助将远程调用伪装成本地调用
通过 RMI 注册服务完成服务的注册和发现
对于第一点,客户端需要依赖接口,而服务端需要提供该接口的实现。 对于第二点,在 J2SE1.5版本之前需要通过
rmic 预先编译好客户端的 Stub 对象和服务端的 Skeleton 对象。在之后的版本中,不再需要事先生成
Stub 和 Skeleton 对象。
下面通过示例代码简单的展示 RMI 中的服务注册和发现
服务端的服务注册
Hello obj = new
HelloImpl(); // #1
Hello stub = (Hello) UnicastRemoteObject.exportObject(obj,
0); // #2
Registry registry = LocateRegistry.createRegistry(1099);
// #3
registry.rebind ("Hello", stub); // #4 |
说明:
初始化服务对象实例,
通过 UnicastRemoteObject.exportObject生成可以与服务端通讯的 Stub
对象,
创建一个本地的 RMI 注册服务,监听端口为 1099。该注册服务运行在服务端,也可以单独启动一个注册服务的进程,
将 Stub 对象绑定到注册服务上,这样,客户端可以通过 Hello 这个名字查找到该远程对象。
客户端的服务发现
Registry registry
= LocateRegistry.getRegistry(); // #1
Hello stub = (Hello) registry.lookup("Hello");
// #2
String response = stub.sayHello(); // #3 |
说明:
获取注册服务实例,在本例中,由于没有传入任何参数,假定要获取的注册服务实例部署在本机,并监听在 1099
端口上,
从注册服务中查找服务名为 Hello 的远程对象,
通过获取的 Stub 对象发起一次 RMI 调用并获得结果。
理解 RMI 的工作原理和基本概念,对掌握现代分布式服务框架很有帮助,建议进一步的阅读 RMI 官方教材。
Dubbo
Dubbo是 阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和
Spring框架无缝集成。
Hessian
Hessian是一个轻量级的 remotingonhttp 工具,使用简单的方法提供了RMI的功能。
相比 WebService,Hessian 更简单、快捷。采用的是二进制RPC协议,因为采用的是二进制协议,所以它很适合于发送二进制数据。
Thrift
Apache Thrift 是 Facebook 开源的跨语言的 RPC 通信框架,目前已经捐献给
Apache 基金会管理,由于其跨语言特性和出色的性能,在很多互联网公司得到应用,有能力的公司甚至会基于
thrift 研发一套分布式服务框架,增加诸如服务注册、服务发现等功能。
详细内容可以参考:
性能工具之Jmeter压测Thrift RPC服务
Hprose
国人开发的一个远程方法调用的开源框架。它是一个先进的轻量级的跨语言跨平台面向对象的高性能远程动态通讯中间件。
详细内容可以参考:
性能工具之Jmeter压测Hprose RPC服务
HTTP
常见于 WEB 应用,基于 HTTP(S) 协议传输文本。当一个 URL发送请求时,服务端 doGet
或者 doPost 方法会被调用,获取相应的参数。压测HTTP接口时,只需要通过定位URL接口并传参,相对比较简单。
如何进行选择?
是否允许代码侵入: 即需要依赖相应的代码生成器生成代码,比如 Thrift。
是否需要长连接获取高性能: 如果对于性能需求较高的 haul,那么可以果断选择基于 TCP 的 Thrift、Dubbo。
是否需要跨越网段、跨越防火墙: 这种情况一般选择基于 HTTP 协议的Hessian 和 Thrift
的 HTTP Transport。
此外,Google 推出的基于 HTTP2.0 的 gRPC 框架也开始得到应用,其序列化协议基于
Protobuf,网络框架使用的是 Netty4 ,但是其需要生成代码,可扩展性比较差。
小结
现代 RPC 的本质其实就是在网络上传输数据包,而这个数据包的特点是Header + Body。Header
即协议头,分为定长或者变长,这个取决于协议的设计者。例如 dubbo 协议就是定长的。而有些协议是变长的。Body
就是消息体,其实就是对象序列化的过程,把序列化好的数据放入 Body 里面。现在流行的序列化方案有
Hessian,Java-built-in,JSON,MsgPack,Protobuf 等。底层框架一般使用
NIO/Netty 架构,因为是异步通信,需要支持高性能、高并发。 |