【hadoop二次开发】模仿源码,手写一个RPC过程调用

Hadoop RPC

RPC(Remote Procedure Call)-远程过程调用,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议(比如TCP\UDP)。
代码实现
添加pom依赖

<dependency>
			<groupId>org.apache.hadoop</groupId>
			<artifactId>hadoop-client</artifactId>
			<version>2.7.0</version>
</dependency>

在hadoop集群中,namenode和datanode通信依赖于rpc

创建一个demo工程(hadoopProject)

在这里插入图片描述
这个是总工程下的pom文件

再创建两个子工程rpc-client和rpc-server,代表两个服务器。
实现rpc,
首先在client客户端下面pom文件导入服务端依赖,因为client远程去调用server服务端。
在这里插入图片描述

rpc-server工程

再来看rpc-server怎么实现rpc服务的,先在java目录下hadoop.rpc中创建一个协议,这个协议其实是一个接口。
接口中有内容的,第一件事写上版本号(long versionID = 1234L;);然后写一个抽象方法(void mkdir(String path);)实现远程过程调用,让客户端去调用它。
在这里插入图片描述
然后实现服务端的代码(就像hadoop中namenode就是一个服务端,从参照物角度datanode就是一个客户端),实现ClientProtocol2接口,实现mkdir()方法,然后再实现服务端具体功能,在这里namenode里面是有main函数的,通过main函数来驱动服务端功能调用。
在main函数中,开始构建rpc,使用建造者模式(new RPC.builder()),通过这种模式建造一个rpc对外提供调用,首先指定configuration加载配置文件,然后考虑加载后这个rpc的地址是哪里(.setBindAddress(“localhost”)),提供的端口号是多少(.setPort(9999)),然后绑定协议(.setProtocol(ClientProtocol2.class)),然后再设置一下实例(.setInstance(new NameNodePpcServer()))指明在哪启动的,最后进行构建(.build()),声明一个名称(final RPC.Server server = new RPC.builder()…)。这里会报错,常识问题,rpc是远程调用,意味着跨网络的请求,这个网络不见准稳定,会出现网络拥堵,松动等,rpc可能就会出现异常,失败等现象,这时需要进行抛异常trycath处理,这里抛异常。
抛完异常后就可以启动服务端了server.start();,就有了服务端的rpc,可以进行客户端的调用。
在这里插入图片描述

rpc-client工程

创建DFSClient文件,客户端只是远程调用,不用关心协议是什么,在这里写个main函数作为驱动,调用RPC的动态代理模式(RPC.getProxy()),用来代理协议,这里需要知道getProxy传入什么参数。

在RPC.java源码文件中:

 /** Construct a client-side proxy object that implements the named protocol,
   * talking to a server at the named address. 
   * @param <T>*/
  public static <T> T getProxy(Class<T> protocol,//协议
                                long clientVersion,//版本号即versionID
                                InetSocketAddress addr, //动态代理代理哪台机器的内容,这台机器的地址,端口号
                                Configuration conf,
                                SocketFactory factory) throws IOException {
    return getProtocolProxy(
        protocol, clientVersion, addr, conf, factory).getProxy();
  }

参数填充完,也是报错,因为也是跨网络,需要抛异常。
然后可以进行远程过程调用了。
现在有两个工程rpc-client和rpc-server,rpc-server提供两个一个mkdir方法,客户端需要去了解协议是什么,通过代理即可访问mkdir方法,创建一个/usr/local路径。
在这里插入图片描述
首先启动服务端rpc-server,然后启动客户端rpc-client,这样服务端就可以打印了。
在这里插入图片描述
如果需要扩展其他功能,只需在当前的协议(ClientProtocol2接口)里创建抽象对象。
在这里插入图片描述
然后谁实现了它,在实现它的类中实现该抽象方法。
在这里插入图片描述
有了这个方法之后,客户端不需要去了解服务端协议里改变了什么,可以直接去调用。
在这里插入图片描述

RPC总结

1.动态代理,通过服务端暴露了一个接口(ClientProtocol2),不需要了解这个接口里面的内容,只需要通过动态代理拿到服务端的方法。
2.反射,怎么反射,getProxy
3.序列化,跨网络调用要了解序列化
4.非阻塞异步IO(NIO),不可缺少

疑问 :
Hadoop fs -mkdir /XXXXX. 是在服务端执行、还是在客户端执行的?
是在服务端执行的具体操作
在hadoop源码中是通过RPC封装的类将参数传递到服务端执行的

接口ClientProtocol2去掉versionID版本号,其他类不报错,这时启动服务端,再启动客户端,服务端会运行异常。

log4j:WARN No appenders could be found for logger (org.apache.hadoop.metrics2.lib.MutableMetricsFactory).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Exception in thread "main" java.lang.RuntimeException: java.lang.NoSuchFieldException: versionID
	at org.apache.hadoop.ipc.RPC.getProtocolVersion(RPC.java:174)
	at org.apache.hadoop.ipc.WritableRpcEngine$Invocation.<init>(WritableRpcEngine.java:114)
	at org.apache.hadoop.ipc.WritableRpcEngine$Invoker.invoke(WritableRpcEngine.java:242)
	at com.sun.proxy.$Proxy4.mkdir(Unknown Source)
	at hadoop.rpc.DFSClient.main(DFSClient.java:18)
Caused by: java.lang.NoSuchFieldException: versionID
	at java.lang.Class.getField(Class.java:1703)
	at org.apache.hadoop.ipc.RPC.getProtocolVersion(RPC.java:170)
	... 4 more

说明RPC中versionID是必不可少的。

如果自写RPC框架,
需要先定好有哪些协议,哪些功能,这时谁来实现这个协议谁就是服务端,

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值