JAVA RPC: http://jbm3072.iteye.com/blog/1088102
目标:让客户端调用远程机器(不同JVM上)的方法.
技术:RPC(Remote Process Call远程过程调用)
优点:使用RPC,可以像使用本地的程序(本地JVM)一样使用远程服务器上的程序。使用RPC的好处是简化了远程服务访问。提高了开发效率。
做法:在分发代码时,只需要将接口分发给客户端使用,在客户端看来只有接口,没有具体类实现。这样保证了代码的可扩展性和安全性。
基础:Java反射机制,动态代理,Java IO/NIO/Socket
Server接口
public interface Server { public void stop(); public void start(); public void register(Class interfaceDefiner,Class impl); public void call(Invocation invo); public boolean isRunning(); public int getPort(); }
启动服务器
Server server = new RPC.RPCServer(); server.register(Echo.class, RemoteEcho.class); server.start(); // 1.向服务器注册接口和实现类并启动服务器
RPC
public class RPC { public static <T> T getProxy(final Class<T> clazz,String host,int port) { final Client client = new Client(host,port); InvocationHandler handler = new InvocationHandler() { // 5. 当客户端调用生成的代理对象的方法,实际上调用的是该回调方法 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Invocation invo = new Invocation(); // 封装Invocation对象,要调用的接口,接口的方法,参数 invo.setInterfaces(clazz); invo.setMethod(new com.xuyuan.j2ee.rpc.protocal.Method(method.getName(),method.getParameterTypes())); invo.setParams(args); client.invoke(invo); // 6. 客户端向服务器发送Invocation对象 return invo.getResult(); // 12. 回调方法invoke()结束,返回远程方法的执行结果 } }; // 3. 生成接口的代理对象,传入回调对象InvocationHandler.在调用接口的方法时,会调用回调方法 T t = (T) Proxy.newProxyInstance(RPC.class.getClassLoader(), new Class[] {clazz}, handler); return t; } public static class RPCServer implements Server{ private Listener listener; private Map<String ,Object> serviceEngine = new HashMap<String, Object>(); public void call(Invocation invo) { Object obj = serviceEngine.get(invo.getInterfaces().getName()); //根据接口名,找到对应的处理类(实现类) Method m = obj.getClass().getMethod(invo.getMethod().getMethodName(), invo.getMethod().getParams()); Object result = m.invoke(obj, invo.getParams()); // 9. 利用反射,调用方法,返回值设置到Invocation对象中 invo.setResult(result); } public void register(Class interfaceDefiner, Class impl) { this.serviceEngine.put(interfaceDefiner.getName(), impl.newInstance()); } public void start() { listener = new Listener(this); this.isRuning = true; listener.start(); // 1.启动服务器,监听器是个线程类,会调用run() } } }
监听器
public class Listener extends Thread { private ServerSocket socket; private Server server; public void run() { socket = new ServerSocket(server.getPort()); // 2. 创建ServerSocket,接受客户端的连接 while (server.isRunning()) { Socket client = socket.accept(); // 8. 接收客户端传递的Invocation对象,里面包含了客户端想要调用的接口,方法,参数 ObjectInputStream ois = new ObjectInputStream(client.getInputStream()); Invocation invo = (Invocation) ois.readObject(); // 9. 让服务器调用真正的目标方法 server.call(invo); // 10. 往客户端写回数据,同样给客户端发送Invocation对象 ObjectOutputStream oos = new ObjectOutputStream(client.getOutputStream()); oos.writeObject(invo); } } }
客户端
public class Client { private Socket socket; private ObjectOutputStream oos; private ObjectInputStream ois; public void invoke(Invocation invo) throws UnknownHostException, IOException, ClassNotFoundException { socket = new Socket(host, port); oos = new ObjectOutputStream(socket.getOutputStream()); // 7. 客户端向服务器写数据。因为客户端不能直接调用接口方法(在不同JVM上), // 可以通过传递带有接口,方法,参数的Invocation对象给服务器,让服务器解析出对象并真正调用方法 oos.writeObject(invo); // 11. 接收服务器返回的数据Invocation对象,对象里也含有方法的执行结果 ois = new ObjectInputStream(socket.getInputStream()); Invocation result = (Invocation) ois.readObject(); invo.setResult(result.getResult()); } }
启动客户端,调用接口的方法
Echo echo = RPC.getProxy(Echo.class, "127.0.0.1", 20382); // 3. 生成接口Echo的代理实现类 String res = echo.echo("hello,hello"); // 4. 像使用本地的程序一样来调用Echo中的echo方法
总结:
因为客户端和服务器位于不同的JVM上(不同的机器),要让客户端能够调用到服务器上的某个类的某个方法,需要让客户端和服务器能够进行远程通信。
远程通信需要协议。 这里的协议就是Echo接口。 暴露给客户端的是Echo接口的某个方法。在服务器上有Echo接口的具体实现。
所以我们的目的是客户端能够调用到位于服务器上的Echo接口的实现类的某个方法。
Invocation:
负责客户端和服务器的数据交互,即客户端想要调用哪个接口,哪个方法,方法带有什么参数。以及服务器返回给客户端方法的执行结果。
需要实现序列化,因为要在网络环境下传输。
InvocationHandler:
回调对象,客户端调用接口的方法,实际上会调用回调方法invoke()
在回调方法里,封装了客户端要调用的接口,方法,参数。封装成Invocation对象
回调方法结束,客户端调用接口的方法的过程也就结束了。具体是怎么调用接口的方法:
Client:
将上面封装好的Invocation对象,通过Socket或者NIO编程发送给服务器。
而服务器的监听器一直在监听客户端的数据
将封装了接口,方法,参数的Invocation发送给服务器的目的是让服务器调用位于服务器上的接口的实现类的方法。
Listener:
负责监听客户端的写入数据, ==》监听到客户端发送的Invocation对象,读取出来
委托给Server调用客户端想要调用的方法, ==》Invocation对象包含了客户端想要调用的接口,方法,参数
调用方法结束后,向客户端回写数据 ==》调用方法的返回值也一并封装到Invocation对象传输给客户端
Server:
取得客户端发送的Invocation对象后,解析出接口,方法,参数。这样服务器就知道了客户端想要调用的接口和方法
这里还有一个过程,就是在服务器启动的时候,要先注册接口和接口的实现类的关系。
这样当客户端传递含有接口名字(也只能传递接口)的Invocation对象时,服务器就能知道该接口对应的实现类。
利用反射机制,真正调用到服务器上的接口的实现类的方法,并传入参数
Client:
服务器调用接口实现类的方法结束后,还会返回Invocation对象给客户端。
客户端同样能解析出Invocation对象,取得返回值。这样客户端仅仅和接口打交道,隐藏了数据交互的过程。
服务器启动时序图
客户端连接服务器时序图
Hadoop的RPC采用客户机/服务器模式。请求程序就是一个客户机, 而服务提供程序就是一个服务器。当我们讨论HDFS时, 通信可能发生在:
情景 |
服务器 |
Client-NameNode |
NameNode |
Client-DataNode |
DataNode |
DataNode-NameNode |
NameNode |
DataNode-DateNode |
某一个DateNode是服务器, 另一个是客户端 |
如果我们考虑Hadoop的Map/Reduce以后, 这些系统间的通信就更复杂了。为了解决这些客户机/服务器之间的通信, Hadoop引入了一个RPC框架。该RPC框架利用的Java的反射能力, 避免了某些RPC解决方案中需要根据某种接口语言(如CORBA的IDL)生成存根和框架的问题。
IPC
实现RPC的一种方法,具有快速、简单的特点。 它不像Sun公司提供的标准RPC包,基于Java序列化。
IPC无需创建网络stubs和skeletons。
IPC中的方法调用要求参数和返回值的数据类型必须是Java的基本类型,String和Writable接口的实现类,以及元素为以上类型的数组。
接口方法应该只抛出IOException异常。
使用模型 采用客户/服务器模型
Server:它把Java接口暴露给客户端。指定好监听端口和接受远程调用的对象实例后,通过RPC.getServer()可以得到Server实例。
Client:连接Server,调用它所暴露的方法。Client必须指定远程机器的地址,端口和Java接口类,通过RPC.getClient()可以得到Client实例。
Server不可以向Client发出调用,但在Hadoop中,有双向调用的需求。 比如在DFS,NameNode和DataNode需要互相了解状态。
相关推荐
本文将深入探讨Hadoop的RPC机制,解析其工作原理,并结合源码分析其内部实现。 一、RPC简介 RPC是一种让程序能够调用运行在其他地址空间(通常在另一台机器上)的程序的方法。在Hadoop中,RPC被广泛用于NameNode、...
### Hadoop源码分析(client部分) #### Hadoop概述 Hadoop是一个开源的分布式存储与计算框架,由Apache基金会维护。它为用户提供了处理和存储海量数据的能力,并且能够运行在低成本的商品硬件集群上。Hadoop的...
### Hadoop源码分析知识点详解 #### 一、Hadoop及其核心技术背景 Hadoop作为一款开源的分布式计算框架,其核心思想来源于Google发布的几篇重要论文。这些论文详细阐述了Google构建其分布式计算平台的关键技术和...
### Hadoop源码阅读总结:IPC/RPC 通信机制详解 #### 一、概述 Hadoop作为分布式计算框架,其内部各个组件之间的通信主要通过RPC(Remote Procedure Call)实现。本文将详细介绍Hadoop中RPC机制的工作原理,特别是...
Hadoop 培训课程(2)HDFS 分布式文件系统与HDFS HDFS体系结构与基本概念*** HDFS的shell操作*** java接口及常用api*** ---------------------------加深拓展---------------------- ...HDFS的分布式存储架构的源码分析**
10-hdfs下载数据源码分析-getFileSystem2.avi 第三天 mapreduce的原理和编程 01-hdfs源码跟踪之打开输入流.avi 02-hdfs源码跟踪之打开输入流总结.avi 03-mapreduce介绍及wordcount.avi 04-wordcount的编写和...
### Hadoop RPC 深入理解 #### 一、引言 ...通过以上分析可以看出,Hadoop RPC 不仅提供了一个高效的通信框架,还通过对细节的精确控制确保了高性能和服务的可靠性。这对于构建大型分布式系统来说至关重要。
### Hadoop架构设计与源码分析 #### Hadoop简介 Hadoop是一个能够对大量数据进行分布式处理的软件框架,由Apache基金会开发。它能够提供高可靠性、高扩展性以及高效的数据处理能力,被广泛应用于大数据处理领域。 ...
总的来说,Hadoop源码分析涵盖了分布式文件系统的设计原理、分布式计算模型的实现以及相关的通信、安全和监控机制。深入理解Hadoop的源码,有助于开发者更好地利用这个框架来处理大数据问题,同时也能为优化分布式...
源码分析可以从以下几个方面入手: 1. 源码结构:了解项目目录结构,如src/main/java下的org.apache.hadoop.hbase目录,包含了所有主要模块的源代码。 2. 主要组件:深入研究RegionServer、MasterServer、Client等...
10-hdfs下载数据源码分析-getFileSystem2.avi 第三天 mapreduce的原理和编程 01-hdfs源码跟踪之打开输入流.avi 02-hdfs源码跟踪之打开输入流总结.avi 03-mapreduce介绍及wordcount.avi 04-wordcount的编写和...
5. **环境配置**:编译Hadoop源码前,还需要确保Java Development Kit (JDK) 已安装,并且`JAVA_HOME`环境变量设置正确。Hadoop 2.9.x可能需要特定版本的JDK,因此请确保使用的JDK版本与Hadoop兼容。 6. **编译流程...
分布式Java应用基础与实践源码分析 在当前的互联网时代,分布式系统已经成为企业级应用的主流架构。Java作为广泛使用的编程语言,其在分布式领域的应用非常广泛。本篇将深入探讨分布式Java应用的基础知识和实践要点...
- Java提供了多种RPC框架,如Hadoop的Hadoop RPC、Apache Thrift、Google的gRPC以及本案例中的Gene-RPC-Framework。它们都利用Java的网络编程接口来实现跨进程通信。 3. **服务提供者和服务消费者**: - 服务提供...
Hadoop的RPC基于Java的Protocol Buffers,提供高效、灵活的序列化和反序列化能力,确保跨网络的数据交换效率。 五、安全通信与身份验证 Hadoop支持Kerberos等安全协议,用于确保客户端和服务端的身份验证和授权。...
在深入分析Hadoop源代码的过程中,我们关注到其在数据通信和序列化方面的重要机制。Hadoop并没有简单地采用Java自带的序列化方法,而是设计了一套自有的系统,这主要是为了提高性能、可扩展性和跨平台兼容性。在...
NameNode源码分析(RPC是基础) DataNode源码分析 FileSystem源码分析(如何与NameNode通信ClientProtocol) JobTracker源码分析 TaskTracker源码分析 网站日志分析项目(这个项目分析可以让你更加掌握好所学的知识...
《深入解析Hadoop之HBase 0.99.2源码分析》 在当今的信息化社会,大数据处理已经成为企业核心竞争力的关键要素。Hadoop作为开源大数据处理框架的领头羊,其生态中的HBase更是备受关注。HBase是基于Google Bigtable...