Voidbox: Docker on Hadoop在hulu的实战

于2017-03-29由小牛君创建

分享到:



Voidbox- Docker on Hadoop

一个YARN上基于Docker的计算框架

杨华辉,董西成,梁宇明

1. Voidbox设计动机

YARN是Hadoop 2.0中的分布式资源管理系统,能够对集群中的各类计算框架(比如MapReduce和Spark等)进行统一的管理和调度,同时使用轻量级隔离方案cgroups对应用程序进行隔离,避免彼此之间的干扰。然而,目前YARN对环境依赖复杂和隔离性需求高的应用程序支持不足,而这些正是Docker容器技术的优势。

Docker是近两年非常流行的容器虚拟化技术,可以自动化打包部署绝大部分应用,它使得任何程序能够运行在资源隔离的容器环境,从而提供了一套更加优雅的项目构建、发布、运行的解决方案。

为了整合YARN和Docker各自的独特优势,Hulu北京大数据团队开发了Voidbox。Voidbox是一个分布式的计算框架,利用YARN作为资源管理模块,用Docker作为执行任务的引擎,从而让YARN既可以调度传统的MapReduce和Spark等类型的应用程序,也可以调度封装在Docker镜像中的应用程序。Voidbox带来了如下几点好处:

● 降低编写分布式程序的复杂度

Voidbox处理了在分布式计算系统开发中面临的共同问题,比如集群服务发现,动态资源调度,任务间协调,灾难恢复等。使用Voidbox提供的接口,用户可以很容易地实现一个分布式的应用程序。

● 简化部署

传统的做法中,我们会给某个依赖环境复杂的应用申请一个特定的虚拟机,这个虚拟机镜像一般很大而且不容易进行多实例部署。Voidbox实现了资源的动态调度,只会在程序需要运行时分配资源,大大减少了运维虚拟机的成本。

● 提高集群利用率

Spark/Mapreduce和Voidbox应用程序混合部署在同一个集群,最大化集群的利用率。

综上,YARN作为大数据平台中的数据操作系统,其地位得到了进一步巩固和增强。

Voidbox支持基于Docker Container的DAG(有向无环图)任务,提供命令行方式与IDE方式等多种应用程序提交方式,满足了生产环境和开发环境的需求。此外,Voidbox可以配合Jenkins,GitLab,私有的Docker仓库完成一整套开发、测试、自动发布的流程。

2. Voidbox 架构设计

2.1 YARN架构图

YARN允许不同的应用程序在同一个集群中动态地共享资源,以下是一个应用程序运行在YARN中的架构图:

图1 YARN系统架构

如图1所示,客户端向Resource Manager提交一个应用程序,Resource Manager根据应用的需求分配资源,启动应用程序的管理程序Applicaiton Master,Application Master负责这个应用生命周期内的任务调度。各模块功能:

● ResourceManager:负责YARN集群资源的管理与调度。

● NodeManager:运行在工作节点的机器上,负责该机器的任务执行,并收集机器信息,通过心跳汇报给Resource Manager

● Container:在YARN集群中,Container是CPU,内存等资源的抽象。用户可以在Container里运行任何程序。

● HDFS: Hadoop的分布式文件系统。

2.2 系统总体设计架构图

在Voidbox中,YARN负责集群的资源调度,Docker作为一个执行引擎,从Docker Registry中拉取镜像执行。Voidbox负责为基于容器的DAG任务申请资源,运行Docker任务。


图2 Voidbox系统架构
如图2所示,每个黑线框代表一台机器,上面运行着几个模块。为了更清晰的描述,这里分成三大模块介绍,下面主要介绍Voidbox模块和Docker模块:

● Voidbox组件:

○ VoidboxClient:客户端程序。用户可通过该组件管理Voidbox应用程序(Voidbox应用程序包含一个或多个Docker作业,一个作业包含一个或多个Docker任务),比如提交和杀死Voidbox应用程序等。

○ VoidboxMaster:实际上是一个YARN的Application Master,负责向YARN申请资源,并将得到的资源进一步分配给内部的Docker任务。

○ VoidboxDriver:负责单个Voidbox应用程序的任务调度。Voidbox支持基于Docker Container的DAG任务调度并且在任务之间可以插入其他用户代码,Voidbox Driver负责处理DAG任务之间的依赖顺序调度以及运行用户代码。

○ VoidboxProxy:是YARN与Docker引擎之间的桥梁,负责中转YARN发向Docker引擎的命令,比如启动或杀死Docker容器等。

○ StateServer:维护各个Docker引擎的健康状况信息,向Voidbox Master提供可运行Docker Container的机器列表,使得Voidbox Master可以更有效地申请资源。

● Docker组件:

○ DockerRegistry:存储Docker镜像,作为内部Docker镜像的版本管理工具。

○ DockerEngine: Docker Container执行的引擎,从Docker Registry获取相应的Docker镜像,执行Docker相关命令。

○ Jenkins:配合GitLab进行应用程序的版本管理,当应用版本更新时,Jenkins负责编译打包,生成Docker镜像,上传至Docker Registry,从而完成应用程序自动发布的流程。

2.3 工作模式

Voidbox提供两种应用程序运行模式,分别是yarn-cluster模式和yarn-client模式。

yarn-cluster模式中应用程序的控制组件和资源管理组件都运行在集群中,Voidbox应用程序提交成功后,客户端可以随时退出而不影响集群中应用程序的运行。yarn-cluster模式适合生产环境提交应用程序。

yarn-client模式中应用程序的控制组件运行在客户端,其他组件运行在集群中,客户端可以看到关于应用程序运行状态的更多信息,客户端退出后,在集群中运行的应用程序也随即退出。yarn-client模式可以方便用户进行调试。下面我们简要介绍两种模式的实现架构和原理:

● yarn-cluster模式


图3 yarn-cluster模式运行

如图3所示Voidbox Master和Voidbox Driver都运行在集群中,Voidbox Driver负责控制业务逻辑,Voidbox Master负责申请资源,释放资源。

● yarn-client模式


图4 yarn-client模式运行

如图4所示,Voidbox Master运行在集群机器里,Voidbox Driver运行在Voidbox Client里。对于yarn-client模式,用户可以直接在IDE中提交应用程序,方便用户进行调试。

2.4工作流程

下面选取yarn-cluster模式,介绍从提交到运行结束的工作流程:

1.用户使用Voidbox API编写应用程序(Voidbox提供了DAG编程模型,详见第4节),打包成一个jar包,并用Voidbox Client提交到集群中;

2.ResourceManager接收到客户端提交的应用程序,为Voidbox Master分配资源,并启动;

3.VoidboxMaster启动Voidbox Driver,后者根据Voidbox应用程序的代码逻辑将之应用程序分解成若干个Docker作业,作业又包含若干Docker任务,并调用Voidbox Master的接口,为这些任务申请资源并分发到各个结点上运行;

4.VoidboxMaster向Resource Manager申请资源,Resource Manager根据集群资源情况为其分配YARN Container,Voidbox Master在YARN Container中启动Voidbox Proxy,由后者负责与Docker引擎通信,启动Docker容器;

5.用户任务在Docker容器中运行,并把日志输出到本地文件中,用户通过YARN Web界面可以实时看到应用程序的日志输出;

6.Docker任务全部结束后,日志会被聚集到HDFS中,这样在应用程序运行结束后,用户仍然可以通过YARN Web界面跳转到history server,查看应用程序的历史日志。

2.5 Docker与YARN的资源管理整合

YARN作为集群中的统一资源管理者,负责所有机器上的资源管理和调度;而Docker作为一个容器技术,同样具有资源管理的功能,如何整合两者的资源管理功能显得尤为重要。

在YARN中,用户任务只能运行在YARN Container中,而Docker Container只能由Docker引擎管理,这摆脱了YARN的管理,破坏了YARN的资源统一管理和调度功能,从而可能产生资源泄露等风险。为了让YARN可以管理和调度Docker Container,需要在YARN和Docker之间构建一层代理,这正是Voidbox Proxy引入的原因。YARN通过Voidbox Proxy管理Docker Container的生命周期,包括启动,停止等。

为了更清晰地理解Voidbox Proxy的作用,这里以YARN停止Voidbox应用程序为例进行说明。当用户杀死Voidbox应用程序,YARN需要回收应用程序的所有资源,此时,YARN向该应用程序涉及的机器发送杀死YARN Container命令,该命令由对应的Voidbox Proxy捕获,并进一步传递给Docker引擎执行,从而完成资源回收。避免仅回收YARN Container,而使Docker引擎无法释放资源造成资源泄露(开源版本存在此问题,具体见YARN-1964)。

3. 容错性设计

虽然Docker目前有稳定的版本发布,但是企业生产环境的机器以及操作系统内核等版本多种多样,给Docker带来不稳定的因素。所以Voidbox从多个层面考虑容错设计,保证Voidbox高可用。

● VoidboxMaster容错

ResouceManager通过心跳发现VoidboxMaster程序异常退出时,会通知NodeManager回收属于这个作业的所有YARN Container,然后重新启动Voidbox Master。

● VoidboxProxy容错

VoidboxProxy和Voidbox Master之间保持周期性心跳,如果Voidbox Master通过心跳发现Voidbox Proxy异常退出,会代理回收Docker Container资源。

● DockerContainer容错

每个应用程序可以配置Container允许重试的最大次数,当Container异常退出时,Voidbox Master会收到Container退出返回的exit code,根据返回码进行相应的逻辑处理或者重试。

4. 编程模型

Voidbox提供了基于Docker Container的DAG编程模型,举例如下:


图5 Docker container-based的DAG编程模型

如图5所示,应用程序代码中有四个job,每个job可单独指定各自的CPU和内存资源需求、运行的Docker 镜像和任务运行的并行度等参数。其中job1和job2并行运行,全部运行结束后job3运行。 job1,job2和job3组成一个stage,这个stage运行结束后,可以插入运行其他代码,最后运行job4。

同时,Voidbox支持命令行模式直接描述与提交任务,这种模式不需要编程,属于DAG编程模式的子集。

5. 应用实战

目前在YARN集群中可以同时运行Docker,MapReduce,Spark等应用程序,在Hulu内部已经有很多短任务利用Voidbox调度执行。

● 构建自动化测试流程

○ Voidbox配合Jenkins和GitLab等工具,当代码更新到GitLab特定分支之后,Jenkins完成自动测试,把程序编译打包,重新生成Docker镜像,推送到Docker Registry中,从而完成一整套开发测试自动发布的流程。

● 复杂任务并行化

○ TestFramework用来定期回归测试一些组件的可用性,这个项目开发语有Ruby,Java等,依赖环境复杂。所以我们维护两层Docker镜像结构,第一层是系统软件以及依赖层面的Docker image作为base image,第二层基于base image打包业务层面的代码,发布为一个Docker image,利用定时调度软件启动命令,在Voidbox集群中运行。解决 Test Framework依赖繁多,更新复杂,多任务之间并行度控制等问题。

○ Facematch (http://tech.hulu.com/blog/2014/05/03/face-match-system-overview/)是一个视频分析应用,它使用C语言实现,且依赖的图形库很多,其使用Voidbox可优化如下:首先将facematch处理程序打包成一个Docker镜像,然后使用Voidbox并行控制,同时处理多个视频,解决了机器环境准备复杂,并行度控制等问题。

● 构建复杂工作流

○ 多个任务之间有依赖,比如完成用户行为的载入更新之后,再对用户行为进行分析,这两个步骤有先后依赖关系,可用Voidbox DAG编程模型组成一个DAG工作流,轻易完成计算任务。

6. 周边产品比较

6.1 YARN 2.6.0自带DockerContainerExecutor模块的不同

● DockerContainerExecutor(https://issues.apache.org/jira/browse/YARN-1964)在YARN 2.6.0中发布,还是alpha版,不够成熟,仅仅是在default executor之上加了一层Docker封装。

● YARN2.6.0中的方案本质上是一个ContainerExecutor,目前YARN提供了DefaultContainerExecutor,DockerContainerExecutor等实现方案,但是目前YARN集群无法根据应用程序指定使用哪个ContainerExecutor,难以优雅地在YARN上混合部署Docker应用和其他类别的应用。

● DockerContainerExecutor把原先调度到YARN Container的任务放到Docker Container中运行,随之可以利用Docker Engine对于Docker Container的CPU、内存的隔离特性来满足YARN任务的资源隔离需求。Voidbox不但可以在YARN上运行任意的docker image,还提供如下新特性:

○DAG编程模型

○可配置的Container级别的容错性

○多种运行模式,兼顾开发环境与生产环境

○与其他Hadoop作业共享集群资源

○图形化日志查看工具

6.2 Mesos解决方案

● Marathon(https://mesosphere.github.io/marathon/)是一个运行在Mesos上的框架,它的设计宗旨是在同一组服务器之上,更智能地运行多种应用程序和服务Hadoop、Storm,甚至一个标准的Web应用,当然也包含了Docker容器类的应用。

● Chronos(https://mesos.github.io/chronos/)是一个基于Mesos实现的运行容器定时任务的工具。

● Apache Aurora(http://aurora.apache.org/)是基于Mesos实现的调度框架,可以同时运行短作业和长服务,具有任务优先级和资源抢占能力,致力于提高集群利用率。

● 相对于Mesos来说,YARN的生态系统更加庞大以及成熟,社区更加活跃,用户群更加庞大。在YARN上面开发Voidbox,可以与现有的MapReduce/Spark等任务混合部署在同一个集群,进一步提高集群利用率,降低维护成本。

6.3 Kubernetes平台

● Kubernetes(http://kubernetes.io/)的核心是Pod,Pod是Container的集合,Kubernetes是一个Pod编排工具,在此基础上提供副本管理和访问代理等能力。所以Kubernetes更像一个加强版本的Swarm(Docker编排工具)。

● 将来,当Kubernetes作为一个框架部署在Mesos上,或者作为一个Application部署在YARN上的时候,虽然可以混合部署提高资源利用率,但也只是提供某种模式下的容器的编排运行方式。

6.4 总结

● 相对于之上特定的DSL部署描述语法,Voidbox提供了更加灵活的编程模型。开发者在Voidbox提供的API之上,可以很方便地实现基于DAG的编程模型,或者是基于生产者消费者的编程模型,也可以整合Oozie,Jenkins,Gitlab等打造一套工作流管理。

● Voidbox以灵活的编程模型为基础,理论上可以实现几乎所有的基于容器的部署需求。并且可以与现有程序混合部署,提高集群利用率。

7. 展望,下一步工作

● 支持更多的Hadoop版本

Voidbox将支持除了Hadoop 2.6.0+之外的更多版本。

● VoidboxMaster的容错恢复,把元数据持久化下来,减少重试的开销

如果Voidbox Master意外退出了,YARN会回收属于这个作业的所有资源,然后重启Voidbox Master。将来可以在State Server上存储更多应用程序运行的元数据,降低重启Voidbox Master的开销。

● 支持长服务运行

在YARN上运行长服务需要解决的关键问题是,Application Master异常退出时不影响正在运行的服务实例,以及当新的Application Master重启后可以接管之前运行服务实例。