有时候客户端需要使用责任链模式来完成一些复杂的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!