Hadoop之JobTracker源码分析

本文深入分析了Hadoop中JobTracker的角色,详细探讨了JobTracker的启动过程,特别是任务调度器JobQueueTaskScheduler的工作原理,以及interTrackerServer的非阻塞异步IO实现。此外,还介绍了JobTracker如何处理client提交的任务并分配给TaskTracker。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

JobTracker源码分析


前言

JobTracker是Hadoop中的一个重要角色,负责任务的调度和分配,和client端的任务提交也有关系,这次主要分析JobTracker中JobTracker和TaskTracker心跳机制在JobTracker这端的详细实现过程以及client提交的任务是如何被处理然后分配给TaskTracker的。

JobTracker启动

在hadoop-1.1.2的src/mapred里面的org.apache.hadoop.mapred里面可以找到JobTracker.java,说到启动,JobTracker是以一个单独的进程运行的,因此可以发现JobTracker.java里面是有主函数的,进入到main()函数


  
  
  1. public static void main(String argv[]
  2. ) throws IOException, InterruptedException {
  3. //打印一条启动的日志
  4. StringUtils.startupShutdownMessage(JobTracker.class, argv, LOG);
  5. try {
  6. if(argv.length == 0) {
  7. JobTracker tracker = startTracker(new JobConf()); //核心的启动函数,在里面实例了几个重要对象
  8. tracker.offerService(); //将某些重要对象启动,作为rpcserver或者httpserver
  9. }
  10. else {
  11. if ("-dumpConfiguration".equals(argv[0]) && argv.length == 1) {
  12. dumpConfiguration(new PrintWriter(System.out));
  13. }
  14. else {
  15. System.out.println("usage: JobTracker [-dumpConfiguration]");
  16. System.exit(-1);
  17. }
  18. }
  19. } catch (Throwable e) {
  20. LOG.fatal(StringUtils.stringifyException(e));
  21. System.exit(-1);
  22. }
  23. }

进入到startTracker函数,经过几次默认参数的调用最后到达的startTracker如下


  
  
  1. public static JobTracker startTracker(JobConf conf, String identifier, boolean initialize)
  2. throws IOException, InterruptedException {
  3. DefaultMetricsSystem.initialize("JobTracker");
  4. JobTracker result = null;
  5. while (true) {
  6. try {
  7. result = new JobTracker(conf, identifier); //JobTracker构造函数,其中identifier是通过日期产生的
  8. result.taskScheduler.setTaskTrackerManager(result); //将taskScheduler的taskTrackerManager设置为JobTracker自身,这个
  9.                            //的作用在后面的代码中会说明
  10. break;
  11. } catch (VersionMismatch e) {
  12. throw e;
  13. } catch (BindException e) {
  14. throw e;
  15. } catch (UnknownHostException e) {
  16. throw e;
  17. } catch (AccessControlException ace) {
  18. // in case of jobtracker not having right access
  19. // bail out
  20. throw ace;
  21. } catch (IOException e) {
  22. LOG.warn("Error starting tracker: " +
  23. StringUtils.stringifyException(e));
  24. }
  25. Thread.sleep(1000);
  26. }
  27. if (result != null) {
  28. JobEndNotifier.startNotifier(); //开启一个Job结束的通知器,其实内部是开一个线程观察一个BlockingQueue<jobEndStatusInfo>的队列,当TaskTracker通过RPC告诉JobTracker Job的运行状态后,如果结束就会在某个地方往这个队列里面加入任务的结束状态信息,然后
  29. 该观察线程就会发出HttpNotification,而接受这个Notification的应该是JobTracker内部的一个HttpServer
  30. MBeans.register("JobTracker", "JobTrackerInfo", result);
  31. if(initialize == true) {
  32. result.setSafeModeInternal(SafeModeAction.SAFEMODE_ENTER);
  33. result.initializeFilesystem(); //初始化文件系统,其实就是通过`return FileSystem.get(conf);`返回一个文件系统类,内部有一个缓存,首先判断缓存中是否有Key(uri,conf)对象的文件系统类,有就直接返回,否则通过反射生成一个。uri是conf中fs.defult.name的属性值,如果该值没有设置则使用file:///
  34. result.setSafeModeInternal(SafeModeAction.SAFEMODE_LEAVE);
  35. result.initialize(); //初始化,主要是对JobHistory做了初始化,然后设置了httpserver的属性,并且开启了一个HDFS monitro线程,这里不是这次的关注点,可以略过
  36. }
  37. }
  38. return result;
  39. }

上个代码段中很重要的一个调用就是JobTracker的构造函数,几个重要对象例如taskScheduler和interTrackerServer以及HttpServer都是在里面实例化的。


  
  
  1. Class<? extends TaskScheduler> schedulerClass
  2. = conf.getClass("mapred.jobtracker.taskScheduler",
  3. JobQueueTaskScheduler.class, TaskScheduler.class); //其实就是看conf里面有没有配置不同的TaskScheduler,系统默认的是采用
  4. //JobQueueTaskScheduler,这个也是这次讲的时候也以它为例说明
  5. taskScheduler = (TaskScheduler) ReflectionUtils.newInstance(schedulerClass, conf); //通过反射实例化taskScheduler
  6. int handlerCount = conf.getInt("mapred.job.tracker.handler.count", 10); // Handler的个数,默认10个,Handler后面会降到,这里先略过
  7. this.interTrackerServer =
  8. RPC.getServer(this, addr.getHostName(), addr.getPort(), handlerCount,
  9. false, conf, secretManager);  //interTrackerServer是一个RPC server,它内部有listener, reader ,responder, handler这样几个比较重要的对象,用来接受处理和响应RPC请求。
  10. infoServer = new HttpServer("job", infoBindAddress, tmpInfoPort,
  11. tmpInfoPort == 0, conf, aclsManager.getAdminsAcl()); //HttpServer,也就是通过50070端口可以访问到JObTracker信息的server
  12. infoServer.setAttribute("job.tracker", this);          //不是这次的说明范围内,大致知道它是一个httpserver就行了
  13. infoServer.addServlet("reducegraph", "/taskgraph", TaskGraphServlet.class); 
  14. infoServer.start();

JobTracker中的几个重要对象

taskScheduler:任务调度器,这里以默认的JobQueueTaskScheduler来说明其作用,JobQueueTaskScheduler内部会初始化JobQueueJobInProgressListener和EagerTaskInitializationListener,其中EagerTaskInitializationListener会开启内部的一个初始化线程监听JobInitQueue,然后如果发现队列里面有待初始化的Job则取出然后调用了ttm(task tracker manager)的initJob函数,其实会发现这个ttm就是jobtracker本身,这样就会调用jobtracker的initJob函数。而jobQueueJobInProgressListener则是在jobtracker接受到client端的submitjob请求的时候会调用jobAdded添加job到jobQUeue中然后在tasktracker与jobtracker的心跳中,分发任务的时候会从jobQUeue中取出来。

intertrackerServer:其实就是一个RPC的server,但是里面通过了listener、reader、handler、responder这几个对象和NIO实现了非阻塞异步IO。其中listener主要用来监听do_accept,reader监听do_read,handler处理rpc请求内容,responder负责根据调用结果返回给client

HttpServer: 这个就是jobtracker web接口的server,这里没有具体去分析。

intertackerServer分析

intertrackerServer的启动在offerService函数中,intertrackerServer.start(),其实就是开启一个rpc server。要理解intertackerServer干了些什么,这个rpc server是如何接受和处理请求的,得从intertrackerServer = RPC.getServer看起


  
  
  1. public static Server getServer(final Object instance, final String bindAddress, final int port,
  2. final int numHandlers,
  3. final boolean verbose, Configuration conf)
  4. throws IOException {
  5. return getServer(instance, bindAddress, port, numHandlers, verbose, conf, null);
  6. }
  7. /** Construct a server for a protocol implementation instance listening on a
  8. * port and address, with a secret manager. */
  9. public static Server getServer(final Object instance, final String bindAddress, final int port,
  10. final int numHandlers,
  11. final boolean verbose, Configuration conf,
  12. SecretManager<? extends TokenIdentifier> secretManager)
  13. throws IOException {
  14. return new Server(instance, conf, bindAddress, port, numHandlers, verbose, secretManager);
  15. }
  16. //这个Server函数是RPC类中的内部类Server,它的super类是ipc.Server
  17. public Server(Object instance, Configuration conf, String bindAddress, int port,
  18. int numHandlers, boolean verbose,
  19. SecretManager<? extends TokenIdentifier> secretManager)
  20. throws IOException {
  21. super(bindAddress, port, Invocation.class, numHandlers, conf,
  22. classNameBase(instance.getClass().getName()), secretManager); //第三个参数Incocation.class需要注意,它是rpc中的调用信息 //的存储类,在这个调用中会实例化listener和responder
  23. this.instance = instance;
  24. this.verbose = verbose;
  25. }

其实可以看到,getServer最后会调用new Server生成一个rpcserver,new Server(instance, conf, bindAddress,port, numHandlers,verbose,secretManager)这个函数需要注意的是第一个参数instance,它其实就是jobtracker的实例,在RPC.Call函数中将要用到这个变量。

在jobTracker的 offerservice函数中会调用interTrackerServer.start函数,由于RPC.Server继承了ipc.Server,其实就是调用ipc.Server的start方法如下:


  
  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值