RMI原理详解

RMI原理详解

绪论

RMI(Remote Method Invoke),远程方法调用框架,JDK自带的一个远程过程调用框架。用户可以基于RMI框架构建自己的分布式应用,RMI为客户端和服务器之间提供底层的通信服务。

主要组成部分

      RMI主要包括注册中心、跨JVM实例的内存对象管理、应用服务。

Ø  注册中心

提供服务的绑定、解绑、重绑、查找、列举,服务提供者需要将服务绑定到注册中心后,客户端才能够调用远程服务。Registry的接口的UML图如下:


RMI原理详解_第1张图片
 

Registry服务

 

 

注册中心涉及的类的UML图如下所示,主要包括客户端的存根RegistryImpl_Stub和服务端的骨架RegistryImpl_Skel,服务的注册调用是通过本地的存根对象和服务器的骨架进行通信的,RMI协议的通信是通过服务端UnicastRefUnicastServerRef来进行的,这二者之间封装了顶层的socket的调用。


RMI原理详解_第2张图片
 

通信层次关系图如下所示:


RMI原理详解_第3张图片
 

其中TCPTransPoint提供了socket连接,完成客户端和服务器最底层的通信服务,其中服务端的处理流程图如下所示:



RMI原理详解_第4张图片
 
 

1.       服务端在RegistryImpl启动的端口出开启服务监听,提供一个线程进行socket的接收。

2.      接受线程将创建好的socket以及客户端的信息组装起来扔给业务线程池进行处理

3.        业务线程层从socket中获取相关信息,首先根据objectid确定要访问的服务,id0的表示Registry服务,2表示DGC服务,接下来读取要访问的方法,通过一个int的数字进行标识,如0代表bind方法调用(对于一些普通的服务,是通过对方法method生成一个hash值,采用的是SHA算法)

4.      根据ObjectIDObjectTable中获取对应的RemoteObject对象,接下来交给Dispatch进行分发处理(主要是根据methodhash值定位到具体的方法),注册服务的DispatcherRegistryImpl_Skel

5.        相应的RemoteObject处理完成后将生成的对象反序列化后通过socket返回给客户端。

注意:服务的提供者不一定要和注册中心位于同一个JVM实例中,但是必须在同一台机器上,可以是同一个机器上的不同的网卡上的IP。服务的端口如果不指定的话,启动后系统会选取一个随机端口,对于要跨越防火墙的远程调用来说需要特别注意,每次一不同的端口启动的时候,如果防火墙上未配置此端口的可访问的ACL策略,访问会被拒绝。

 

Ø  服务的提供者

服务的提供者可以在虚拟机中提供对外的服务,开启服务的方式和注册服务的方式一样,服务开启的时候,会通过UnicastServerRefexportObject方法导出相应的服务(继承了Remote的接口),此时导出的RemoteObject对象是弱引用的,如果不进行服务的注册的时候,接下来的GC可能会回收掉这个对象,只有当将服务绑定到注册中心后,注册中心会给服务提供者所在的JVM发送一个固定RemoteObject对象的请求,此时这个RemoteObject对象才有一个强引用,具体可以查看Target类的实现。绑定成功后,会在注册中心生存一个这个服务的Proxy对象,这个proxy对象也引用了一个unicastRef对象,用于和服务提供者所在的服务进行通信,当去注册后,会从RegistryImplbinds中去掉对这个Proxy对象的引用,当这个proxy对象被注册中心所在的GC回收成功后,注册中心会发送一个GDC的请求到服务提供者所在的JVM,告知可以去固定这个RemoteObject服务对象,后续的GC会回收掉这个RemoteObject对象。

注意:服务提供者注册服务的时候要先查看下远端是否已经注册了该服务,重复注册的话会失败的,所以在代码的编写中一定要考虑这个服务提供者重启后的服务提供。如果存在应该重新绑定,而不是重复绑定。

 

Ø  客户端

客户端对象通过Naminglookup对象去注册中心获取注册的服务对象,客户端首先是通过RegistryImpl_stub对象和注册中心的RegistrtImpl_Skel通信来获取服务的相关的信息,注册中心会将这个服务的接口访问信息(host:port)ObjectId信息返回到客户端,客户端的RMILoaderClass会根据这些信息生成一个维护了unicastRefProxy对象,后续就可以通过这个对象直接与服务提供者进行通信请求服务了。在整个通信的过程中,Remote对象都是通过序列化为接口访问信息(host:port)ObjectId信息返回给客户端的。

注意:如果服务提供者的信息一直发生变化,可以在通信失败后重新去注册中心拉取最新的信息,以排除是服务提供者信息变化的原因导致的失败。

RMI服务的优缺点

优点:

1.      使用简单,只需要按照规范定义自己的服务对象即可

2.      支持扁平化的服务需求,一个注册中心,多个服务提供者

3.     分布式客户端处理

4.     具有一定的安全性,传输中调用的方法和请求服务均是采用HASHObjectId对应

5.      具有分布式内存管理的功能,当一个服务不去注册后,会通过远程内存管理接口来进行内存的回收

缺点:

1.     注册中心和服务提供者必须在同一台机器上,不支持分布式部署的需求

2.      服务提供者服务挂掉以后,注册中心完全感知不到,导致客户端依然会去建立连接,没有服务可用性的检测机制

3.     服务挂掉后,重启的时候需要先去注册掉原来的服务,然后再进行新服务的绑定

4.      不支持重试机制,一次失败后直接操作失败

5.      客户端需要每次请求前都需要去注册中心获取最新的服务信息

6.     序列化效率太差,支持是用的java的序列化机制,数据量大的时候,传输的无用信息很多,日后可以考虑压缩算法

7.      没有负载均衡处理,不支持多个节点提供同样的服务

8.      只能用于JAVA平台中,无法和其他语言开发的服务进行对接

9.      所有的服务均要从注册中心获取,注册中心挂掉后,所以服务均不可用,存在单点问题

10.服务端的采用的还是BIO的模式,效率上较基于NIONetty框架差很远

11.缺少服务的统计信息,流量的监控信息

 

 

你可能感兴趣的:(java,rmi)