Spring YARN 应用模型

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

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

我们Spring IO Platform 的一个优势在于其技术的互操作性。一个很好的例子是 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 的类路径中,或者让 Hadoop 的工具在作业提交期间将您的包复制到 Hadoop 中。一旦你完成了 WordCount,你的代码将依赖于 Hadoop 默认类路径中不存在的第三方库。你应该如何打包你的依赖库?此外,如果你的依赖项与 Hadoop 默认类路径中已有的库冲突怎么办?

Spring Boot 有助于为这些构建和打包问题提供优雅的解决方案。您可以创建一个可执行的 jar 包(有时称为 uber 或 fat jar),它将您的应用程序代码及其所有依赖项捆绑到单个 .jar 文件中,或者创建一个 zip 文件,可以在代码即将执行之前将其解压。这两种打包格式的主要区别在于,后者允许您重复使用 Hadoop 默认类路径中已有的 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 来实现此接口,并将所有逻辑封装到该实现中。

但是,如果未定义,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 本身就是一个原型注解,其中定义了 Spring 的 @Component。这会自动将一个类标记为具有 @YarnContainer 功能的候选类。

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

为了证明我们在这个类中确实有一些实际的功能,我们简单地使用 Spring Hadoop 的 @FsShell 来列出 HDFS 文件系统根目录中的条目。为此,我们需要访问 Hadoop 的 Configuration,该配置已为您准备好,因此您可以直接将其自动装配。

创建 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 根据类路径设置、其他 bean 和各种属性设置开始添加 bean。
  • 由于 Spring YARN 位于类路径中,因此会进行 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://127.0.0.1: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

使用资源管理器 UI,您可以查看应用程序的状态。

Resource Manager UI

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

$ 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

搜索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://127.0.0.1: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://127.0.0.1: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 社区中所有即将举行的活动。

查看全部