Hadoop RPC机制

一、RPC基础概念

1.1 RPC的基础概念

RPC,即Remote Procedure Call,中文名:远程过程调用

(1)它允许一台计算机程序远程调用另外一台计算机的子程序,而不用去关心底层的网络通信细节,对我们来说是透明的。因此,它经常用于分布式网络通信中。

RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式程序在内的应用程序更加容易。

(2)Hadoop的进程间交互都是通过RPC来进行的,比如NameNode和DataNode之间,JobTracker和TaskTracker之间等。

因此,可以说:Hadoop的运行就是建立在RPC基础之上的。

1.2 RPC的显著特点

(1)透明性:远程调用其他机器上的程序,对用户来说就像是调用本地方法一样;

(2)高性能:RPC Server能够并发处理多个来自Client的请求;

(3)可控性:JDK中已经提供了一个RPC框架——RMI,但是该框架过于重量级并且可控之处比较少,所以Hadoop RPC实现了自定义的RPC框架。

1.3 RPC的基本流程

RPC

(1)RPC采用了C/S的模式;

(2)Client端发送一个带有参数的请求信息到Server;

(3)Server接收到这个请求以后,根据发送过来的参数调用相应的程序,然后把自己计算好的结果发送给Client端;

(4)Client端接收到结果后继续运行。

1.4 Hadoop中的RPC机制

同其他的RPC框架一样,Hadoop RPC分为四个部分:

(1)序列化层:Client与Server端通信传递的信息采用了Hadoop里提供的序列化类或自定义的Writable类型;

(2)函数调用层:Hadoop RPC通过动态代理以及Java反射实现函数调用;

(3)网络传输层:Hadoop RPC采用了基于TCP/IP的scoket机制;

(4)服务器端框架层:RPC Server利用Java NIO以及采用了事件驱动的I/O模型,提高RPC Server的并发处理能力。

Hadoop RPC在整个Hadoop中应用非常广泛,Client、DataNode、NameNode之间的通讯全靠它了。例如:我们平时操作HDFS的时候,使用的是FileSystem类,它的内部有个DFSClient对象,这个对象负责与NameNode打交道。在运行时,DFSClient在本地创建一个NameNode的代理,然后就操作这个代理,这个代理就会通过网络,远程调用到NameNode的方法,也能返回值。

Hadoop RPC

1.5 Hadoop RPC涉及技术

(1)动态代理

动态代理可以提供对另一个对象的访问,同时隐藏实际对象的具体实现,代理对象对客户隐藏了实际对象。目前Java开发包中提供了对动态代理的支持,但现在只支持对接口的实现。

(2)反射——动态加载类

(3)序列化

(4)非阻塞的异步I/O(NIO)

二、如何使用RPC

2.1 Hadoop RPC对外提供的接口

Hadoop RPC对外主要提供了两种接口(见类org.apache.hadoop.ipc.RPC),分别是:

(1)public static <T> ProtocolProxy <T> getProxy()/waitForProxy(...)

构造一个客户端代理对象(该对象实现了某个协议),用于向服务器发送RPC请求。

(2)public static ServerRPC.Builder(Configuration).build()

为某个协议(实际上是Java接口)实例构造一个服务器对象,用于处理客户端发送的请求。

2.2 使用Hadoop RPC的四大步骤

(1)定义RPC协议

RPC协议是客户端和服务器端之间的通信接口,它定义了服务器端对外提供的服务接口。

(2)实现RPC协议

Hadoop RPC协议通常是一个Java接口,用户需要实现该接口。

(3)构造和启动RPC Server

直接使用静态类Builder构造一个RPC Server,并调用函数start()启动该Server。

(4)构造RPC Client并发送请求

使用静态方法getProxy构造客户端代理对象,直接通过代理对象调用远程端的方法。

三、RPC应用实例

3.1 定义RPC协议

如下所示,我们定义一个IProxyProtocol通信接口,声明一个add()方法:

package com.rpc.interfaces;

import org.apache.hadoop.ipc.VersionedProtocol;

public interface IProxyProtocol extends VersionedProtocol {

	static final long VERSION = 23234L;  //版本号,默认情况下,不同版本号的RPC Client和Server之间不能相互通信
	int add(int num1, int num2);
	
}

需要注意的是:

(1)Hadoop中所有自定义RPC接口都需要继承VersionedProtocol接口,它描述了协议的版本信息。

(2)默认情况下,不同版本号的RPC Client和Server之间不能互相通信,因此客户端和服务端通过版本号标识。

3.2 实现RPC协议

Hadoop RPC协议通常是一个Java接口,用户需要实现该接口。对IProxyProtocol接口进行简单的实现如下所示:

package com.rpc.server.proxy;

import java.io.IOException;

import org.apache.hadoop.ipc.ProtocolSignature;

import com.rpc.interfaces.IProxyProtocol;

public class MyProxy implements IProxyProtocol {

	@Override
	public ProtocolSignature getProtocolSignature(String protocol, long clientVersion,
			int clientMethodHash) throws IOException {
		return this.getProtocolSignature(protocol, clientVersion, clientMethodHash);
	}

	@Override
	public long getProtocolVersion(String protocol, long clientVersion) throws IOException {
		System.out.println("MyProxy.ProtocolVersion = " + IProxyProtocol.VERSION);
		return IProxyProtocol.VERSION;
	}

	@Override
	public int add(int num1, int num2) {
		System.out.println("invoke method add()");
		return num1 + num2;
	}

}

这里实现的Add方法很简单,就是一个加法操作。为了查看效果,这里通过控制台输出一句:“我被调用了!”。

3.3 构造RPC Server并启动服务

这里通过RPC的静态方法getServer来获得Server对象,如下代码所示:

package com.rpc.server;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.ipc.RPC;
import org.apache.hadoop.ipc.RPC.Server;

import com.rpc.interfaces.IProxyProtocol;
import com.rpc.server.proxy.MyProxy;

public class MyServer {
	
	public static int PORT = 5555;
	public static String IP_ADDRESS = "127.0.0.1";
	
	public static void main(String[] args) throws Exception {
		MyProxy proxy = new MyProxy();
		Server server = new RPC.Builder(new Configuration())
			.setProtocol(IProxyProtocol.class)
			.setBindAddress(IP_ADDRESS)
			.setPort(PORT)
			.setInstance(proxy)
			.build();
		server.start();
	}

}

这段代码的核心在于RPC.getServer方法,该方法有四个参数,第一个参数是被调用的Java对象,第二个参数是服务器的地址,第三个参数是服务器的端口。获得服务器对象后,启动服务器。这样,服务器就在指定端口监听客户端的请求。到此为止,服务器就处于监听状态,不停地等待客户端请求到达。

3.4 构造RPC Client并发出请求

这里使用静态方法getProxy或waitForProxy构造客户端代理对象,直接通过代理对象调用远程端的方法,具体如下所示:

package com.rpc.client;

import java.io.IOException;
import java.net.InetSocketAddress;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.ipc.RPC;

import com.rpc.interfaces.IProxyProtocol;

public class MyClient {
	
	private static String SERVER_IP = "127.0.0.1";
	private static int SERVER_PORT = 5555;
	
	public static void main(String[] args) {
		InetSocketAddress inetSocketAddress = new InetSocketAddress(SERVER_IP, SERVER_PORT);
		try {
			IProxyProtocol proxy = RPC.waitForProxy(IProxyProtocol.class,
					IProxyProtocol.VERSION, inetSocketAddress, new Configuration());
			int result = proxy.add(10, 25);
			System.out.println("10 + 25 = " + result);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}

以上代码中核心在于RPC.waitForProxy(),这方法有四个参数,第一个参数是被调用的接口类第二个是客户端版本号,第三个是服务端地址。返回的代理对象,就是服务端对象的代理,内部就是使用java.lang.Proxy实现的。

经过以上四步,我们便可利用Hadoop RPC搭建一个非常高效的客户机-服务器网络模型。

3.5 查看运行结果

(1)启动服务端,开始监听客户端请求

server

(2)启动客户端,开始向服务器发请求

client

(3)查看服务端状态,是否被调用


从上面的RPC调用中,可以看出:在客户端调用的业务类的方法是定义在业务类的接口中的。该接口实现了VersionedProtocol接口。

(4)现在我们执行jps命令,查看输出信息,会出现如下图信息:


从上图可以看到一个Java进程“MyServer”,该进程正是我们刚刚运行的RPC的服务端类MyServer。因此,大家可能联想到我们搭建Hadoop环境时,也执行过该命令用来判断Hadoop的相关进程是否全部启动。

其实Hadoop启动时产生的5个进程也应该是RPC的服务端。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值