1. JobClient(题外话,自己翻译了一下JobClient的运行机制):
JobClient是用户提交的信息与JobTracker交互的主要接口。它提供的功能有:提交作业,跟踪作业进度,访问作业报告和进度,获取MR集群的状态等。
作业提交过程:
a. 检查作业的输入输出是否合乎规范;
b. 为作业计算出InputSplit(单个Mapper需要执行的部分);
c. 如有需要,为DistributedCache设置一些必要的统计信息;
d. 将作业的jar文件和配置文件copy到分布式系统的目录中;
e. 提交作业给JobTracker, 并且有选择地或者说随意地侦听其作业状态。
通常来说用户创建应用程序,通过JobConf设定一些配置参数,然后使用JobClient来提交作业,并且监视作业进度:
下面例子说明怎样使用JobClient:
* // 创建新的JobConf对象
* JobConf job = new JobConf(new Configuration(), MyJob.class);
*
* // 指定一些配置参数
* job.setJobName("myjob");
*
* job.setInputPath(new Path("in"));
* job.setOutputPath(new Path("out"));
*
* job.setMapperClass(MyJob.MyMapper.class);
* job.setReducerClass(MyJob.MyReducer.class);
*
* // 提交作业,然后一直监视作业进度,直到其完成
* JobClient.runJob(job);
作业控制
<p>有时候客户端需要使用责任链模式来完成一些复杂的job,这是相当容易实现的。因为前一个job输出到分布式文件系统的结果能够成为下一个job的输入。然而,这些作业能够成功完成完全依赖于这些client的正确控制。在这样的情境下,作业控制选择有:
runJob: 只有在前面的作业完成后才提交作业;
submitJob: 提交作业,然后监视正在运行的作业进度,进行作业调度决策;
setJobEndNotificationURI:设置一个作业完成的提示,并停止监听。
2. JobTracker
它是网络环境中实现提交和跟踪作业的核心。我们可以从它实现的接口中,猜测它的功能:
MRConstants
一些默认参数的定义,比如mapred.disk.healthChecker.interval,检查磁盘间隔
InterTrackerProtocol
与TaskTracker进行交互,如发送心跳、报告错误等
JobSubmissionProtocol 与JobClient进行交互,如提交作业、管理作业以及任务
TaskTrackerManager
管理集群上的TaskTrackers,这个接口主要是为了测试JobTracker,不建议用户继承使用
RefreshUserMappingsProtocol 安全相关的协议,JobTracker和NameNode都实现了它
RefreshAuthorizationPolicyProtocol
更新当前使用的服务层的认证策略
AdminOperationsProtocol
管理操作,服务于框架,不建议用户使用
JobTrackerMXBean
JobTracker自身的一些信息
3. RPC实现机制
有关VersionedProtocol的基本都是基于RPC实现,我们下面来分析一下JobSubmissionProtocol,其他同理。
JobSubmissionProtocol是JobTracker和JobClient用来交流的协议, JobTracker实现了这个接口中的所有方法。JobClient通过这个接口来调用JobTracker中的方法来提交作业,使其运行并监控作业状态。
在JobTracker的构造方法:JobTracker(final JobConf conf, String identifier, Clock clock, QueueManager qm) 中可以找到下面的代码:
this.interTrackerServer = RPC.getServer(this, addr.getHostName(), addr.getPort(), handlerCount,
false, conf, secretManager);
也就是JobTracker作为RPC协议中的Server,那么聪明的你已经想到JobClient肯定也会监听这个接口,通过RPC,使用本地代理调用Server端的接口。好的,那么我们去找JobClient端的相应代码,Server和Client连接的接口JobSubmissionProtocol是个很好的线索:
JobSubmissionProtocol rpcJobSubmitClient =
(JobSubmissionProtocol)RPC.getProxy(
JobSubmissionProtocol.class,
JobSubmissionProtocol.versionID, addr,
UserGroupInformation.getCurrentUser(), conf,
NetUtils.getSocketFactory(conf, JobSubmissionProtocol.class),
0,
RetryUtils.getMultipleLinearRandomRetry(
conf,
MAPREDUCE_CLIENT_RETRY_POLICY_ENABLED_KEY,
MAPREDUCE_CLIENT_RETRY_POLICY_ENABLED_DEFAULT,
MAPREDUCE_CLIENT_RETRY_POLICY_SPEC_KEY,
MAPREDUCE_CLIENT_RETRY_POLICY_SPEC_DEFAULT
)
);
果然不出所料,通过如上的代码,在Client端建立Server的proxy对象,那么就可以进行使用了。方法的实现是在Server端的。
4. 下面贴出自己的模拟实现代码,多多指教!
NameNoder:
package rpc;
import java.io.IOException;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.ipc.RPC;
import org.apache.hadoop.ipc.RPC.Server;
public class NameNoder implements TestProtocol{
/**
* @param instance the instance whose methods will be called
* @param conf the configuration to use
* @param bindAddress the address to bind on to listen for connection
* @param port the port to listen for connections on
* @param numHandlers the number of method handler threads to run
* @param verbose whether each call should be logged
*/
public static String ADDRESS = "hdfs://will-vm1";
public static int PORT = 9000;
/**
* shift + alt + L 快速生成变量
* shife + alt + M 抽取方法
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
Server server = RPC.getServer(new NameNoder(), ADDRESS, PORT, new Configuration());
server.start();
}
@Override
public long getProtocolVersion(String protocol, long clientVersion)
throws IOException {
return TestProtocol.version;
}
@Override
public String clientMethod(String str) {
return "(In server) This is clientMethod --- " + str;
}
}
DataNoder:
package rpc;
import java.io.IOException;
import java.net.InetSocketAddress;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.ipc.RPC;
import org.apache.hadoop.ipc.VersionedProtocol;
public class DataNoder {
/** Construct a client-side proxy object that implements the named protocol,
* talking to a server at the named address.
* 构造一个实现客户端的代理对象,这个代理对象实现了protocol
* @throws IOException */
public static void main(String[] args) throws IOException {
TestProtocol proxy = (TestProtocol) RPC.waitForProxy(TestProtocol.class,
TestProtocol.version,
new InetSocketAddress(NameNoder.ADDRESS, NameNoder.PORT),
new Configuration());
final String result = proxy.clientMethod("test");
System.err.println(result);
RPC.stopProxy(proxy);
}
}
TestProtocol:
package rpc;
import org.apache.hadoop.ipc.VersionedProtocol;
public interface TestProtocol extends VersionedProtocol{
public static long version = 234324324;
public String clientMethod (String str);
}
敬请指教! Any sugesstions will be appreciated!