Netflix近日公开了部署在AWS之上的Hadoop平台架构,而且运行Hadoop工作负载的架构还是属于“独家制造”。来自Netflix的数据科学家Sriram Krishnan和Eva Tse在官方的博客中介绍了该平台在运行、管理以及访问多集群时的灵活性,还包括基于AWS的Hadoop架构以及Hadoop平台即服务(PaaS),该服务被称之为“Genie”。
毋庸置疑,Netflix在云计算领域有着很独特的发展——几乎把所有的一切都部署在AWS平台之上;除此之外,Netflix已经把触角深入到大数据工作负载的领域。Netflix是一个“重量级”的Hadoop用户,在2012年6月份Gigaom的记者Derrick Harris就撰文阐述了Netflix如何收集用户的数据,进而使用一些方法来对这些数据进行分析,而正是Hadoop在存储以及处理这些数据时为Netflix立下了“汗马功劳”。对该技术博客的编译如下:
云端:Hadoop平台即服务
Hadoop在管理和处理数百TB到PB级数据上的能力,已经成为事实上的标准。在Netflix中,基于Hadoop的数据仓库已经是PB级的规模,而且增长迅速。不过随着大数据时代的爆发,这也不是什么新鲜事。然而该架构是独一无二的,它可以帮助Netflix在云端构建一个几乎是无限规模的数据仓库。(无论是数据的处理还是计算能力都很强大)
在本文中Sriram和Eva讨论这个基于云的数据仓库,阐述了它和传统基于数据中心Hadoop架构的不同之处;还有他们是如何利用弹性云来构建这个具有动态扩展性的系统。与此同时,他们还介绍了Genie,这是自家的Hadoop平台服务(PaaS),而且为作业执行和资源管理提供了一个REST-ful API。
架构视图
传统的基于数据中心的Hadoop数据仓库,数据被托管在HDFS上,HDFS能够运行在标准硬件之上,提供高容错性和高吞吐量的大型数据集的访问。在云端搭建Hadoop数据仓库最经典的方式应该遵循这个模式,只不过是把数据存储在(基于云的Hadoop集群)HDFS之上。然而,就像在下一节描述的那样,他们选择把所有的数据存储在亚马逊的存储服务(S3),这也是架构得以实现的核心原则。架构的总体视图如下图所示,细节将逐一展开。
图:基于AWS的Hadoop架构图
使用S3作为云的数据仓库
S3是Netflix基于云的数据仓库服务真正的“源”。所有值得保留的数据集都存储在S3之中,包括很多数据流的信息,它们来自于(拥有Netflix功能)电视机、个人电脑以及各种移动设备的使用过程,这些信息被称为Ursula的日志数据管道所抓取;同时还有来自Cassandra的维度数据。
那么为什么Netflix使用S3而不是HDFS作为“源”呢?首先,S3提供了一个高达99.999999999%持久性和99.99%可用性(在特定的一年),能够承担两个设施中并发的数据丢失现象;其次,S3提供了版本信息存储块,可以用它来防止意外的数据丢失,例如,一个开发人员错误地删除了一些数据,可以很容易的进行恢复;第三,S3具有弹性,提供了几乎“无限”的规模扩展,这样数据仓库就实现了从几百TB到PB级的有序增长,而无需提前准备存储资源。最后一点,使用S3作为数据仓库可以帮助Netflix运行多个高动态的集群,这些适用于故障和负载,他们将在下面的章节中进行说明。
另一个方面,虽然S3的读/写速度比HDFS要慢。然而,大多数的查询和处理往往是多级的MapReduce作业。在第一阶段中,mapper从S3平行的读取输入数据,reducer在最后阶段把输出数据返回至S3,而HDFS和本地存储用于存储所有的中间级和临时数据,这就降低了性能的开销。
针对不同工作负载的多个Hadoop集群
Netflix目前使用亚马逊的Elastic MapReduce,而把S3作为数据仓库可以针对不同的工作负载弹性配置多个Hadoop集群,所有的集群都连接相同的数据。一个大的(超过500个节点)查询集群被工程师、数据科学家以及分析师用于执行ad hoc查询,Netflix的“产品”(或者说“SLA”)集群,几乎和查询集群有着相同的规模,运行SLA-driven ETL(抽取,转换,加载)作业。Netflix也拥有着几个其他的“dev”集群。如果Netflix使用HDFS做为“源”的话,接下来可能就需要一个进程,在所有的集群中进行数据的复制。而如果使用的是S3的话,这就不是一个问题,因为所有的集群可以对整个数据集进行即时的访问。
Netflix每天都会动态地调整查询和产品集群,其实查询集群在夜间可以更小,因为那时很少有开发者进行登录。相反,产品集群在夜间就必须很大,因为此时大多数的ETL都在运行。Netflix不需要担心数据的重分配或者在扩展/压缩的过程中数据的丢失现象,因为数据都分布在S3上。最后,虽然所有的产品和查询集群都是在云端长期的进行运行,但是Netflix可以把它们当做是一个短暂的过程。一旦某个集群宕掉了,就可以在几十分钟之内启用另一个等同规模的集群(如果需要的话,甚至可以在另一个可用区上),根本不需要担心数据的丢失问题。
工具及网关
开发者在Hadoop的生态系统中使用很多不同的工具,特别是他们使用Hive进行数据的查询和分析,与此同时,使用Pig进行ETL以及算法处理,Vanilla基于Java的MapReduce也偶尔被用于复杂的算法处理。Python在编写不同的ETL进程以及Pig用户自定义功能时是一个很常见的脚本语言。
Netflix的Hadoop集群的访问是通过一些“网关”,它们仅仅是开发者们通过Hadoop、Hive以及Pig的命令行接口(CLIs)来登录和运行的一些云端的实例。当有很多开发者登录和运行很多作业时,网关通常情况下会成为一个争用的单点。在这种情况下,我们鼓励“重量级”的用户启用云端的“个人”网关AMI(Amazon Machine Images)的实例。使用个人网关允许开发者在需要时安装其它的客户端的包(比如R语言)。
Genie —— Hadoop平台即服务
Amazon提供了Hadoop IaaS平台,通过Elastic MapReduce(EMR)提供服务。EMR提供了API和Hadoop集群,在这里你可以获取一个或多个Hadoop作业。Netflix已经实现了Hadoop PaaS服务(也就是Genie);提供了一个更高级别的抽象,不需要构建新的Hadoop集群或者安装Hadoop、Hive以及Pig客户端,就可以通过REST-ful API提交单独的Hadoop、Hive或者Pig作业。此外它还允许管理员去管理和抽象云中不同后端的Hadoop资源配置。
为什么要建立Genie?
Netflix的ETL进程一直是松耦合的,结合了Hadoop和非Hadoop工具,横跨云端以及Netflix数据中心。这是一个非常常见的大数据架构,通常还会使用一个小型关系数据仓库来扩大基于Hadoop的系统。前者提供了一个实时的交互查询和报告,更好的增加了传统BI工具之间的整合。当前Netflix使用Teradata作为他们的传统关系型数据仓库。然而,他们还在研究Amazon的新服务Redshift。
Netflix同样还在数据中心使用了一个企业级的调度程序(UC4)定义了云端和数据中心之间不同作业之间的依赖性,并把它们作为“process flows”运行。因此Netflix需要一个在客户端中剔除Hadoop、Hive和Pig作业的机制,让他们不需要安装完整的Hadoop软件栈。此外基于Netflix每小时需要运行上千个Hadoop作业 —— 尤其是应付在云端更多的ETL和处理迁移至Hadoop带来的负载增加,这个系统必须可以横向扩展。最后因为云中的集群可能会很短暂以及可以有多于一个的集群用来运行Hadoop作业,这里还需要从客户端抽离出后端的细节。
为什么要构建新的东西?
为什么要构建Genie,而不是用一些已存在的东西?最简单的答案就是现在的开源社区中没有一个适合Netflix的需求 —— 用于运行作业、后端集群的抽象、可以向不同集群提交作业、满足需求扩展度(横向或者纵向)的API。开始我们有两个选择Oozie和Templeton。而考虑过最接近的选择就是Oozie,类似UC4。但是它不同于Genie的作业提交式API,因此不能进行对等比较。之所以将Oozie从选择中排除掉,一方面因为它只支持Hadoop生态系统中的作业,而我们的工作将覆盖Hadoop和非Hadoop作业。而Oozie不支持Hive更是开始Genie的原因。再看另一个选择Templeton,现在作为HCatalog的一部分。然而,Templetion不支持提交到多个集群的并行作业,虽然仍在发展中,但是明显还不足需求。
什么是Genie
Genie是专为Hadoop生态系统定制的一组REST-ful服务集合,用于管理作业和资源。有两个关键服务:Execution Service和Configuration Serice。前者提供了REST-ful API,用于提交和管理Hadoop、Hive以及Pig作业;后者是个Hadoop资源的有效储存库,做元数据的连接以及运行资源上的作业。
Execution Service
Execution API,负责客户端与Genie的交互。客户端通过向Execution API发送JSON和XML信息提交作业,其中包括的参数有:
作业的类型,Hadoop、Hive或者是Pig
作业的命令行参数
文件的依赖性,比如S3上的scripts和jar文件
时间表类型(比如:“ad hoc”或者“SLA”),这样Genie就可以使用它来为作业映射适当的集群
Hive元存储需要连接的名称(比如:prod,test或者是一个设备名称)
当一个作业提交成功,Genie将返回一个作业id,这个可以用来获得作业状态以及输出URL。输出URL是个指向作业工作目录的HTTP URL,包含了标准输出以及错误日志(详见下面截图)。每个作业id都可以被转换成多个MapReduce作业,决定于Hive或者Pig中运行中间阶段的数量。
Configuration Service
Configuration Service被用于跟踪当前运行的集群以及支持的时间表。举个例子:查询集群被配置成支持“ad hoc”作业,然而我们的产品集群却被配置成支持“SLA”作业。当一个集群出现,我们告诉Configuration Service它支持的作业类型,以及集群的配置集合(也就是做Hadoop配置的mapred-site.xml、core-site.xml以及hdfs-site.xml和做Hive配置的hive-site.xml)。同时会将它的状态标注为“UP”。类似的,当一个集群关闭时,我们将会把它标注为“Terminated”。同样这里还有一个为集群准备的“Out of Service”状态,这将表示这个集群还存在,但是不支持任何新作业的提交。这在升级和结束进程时是非常有用的,当一个集群不再接收新任务的提交时,必须在终止它之前先让所有运行的作业结束。这个服务是对Eureka的补充,被设计为元数据的储存库,用于云中的短暂(并且不是集群)实例。
当Execution Service接收到一个作业请求时,它通过Configuration Service将作业映射到合适的集群。如果存在多个满足作业需求的集群,它会随机的选取一个集群候选。当然可以通过实现自定义负载平衡器来改进,以及分流单独的Hadoop、Hive、Pig作业,为每个作业分配独立的工作目录,从而实现Genie和作业本身的隔离。一个单独的Genie实例可以实现对不同集群提交作业的,完全的从客户端中抽象出来。
如何使用Genie进行动态的资源管理?
在Netflix不同的工程团队在AWS预留实例上使用ASG(auto-scaling groups)运行他们的服务,根据负载进行扩展和收缩。大部分的ETL作业都在午夜(PST)以后进行,因为在这段时间大部分的ASG都会收缩。因此我们使用这些过剩的保留实例补充到我们其他的生产集群中带来额外的效益。我们使用Configuration Service来登记它们,然后Genie客户端(比如ETL作业)使用Execution Service API连入这些新集群。当工程团队再次需要他们的实例时,这些被借用的实例将会终止并重新登记,同时不会再被Genie客户端接入直到再次剩余。
这里不再需要任何rolling升级,这在传统的Hadoop集群中经常出现的。如果我们需要对生产集群进行升级,一种选择就是使用拥有升级过软件堆栈的新产品集群,并且把旧集群的状态设置成“Out of Service”来终止对它的路由。此外我们还可以使用“Out of Service”设置正在工作中的集群对其升级,并临时的标记另一个正在工作中的集群作为SLA集群 —— 在集群升级时。如果我们不想正在运行的作业失败,必须等到作业结束再进行旧集群的终止或者升级。这很类似于Asgard提供的应用部署和云实例管理能力。
什么是Genie当前的部署状态?
虽然Genie仍在改进过程中,但是已经在我们的生产环境中高度使用。当前已经被部署到一个6-12节点的ASG,横跨3个Availability Zone进行负载平衡和容错处理。对于横向扩展,我们建议基于负载部署节点的数目。通过CloudWatch警报进行配置,附加Asgard管理自动扩展方案。Genie实例通过Eureka登记,客户端使用Eureka API对作业的有效实例进行选择。为了避免客户端过载,当一个实例的请求高于它的负载时Genie还会将作业请求转发到一个轻量级的负载实例。Genie现已支持上千个并行作业的同时提交。通天运行着上千个来自可视化工具和自定制Hive/Pig Web UI的Hive作业以及上万个Hive和基于Pig的ETL作业。扩展到上万个并行作业在理论上是可行的,只需要简单的通过增加ASG的实例数量。