Spring YARN 应用模型

工程 | Janne Valkealahti | 2014年2月6日 | ...

既然 Thomas 刚刚发布了 Spring for Apache Hadoop 的第五个里程碑版本,我想借此机会谈谈其新特性 Spring YARN 的最新进展。

我们Spring IO 平台的一个优势是其技术的互操作性。Spring Boot 和 Spring YARN 如何协同工作以创建更好的 Hadoop YARN 应用开发模型就是一个很好的例子。在这篇博客文章中,我想展示一个全新的 Spring Yarn 应用模型的示例,该模型在很大程度上基于Spring Boot

Spring YARN 简介

从开发者开始工作到有人在 Hadoop 集群上实际执行应用程序,其开发生命周期比仅仅编写几行代码要复杂一些。让我们看看需要考虑什么

  • 应用程序代码的项目结构是什么
  • 项目如何构建和打包
  • 打包好的应用程序如何配置
  • 应用程序如何执行

我们相信 Spring YARN 和 Spring Boot 提供了一个简单的编程模型,可以轻松地将应用程序测试和部署为 YARN 应用程序或传统应用程序。

从高层次来看,Spring YARN 提供了三个组件:YarnClientYarnAppmasterYarnContainer,它们反映了 YARN 架构中的关键过程。这三个组件共同构成了 Spring YARN 应用模型的基础。

在 Hadoop 集群上打包和执行自己的代码一直是一个繁琐的过程。需要将编译后的包放到 Hadoop 的 classpath 中,或者让 Hadoop 的工具在作业提交期间将包复制到 Hadoop 中。一旦你完成了 WordCount 之外的工作,你的代码将依赖于 Hadoop 默认 classpath 中不存在的第三方库。你应该如何打包你的依赖库?此外,如果你的依赖项与 Hadoop 默认 classpath 中已有的库发生冲突怎么办?

Spring Boot 提供了一个优雅的解决方案来解决这些构建和打包问题。你可以创建一个可执行的 jar 包(有时称为 uber 或 fat jar),它将你的应用程序代码及其所有依赖项捆绑到一个 .jar 文件中;或者创建一个 zip 文件,可以在代码执行前解压。这两种打包格式的主要区别在于,后者允许你重用 Hadoop 默认 classpath 中已有的 jar 包。

在本指南中,我们将展示如何使用 Spring Boot 将这三个组件:YarnClientYarnAppmasterYarnContainer 打包成可执行 jar。Spring Boot 内部高度依赖应用程序的自动配置,而 Spring YARN 添加了其自身的自动配置魔法。用户可以将精力集中在自己的代码和应用程序配置上,而不是花费大量时间去理解所有组件如何相互集成。

现在我们将向您展示如何轻松地创建自定义应用程序并将其部署到 Hadoop 集群。请注意,无需使用 XML。

创建 Yarn Container

在这里,您将创建 ContainerApplicationHelloPojo 类。

@Configuration
@EnableAutoConfiguration
public class ContainerApplication {

	public static void main(String[] args) {
		SpringApplication.run(ContainerApplication.class, args);
	}

	@Bean
	public HelloPojo helloPojo() {
		return new HelloPojo();
	}

}

在上面的 ContainerApplication 中,请注意我们如何在类级别本身添加了 @Configuration 注解,以及为 helloPojo() 方法添加了 @Bean 注解。我们之前提到了 YarnContainer 组件,它是容器中执行代码的接口。您可以定义自己的自定义 YarnContainer 来实现此接口并将所有逻辑封装在该实现中。

然而,如果未定义 YarnContainer,Spring YARN 将默认使用 DefaultYarnContainer,此默认实现期望找到一个具有容器应执行的实际逻辑的特定 bean。这有效地创建了一个简单的模型,其中最少只需一个简单的 POJO 即可。

@YarnContainer
public class HelloPojo {

	private static final Log log = LogFactory.getLog(HelloPojo.class);

	@Autowired
	private Configuration configuration;

	@OnYarnContainerStart
	public void publicVoidNoArgsMethod() {
		log.info("Hello from HelloPojo");
		log.info("About to list from hdfs root content");
		FsShell shell = new FsShell(configuration);
		for (FileStatus s : shell.ls(false, "/")) {
			log.info(s);
		}
	}

}

从某种意义上说,HelloPojo 类是一个简单的 POJO,它不扩展任何 Spring YARN 基类。我们在此类中做了什么

  • 我们添加了一个类级别的 @YarnContainer 注解。
  • 我们添加了一个方法级别的 @OnYarnContainerStart 注解
  • 我们 @Autowired 注入了 Hadoop 的 Configuration

@YarnContainer 本身是一个 stereotype 注解,其中定义了 Spring 的 @Component。这会自动将一个类标记为具有 @YarnContainer 功能的候选类。

在此类中,我们可以使用 @OnYarnContainerStart 注解来标记一个没有返回类型或参数的 public 方法,使其作为需要在 Hadoop 上执行的功能。

为了演示此类中确实有一些实际功能,我们简单地使用 Spring Hadoop 的 @FsShell 来列出 HDFS 文件系统的根目录下的条目。为此,我们需要访问 Hadoop 的 Configuration,它已经为您准备好,您可以直接 autowire 注入。

创建 Yarn Client

在这里,您将创建一个 ClientApplication 类。

@EnableAutoConfiguration
public class ClientApplication {

	public static void main(String[] args) {
		SpringApplication.run(ClientApplication.class, args)
			.getBean(YarnClient.class)
			.submitApplication();
	}

}
  • @EnableAutoConfiguration 告诉 Spring Boot 根据 classpath 设置、其他 bean 以及各种属性设置开始添加 bean。
  • 由于 Spring YARN 在 classpath 中,因此会发生 Spring YARN 组件的特定自动配置。

main() 方法使用 Spring Boot 的 SpringApplication.run() 方法启动应用程序。然后我们只需请求一个 YarnClient 类型的 bean 并执行其 submitApplication() 方法。接下来发生什么取决于应用程序配置,我们将在本指南后面介绍。

创建 Yarn Appmaster

在这里,您将创建一个 AppmasterApplication 类。

@EnableAutoConfiguration
public class AppmasterApplication {

	public static void main(String[] args) {
		SpringApplication.run(AppmasterApplication.class, args);
	}

}

用于 YarnAppmaster 的应用程序类看起来比我们为 ClientApplication 所做的还要简单。同样,main() 方法使用 Spring Boot 的 SpringApplication.run() 方法启动应用程序。

有人可能会争辩说,如果你使用这种虚拟类来基本启动你的应用程序,我们能否直接使用一个泛型类来实现?简单的答案是肯定的,我们甚至为此目的提供了一个泛型 SpringYarnBootApplication 类。你可以将其定义为可执行 jar 的主类,并在 gradle 构建过程中完成此操作。

然而,在实际应用中,您很可能需要开始为您的应用程序组件添加更多自定义功能,您可以通过添加更多 bean 来实现这一点。为此,您需要定义一个 Spring @Configuration@ComponentScan。然后 AppmasterApplication 将作为您定义更多自定义功能的主要起点。

创建应用程序配置

创建一个新的 yaml 配置文件。

spring:
  yarn:
    appName: yarn-boot-simple
    applicationDir: /app/yarn-boot-simple/
    fsUri: hdfs://localhost:8020
    rmAddress: localhost:8032
    schedulerAddress: localhost:8030
    client:
      appmasterFile: yarn-boot-simple-appmaster-0.1.0.jar
      files:
       - "file:build/libs/yarn-boot-simple-container-0.1.0.jar"
       - "file:build/libs/yarn-boot-simple-appmaster-0.1.0.jar"
    appmaster:
      containerCount: 1
      containerFile: yarn-boot-simple-container-0.1.0.jar

应用程序的最后一部分是其运行时配置,它将所有组件粘合在一起,然后可以称为 Spring YARN 应用程序。此配置作为 Spring Boot 的 @ConfigurationProperties 的来源,并包含无法自动发现或否则需要由最终用户覆盖的相关配置属性。

然后,您可以为自己的环境编写默认配置。由于这些 @ConfigurationProperties 由 Spring Boot 在运行时解析,您甚至可以轻松地通过使用命令行选项或提供额外的配置文件来覆盖这些属性。

构建应用程序

本博客中使用的示例代码可以在 GitHub 上的我们的spring-hadoop-samples仓库中找到。

签出我们的示例后,从 boot/yarn-boot-simple 目录发出 gradle build 命令。

$ cd boot/yarn-boot-simple
$ ./gradlew clean build

对于这个示例,我们希望保持项目结构简单。我们不会在本博客中详细介绍 gradle 构建文件,但简单来说,我们将从一个项目创建三个不同的 jar 文件。在实际应用中,可能会使用多项目模型,其中每个子项目创建自己的 jar 文件。

运行应用程序

现在您已经成功编译并打包了您的应用程序,是时候做有趣的部分,在 Hadoop YARN 上执行它了。

下面的列表显示了成功进行 gradle 构建后的文件。

$ ls -lt build/libs/
-rw-r--r-- 1 hadoop hadoop 35975001 Feb  2 17:39 yarn-boot-simple-container-0.1.0.jar
-rw-r--r-- 1 hadoop hadoop 35973937 Feb  2 17:39 yarn-boot-simple-client-0.1.0.jar
-rw-r--r-- 1 hadoop hadoop 35973840 Feb  2 17:39 yarn-boot-simple-appmaster-0.1.0.jar

只需运行您的可执行客户端 jar。

$ java -jar build/libs/yarn-boot-simple-client-0.1.0.jar

使用 Resource Manager UI,您可以查看应用程序的状态。

Resource Manager UI

要查找 Hadoop 的应用程序日志,请在配置的 userlogs 目录中进行查找。

$ find hadoop/logs/userlogs/|grep std
hadoop/logs/userlogs/application_1391348442831_0001/container_1391348442831_0001_01_000002/Container.stdout
hadoop/logs/userlogs/application_1391348442831_0001/container_1391348442831_0001_01_000002/Container.stderr
hadoop/logs/userlogs/application_1391348442831_0001/container_1391348442831_0001_01_000001/Appmaster.stdout
hadoop/logs/userlogs/application_1391348442831_0001/container_1391348442831_0001_01_000001/Appmaster.stderr

Grep HelloPojo 类记录的输出。

$ grep HelloPojo hadoop/logs/userlogs/application_1391348442831_0001/container_1391348442831_0001_01_000002/Container.stdout
[2014-02-02 17:40:38,314] boot - 11944  INFO [main] --- HelloPojo: Hello from HelloPojo
[2014-02-02 17:40:38,315] boot - 11944  INFO [main] --- HelloPojo: About to list from hdfs root content
[2014-02-02 17:40:41,134] boot - 11944  INFO [main] --- HelloPojo: FileStatus{path=hdfs://localhost:8020/; isDirectory=true; modification_time=1390823919636; access_time=0; owner=root; group=supergroup; permission=rwxr-xr-x; isSymlink=false}
[2014-02-02 17:40:41,135] boot - 11944  INFO [main] --- HelloPojo: FileStatus{path=hdfs://localhost:8020/app; isDirectory=true; modification_time=1391203430490; access_time=0; owner=jvalkealahti; group=supergroup; permission=rwxr-xr-x; isSymlink=false}

恭喜!您刚刚开发了一个 Spring YARN 应用程序!

订阅 Spring 新闻邮件

保持与 Spring 新闻邮件的联系

订阅

领先一步

VMware 提供培训和认证,助您加速进步。

了解更多

获得支持

Tanzu Spring 通过一项简单的订阅提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

近期活动

查看 Spring 社区的所有近期活动。

查看全部