HadoopSourceAnalyse --- Nodemanager Container FSM

本文详细解析了YARN中Container的生命周期,包括初始化容器服务、加载资源、启动容器过程及状态转换等内容。深入探讨了ContainersLauncher如何使用新线程启动容器,并介绍了容器脚本和令牌的写入细节。

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

overview

上图中还有一个状态变换,从killing 到 Exited_with_failure,这个变换由事件:CONTAINER_EXITED_WITH_FAILURE 触发,执行:ExitedWithFailureTransition;

INIT_CONTAINER And RESOURCE_LOCALIZED  Handle

Container 收到该事件通知后,会首先偿试启动所有的和当前App 相关的 AuxServices,
 for (Map.Entry<String,ByteBuffer> service : csd.entrySet()) {
          container.dispatcher.getEventHandler().handle(
              new AuxServicesEvent(AuxServicesEventType.APPLICATION_INIT,
                  ctxt.getUser(), container.container.getId()
                      .getApplicationAttemptId().getApplicationId(),
                  service.getKey().toString(), service.getValue()));
        }

然年请求所有与当前用户及App相关的 localization resource,然后进入localizing 状态,等待系统加载Resource,当ResourceLocalizer成功加载Resource之后,会向Container发送:RESOURCE_LOCALIZED 事件:
 for (ContainerId container : rsrc.ref) {
        rsrc.dispatcher.getEventHandler().handle(
            new ContainerResourceLocalizedEvent(
              container, rsrc.rsrc, rsrc.localPath));
      }
当所有的Resource都成功加载之后,Container向  ContainersLauncher 发送一个LAUNCH_CONTAINER事件并进入Localized状态, ContainersLauncher将用一个新的线程 去launche container:
 Application app =
          context.getApplications().get(
              containerId.getApplicationAttemptId().getApplicationId());

        ContainerLaunch launch = new ContainerLaunch(getConfig(), dispatcher,
            exec, app, event.getContainer(), dirsHandler);
        running.put(containerId,
            new RunningContainer(containerLauncher.submit(launch), 
                launch));

在新在线程中,先会替换所有的变量(主要是log相关),并用给定的命令生成一份本地执行的脚本文件,奖后向container 发送 LAUNCH_CONTAINER 事件,然后开始执行该脚本,线程会一直等到脚 本执行结束,或被Kill掉,最后返回执行结果。

 try {
        // /// Write out the container-script in the nmPrivate space.
        List<Path> appDirs = new ArrayList<Path>(localDirs.size());
        for (String localDir : localDirs) {
          Path usersdir = new Path(localDir, ContainerLocalizer.USERCACHE);
          Path userdir = new Path(usersdir, user);
          Path appsdir = new Path(userdir, ContainerLocalizer.APPCACHE);
          appDirs.add(new Path(appsdir, appIdStr));
        }
        containerScriptOutStream =
          lfs.create(nmPrivateContainerScriptPath,
              EnumSet.of(CREATE, OVERWRITE));

        // Set the token location too.
        environment.put(
            ApplicationConstants.CONTAINER_TOKEN_FILE_ENV_NAME, 
            new Path(containerWorkDir, 
                FINAL_CONTAINER_TOKENS_FILE).toUri().getPath());

        // Sanitize the container's environment
        sanitizeEnv(environment, containerWorkDir, appDirs, localResources);
        
        // Write out the environment
        writeLaunchEnv(containerScriptOutStream, environment, localResources,
            launchContext.getCommands());
        
        // /// End of writing out container-script

        // /// Write out the container-tokens in the nmPrivate space.
        tokensOutStream =
            lfs.create(nmPrivateTokensPath, EnumSet.of(CREATE, OVERWRITE));
        Credentials creds = container.getCredentials();
        creds.writeTokenStorageToStream(tokensOutStream);
        // /// End of writing out container-tokens
      } finally {
        IOUtils.cleanup(LOG, containerScriptOutStream, tokensOutStream);
      }

发送 LAUNCH_CONAINER,并启动脚 本:
      // LaunchContainer is a blocking call. We are here almost means the
      // container is launched, so send out the event.
      dispatcher.getEventHandler().handle(new ContainerEvent(
            containerID,
            ContainerEventType.CONTAINER_LAUNCHED));

      // Check if the container is signalled to be killed.
      if (!shouldLaunchContainer.compareAndSet(false, true)) {
        LOG.info("Container " + containerIdStr + " not launched as "
            + "cleanup already called");
        ret = ExitCode.TERMINATED.getExitCode();
      }
      else {
        exec.activateContainer(containerID, pidFilePath);
        ret = exec.launchContainer(container, nmPrivateContainerScriptPath,
                nmPrivateTokensPath, user, appIdStr, containerWorkDir,
                localDirs, logDirs);
      }


LAUNCH_CONTAINER Handle

收到该事件之后,通产ContainerMonitor 监 视该container的执行。


For other complete event just ignore here;


当运行 `hadoop-haemon.sh start nodemanager` 时遇到 "找不到或无法加载指定的类 (nodemanager)" 的错误,这通常意味着Hadoop的类路径设置有问题,或者nodemanager的JAR包没有正确包含在启动环境中。以下是几种可能的解决方案: 1. **检查类路径**:确认`JAVA_HOME`环境变量指向的是正确的Java安装目录,并确保`HADOOP_CLASSPATH`包含了所有必要的Hadoop依赖JAR文件,特别是Hadoop的核心库和HDFS客户端。 ```bash export HADOOP_CLASSPATH=$(hadoop classpath) ``` 2. **重启Hadoop守护进程**:有时候仅重启`nodemanager`服务可能不足以解决问题,尝试先停止再重新启动整个Hadoop集群的服务。 ```bash hadoop-daemon.sh stop nodemanager hadoop-daemon.sh start nodemanager ``` 3. **检查日志**:查看`nodemanager`的日志文件(通常是`logs/nodemanager.out`),查找详细的错误信息,以便定位问题的具体原因。 4. **更新或重新打包JAR**:如果nodemanager相关的JAR包有变动或升级,可能需要手动添加新的JAR到类路径,或者替换旧的JAR。 5. **检查配置**:确认`core-site.xml`和`hdfs-site.xml`中的配置是否正确,特别是关于`ha.namenode.rpc-address`和`ha.namenode.http-address`这样的高可用性相关配置。 6. **权限问题**:检查nodemanager用户是否有足够的权限访问必要的文件和资源。 如果以上步骤都试过了还是无法解决,建议查看官方文档、社区论坛或者Hadoop的问题追踪系统,因为这可能是特定版本或配置的一个已知问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值