实验目的

掌握GOF设计模式的代理模式

了解掌握socket编程、java反射、动态代理

了解NIO、多线程

掌握hadoop的RPC框架使用API

实验原理

1.什么是RPC
  在hadoop出现以前,我们写的程序一般都是单机版本,只能在一台机器上处理,而一台机器的处理能力总是有限的,hadoop让我们可以写出分布式程序,将多台节点联合到一起进行处理。分布式程序的各节点之间通信需要依靠网络,一种简单的思路就是部署一个Web服务器,例如tomcat,但是这样会使得整个架构太庞大冗余。通俗地讲,我们需要自己实现一个更加轻量级的通信规则框架,这就是我们说的RPC通信框架。
  RPC(Remote Procedure Call)—远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。所以我们知道,一个RPC框架分为客户端和服务端,客户端发送一个请求给服务端,服务端调用对应的方法逻辑,将得到的结果返回给客户端,整个过程就是这么简单,但是实现起来需要考虑网络带宽,执行性能等多方面的因素。

2.如何实现一个RPC框架
  代理模式是面向切面编程常使用的设计模式,动态代理是jdk帮助我们提供的工具,我们可以利用InvocationHandle类和Proxy类来动态的调用代理类的方法。
  我们实现一个简单的RPC过程为:

1.Client端获取一个RPC代理对象proxy。

2.调用proxy上的方法,被InvocationHandler实现类 Invoker的invoke()方法捕获。

3.invoke()方法内将RPC请求封装成 Invocation实例,再向Server发送RPC请求。

4.Server端循环接收RPC请求,对每一个请求都创建一个Handler线程处理。

5.Handler线程从输入流中反序列化出Invocation实例,再调用Server端的实现方法。

6.调用结束,向Client端返回调用结果。

3.hadoop的RPC框架
  Hadoop中RPC机制建立在Java的DynamicProxy(动态代理)、NIO、socket编程的基础上, 我们可以在Client端调用Server端方法, 就像调用本地方法一样,而屏蔽了中间的复杂过程。

实验环境

1.操作系统
  操作机:Windows_7
  操作机默认用户名:hongya,密码:123456

2.实验工具
  IntelliJ IDEA

 

 

IDEA 全称IntelliJ IDEA,是java语言开发的集成环境,IntelliJ在业界被公认为最好的java开发工具之一,尤其在智能代码助手、代码自动提示、重构、J2EE支持、Ant、JUnit、CVS整合、代码审查、 创新的GUI设计等方面的功能可以说是超常的。IDEA是JetBrains公司的产品,这家公司总部位于捷克共和国的首都布拉格,开发人员以严谨著称的东欧程序员为主。

  优点:
  1.最突出的功能自然是调试(Debug),可以对Java代码,JavaScript,JQuery,Ajax等技术进行调试。
  2.其他编辑功能抛开不看,这点远胜Eclipse。
  3.首先查看Map类型的对象,如果实现类采用的是哈希映射,则会自动过滤空的Entry实例。 不像Eclipse,只能在默认的toString()方法中寻找你所要的key。
  4.其次,需要动态Evaluate一个表达式的值,比如我得到了一个类的实例,但是并不知晓它的API,可以通过Code Completion点出它所支持的方法,这点Eclipse无法比拟。
  5.最后,在多线程调试的情况下,Log on console的功能可以帮你检查多线程执行的情况。

  缺点:
  1.插件开发匮乏,比起Eclipse,IDEA只能算是个插件的矮子,目前官方公布的插件不足400个,并且许多插件实质性的东西并没有,可能是IDEA本身就太强大了。
  2.在同一页面中只支持单工程,这为开发带来一定的不便,特别是喜欢开发时建一个测试工程来测试部分方法的程序员带来心理上的不认同。
  3.匮乏的技术文章,目前网络中能找到的技术支持基本没有,技术文章也少之又少。
  4.资源消耗比较大,建个大中型的J2EE项目,启动后基本要200M以上的内存支持,包括安装软件在内,差不多要500M的硬盘空间支持。(由于很多智能功能是实时的,因此包括系统类在内的所有类都被IDEA存放到IDEA的工作路径中)。

  特色功能:
  智能选择
  丰富的导航模式
  历史记录功能
  JUnit的完美支持
  对重构的优越支持
   编码辅助
  灵活的排版功能
   XML的完美支持
  动态语法检测
  代码检查
  等等。

步骤1:修改映射,查看开发环境

  1.1首先进入操作机C:\Windows\System32\drivers\etc\hosts,修改映射(以实验IP为准)。见下图:

 

 

1.2打开电脑,双击我们的编辑器idea64的图标,进入找到本地课程所在的代码包,在hellohadoop|src|com.hongya|day009,里面的两个包分别是两个试验内容,代码已经实现好,大家可以自己新建代码包,自己重新实现一遍。

 

 

 

 2.1客户端定义我们要实现的操作的类:Login。大家打开代码"com.hongya|day009|myrpc|client|Login"可以看到,Login是一个接口,只有一个未实现的方法!

 

 

2.2服务端定义Login的实现类:LoginImpl。大家打开代码"com.hongya|day009|myrpc|server|LoginImpl"可以看到,实现了它的login方法!

 

 

2.3定义Invocation,此类是用来传递客户端和服务器端的联系参数的代码为:"com.hongya|day009|myrpc|server|Invocation",内容为class、方法名、参数、返回值。

 

 

 

 

 

 

 2.4定义MyInvocationHandler,实现java的InvocationHandler接口代码为:"com.hongya|day009|myrpc|server|MyInvocationHandler",我们主要看他的invoke方法实现,可以看出它将我们要调用的class、方法名、参数通过ObjectOutputStream写出到socket,然后得到socket的返回值。

 

 

 

 

 

 

 

 

 

 

2.5定义RPCServer,不断监听端口的请求代码为:"com.hongya|day009|myrpc|server|RPCServer"此部分代码比较复杂,主要是启动一个线程,对客户端写来的数据进行解析,然后调用对应的方法,将返回值写进socket流。

 

 

 

 

 

 

 

 

 

 

 

 

2.6定义ClientTest和ServerTest。都在"com.hongya|day009|myrpc"包下,每个都有main方法。其中server端是监听端口产生代理对象,client是调用RPC的的getProxy方法得到代理对象,调用login方法。

 

 

3.1理清代码逻辑。这部分比较复杂,需要大家思路清晰,整个代码如下:

 

 

我们的调用顺序是:ServerTest启动,new一个RPCServer,调用start方法,启动线程监听,Client启动,得到代理的Proxy类,调用login方法,将请求封装为Invocation向socket发送ObjectOutputStream,Server端线程监听到后,得到Invocation类,执行对应方法,返回结果给client。

  3.2启动Server端。点开ServerTest,点击右边绿色三角形,run,结果如图:

 

 

 

 

启动程序以后可能会报异常,这和本地环境有关系,只要程序还没停止,就可以继续实验。判断进程是否停止的方法可以看最后的步骤6:关闭进程。

 

 

3.3Client调用。点开ClientTest,点击右边绿色三角形,点击"run",客户端的并没有实现Login的方法,但是依然有输出,因为远程调用了Server端的方法。我们的服务器如果不在本地,也可以实现类似的功能

 

 

 

 

关闭进程。参考步骤6。

步骤4:使用hadoop自带的RPC框架的API

  4.1Client端自定义接口。接口的完全限定名为:com.hongya|day009|hadooprpc|LoginProtocol。注意这里和自定义的RPC框架有所不同,需要添加一个versionId的属性,这是hadoop框架规定的。

 

 

 

 

4.2Server端的实现类。实现类为:com.hongya|day009|hadooprpc|LoginProtocolImpl,和自定义一样,只需要实现具体方法

 

 

 

 

 

 

4.3Server端启动监听代码。实现类为:com.hongya|day009|hadooprpc|Server,方法内容和自定义的Server端类似。注意代码内容,需要按照hadoop的API实现,这部分的源代码全部在org.apache.hadoop.ipc.RPC中:

RPC.Server server = new RPC.Builder(new Configuration()).setBindAddress("localhost").setPort(8888)

                .setProtocol(LoginProtocol.class).setInstance(new LoginProtocolImpl()).build();

        server.start();

 

 

 

 

 

 

4.4Client端发送远程请求。注意这里的Client和Server端的Ip都是localhost,通过本地模拟远程通信,如果你可以和别人合作,也可以修改这里的IP地址,但是注意Client和Server要保持一致。

 

 

 

 

 

 

步骤5:测试基于Hadoop的PRC通信实例

  5.1理清思路逻辑。这时候我们只有这四各类,一个接口和他的实现类、一个客户端程序、一个服务端程序。因为我们利用hadoop自带的RPC框架,调用过程和上面自定义的框架是一样的,只是中间的动态代理和Socket通信以及多线程监听由hadoop实现了。

 

 

5.2启动服务端,点击Server类右边的绿色三角形,启动程序:

 

 

5.3启动客户端,点击LoginClient类右边的绿色三角形,启动客户端程序,启动服务端后,不停止的话,会一直运行这个进程。然后可以多次执行步骤5.2,每次都会输出我们在LoginProtocolImpl实现的逻辑。这里报的异常信息和本地环境有关系,可以忽略。

 

 

步骤6:关闭进程

  6.1注意每次运行程序控制台会有输出信息,如果左边还有一个红点,就没有停止,实验结束需要点一下这个红点,停止这个进程: