Hadoop技术详解

978-7-115-33332-2
作者: 【美】Eric Sammer
译者: 刘敏麦耀锋李冀蕾等
编辑: 汪振
分类: Hadoop

图书目录:

详情

本书将向读者详细介绍Hadoop的各项操作,从最初的设计,到安装、设置,以帮助读者提供稳定持续的系统表现。而对于那些希望通过学习Hadoop工作原理以提高NapReduce工作效率的开发者来说,也将会从本书收益。

图书摘要

版权信息

书名:Hadoop技术详解

ISBN:978-7-115-33332-2

本书由人民邮电出版社发行数字版。版权所有,侵权必究。

您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。

我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。

如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。

• 著    [美] Eric Sammer

  译    刘 敏 麦耀锋 李冀蕾等

  责任编辑 汪 振

• 人民邮电出版社出版发行  北京市丰台区成寿寺路11号

  邮编 100164  电子邮件 315@ptpress.com.cn

  网址 http://www.ptpress.com.cn

• 读者服务热线:(010)81055410

  反盗版热线:(010)81055315


Hadoop正在成为数据中心进行大型数据处理的实际标准,但市场中却一直缺少关于它的详细操作说明书。本书作者Eric Sammer系Cloudera公司的首席架构师,全书将从计划、安装、配置Hadoop系统开始讲起,一直深入到系统调试、维护等方面的知识,向读者展示了Hadoop生产运行环境的详细情况。同时,本书并不只是简述所有的操作工序,而是突出示范了关键部署中的关键操作。

本书适合对大数据感兴趣的爱好者以及正在使用Hadoop系统的数据库管理员阅读使用。


Copyright © 2013 by O'Reilly Media. Inc.

Simplified Chinese Edition, jointly published by O'Reilly Media, Inc. and Posts & Telecom Press, 2013. Authorized translation of the English edition, 2013 O'Reilly Media, Inc., the owner of all rights to publish and sell the same.

All rights reserved including the rights of reproduction in whole or in part in any form.

本书中文简体字版由O'Reilly Media, Inc.授权人民邮电出版社出版。未经出版者书面许可,对本书的任何部分不得以任何方式复制或抄袭。

版权所有,侵权必究。


我要感谢我的妻子——Aida Escriva-Sammer,她也是我的挚友以及我最喜欢的系统管理员,在本书写作期间,她一直支持我。

同时,如果没有Apache Hadoop社区及生态系统项目的支持和努力,这也是不可能成功的。总之,我希望所有的读者都去参与社区活动和开源项目。

在这里,我要感谢:Matt Massie以及O'Reilly公司给我这个机会并且一直鼓励我直至本书完成;Matt和Tom White指导我通过投标的流程;Mike Olson、Omer Trajman、Amr Awadallah、Peter Cooper-Ellis、Angus Klein以及Cloudera 管理团队的其他成员让我有足够的时间、资源和勇气来完成这本书;Aparna Ramani、Rob Weltman、Jolly Chen和Helen Friedland在这个过程里给予的帮助并且不介意我对他们无休止的打扰。此外,特别感谢Christophe Bisciglia给予我在Cloudera工作的机会并不断给我建议。

在本书写作过程中,许多人给了我宝贵的反馈和意见,特别感谢Aida Escriva-Sammer、Tom White、Alejandro Abdelnur、Amina Abdulla、Patrick Angeles、Paul Battaglia、Will Chase、Yanpei Chen、Eli Collins、Joe Crobak、Doug Cutting、Joey Echeverria、Sameer Farooqui、Andrew Ferguson、Brad Hedlund、Linden Hillenbrand、Patrick Hunt、Matt Jacobs、Amandeep Khurana、Aaron Kimball、Hal Lee、Justin Lintz、Todd Lipcon、Cameron Martin、Chad Metcalf、Meg McRoberts、Aaron T. Myers、Kay Ousterhout、Greg Rahn、Henry Robinson、Mark Roddy、Jonathan Seidman Ed Sexton、Loren Siebert、Sunil Sitaula、Ben Spivey、Dan Spiewak、Omer Trajman、Kathleen Ting、Erik-Jan van Baaren、Vinithra Varadharajan、Patrick Wendell、Tom Wheeler、Ian Wrigley、Nezih Yigitbasi和Philip Zeyliger。对那些可能被遗漏了的人们,我深表歉意。

O'Reilly的工作人员从来都是令人惊叹的,特别是Courtney Nash、Mike Loukides、Maria Stallone、Arlette Labat和Meghan Blanchette。

此外,Jaime Caban、Victor Nee、Travis Melo、Andrew Bayer、Liz Pennell和Michael De-metria也给了我管理、技术和合约方面的支持。

最后,要特别感谢Kathy Sammer对我坚定不移的支持,并教会我坚持去做别人认为你做不了的事。


Eric Sammer目前是Cloudera公司的首席方案架构师,协助客户规划、配置、开发和使用Hadoop以及相关的大型项目。他在开发和运营分布式的、高并发的数据摄取和处理系统方面很有经验。在过去的十年里,他参加了开源社区并且为许多项目做出了贡献。


大数据从2012年开始越来越火热,人人都开始谈论大数据并试图从这项技术中获益。其实大数据不是今天才开始的,何为大?何为小?我想主要要从两个方面来看这个问题,第一是需求,第二是处理能力。从需求上来讲,人们对数据“大”的追求是无止境的,无论是结绳计数、算盘时代、还是今天的大数据时代,人们总是希望在庞大的数据中获得更多的知识。从处理能力来讲,超过了时代技术能处理的数据都叫大数据,人们不断地发明创造新的技术来满足探索世界的需要。结绳、阿拉伯数字、算盘、计算机、集群……一次次技术飞跃无不是人类在技术上不断地探索和实践的结果。

今天的数据处理革命,源自Google在2003年发表的三篇著名论文。论文的开源实现Hadoop在2006年发布,第一次将分布式存储和平行计算平民化,让更多公司和个人能够享受技术突破的愉悦,为世界创造更多、更好的数据产品。爱立信作为一家着眼于通信技术、倡导互联社会的企业也积极投身于这场革命中,希望利用大数据更好地为自身和行业提供优秀的数据解决方案。

随着大数据技术的推广和普及,爱立信广州研发中心也开始动手实践和应用大数据。研发中心技术委员会在2012年底成立了大数据和机器学习特别兴趣小组,探索大数据应用于网络维护、优化以及帮助运营商获得更好的商业智能。作为学习和工程实践,小组选择从Hadoop运维(Hadoop Operation)入门,希望站在巨人的肩膀上快速建立稳定的大数据平台。的确,由于作者在此领域有多年实践经验,本书对很多工程实践有很深刻的理解,能在细节上提出解决方案,避免后来者重复劳动,少走一些弯路。我们也在翻译此书的过程中获益良多!

翻译工作是枯燥的,有时需要为准确性反复推敲、不断讨论。我们很难说做到了雅,但我们尽量让文字能够准确表达作者本意,在技术实践中可以做正确指导。尽管翻译工作是在业余时间进行的,但小组同事表现出极大的热情和专注。众人拾柴火焰高,很快我们就拿出了初译稿,并进行了两轮校译,最后由刘敏、麦耀锋、李冀蕾对全书风格进行统一。尽管如此,本书的中文译稿仍有不少疏漏和错误,望各位读者能不吝指正!我们的联系方式为:bigdatafans@163.com

参与此书翻译的同事有:前言—李冀蕾;第一章—刘敏;第二章—李璇;第三章—麦耀锋;第四章—王晓辉;第五章—邓乾华、叶燕宝、李冀蕾;第六章—梁汉健;第七章—邓陈斌;第八章—刘敏;第九章—苏帆;第十章—李冀蕾;第十一章—曾庆楠;附录—李冀蕾。

参与此书一审的同事有:第一章—麦耀锋;第二章—刘敏;第三章、第四章—麦耀锋;第五章—刘军;第六章—李冀蕾;第七章—李璇;第八章—梁汉健;第九章—刘敏;第十章—苏帆;第十一章—邓陈斌。

参与此书二审的同事有:第一章—李冀蕾;第二章—邓陈斌;第三章—麦耀锋;第四章—李璇;第五章—刘敏;第六章—苏帆;第七章—刘军;第八章—李冀蕾;第九章—邓乾华;第十章—梁汉健;第十一章—麦耀锋。

感谢所有同事为此付出的努力和汗水,也要感谢姜信宝、贾锦杰两位同事对本书翻译工作的支持和帮助!正是有了你们的帮助,本书中文版才能得以顺利面世。

大数据和机器学习特别兴趣小组

2013年于爱立信广州研发中心


本书采用以下排版约定。

斜体

用于表明新的术语、URL、电子邮件地址、文件名和文件扩展名。

等宽字体

用于程序清单,正文段落中有关的程序元素,如变量及函数名、数据库、数据类型、环境变量、语句和关键字等。

等宽加粗字体

用于显示命令或应由用户输入的其他文本。

等宽斜体字体

表明这里的文本需要被替换成用户提供的值或由其他上下文确定的值。

提示

这个图标表示提示、建议或者通用的说明。


警告

这个图标表示警告或者注意事项。

这本书的目的是帮助读者完成工作。通常情况下,可以在程序或文档中使用本书中给出的代码,而不必联系我们获得代码使用授权,除非你需要使用大量的代码。例如,在写程序的时候引用几段代码不需要向我们申请许可,但以光盘方式销售或重新发行O'Reilly书中的示例便需要获得许可。引用本书或引用本书中的示例代码来回答问题也不需要申请许可,但是,如果要将本书中大量范例代码加入你的产品文档,则需要申请许可。

我们欣赏引用注明出处的做法,但不强求。引用通常包括书名、作者、出版社和ISBN,例如,Hadoop Operations by Eric Sammer (O'Reilly). Copyright 2012 Eric Sammer, 978-1-449-32705-7。

如果觉得使用示例代码的情况不属于前面列出的合理使用或许可范围,请通过电子邮件联系我们,邮箱地址为permissions@oreilly.com 。

Safari Books Online (www.safaribooksonline.com ) 是一个定制的数字图书馆,以图书和视频的方式提供了来自技术和商业方面的世界权威作家的专业书籍。

技术专家、软件开发人员、网页设计师以及商业和创意专业人士以Safari Books Online作为其进行研究、解决问题、学习和认证培训的主要资源。

Safari Books Online为团体、政府机关以及个人提供了一系列的产品组合和定价计划。用户在此可以访问成千上万的书籍、培训视频和正式出版的手稿。这是一个可完全检索的数据库,内容来自各出版商,如O'Reilly Media、Prentice Hall Professional、Addison-Wesley Professional、Microsoft Press、Sams、Que、Peachpit Press、Focal Press、Cisco Press、John Wiley & Sons、Syngress、Morgan Kaufmann、IBM Redbooks、Packt、Adobe Press、FT Press、Apress、Manning、New Riders、McGraw-Hill、Jones & Bartlett、Course Tech-nology等。如需获得更多关于Safari Books Online的信息,请访问我们的网站。

对于本书如果有任何意见或疑问,请按照以下地址联系本书出版商:

O'Reilly Media, Inc.
   1005 Gravenstein Highway North
   Sebastopol, CA 95472
   800-998-9938 (美国或加拿大)
   707-829-0515 (国际或本地)
   707-829-0104 (传真)

本书也有相关的网页,我们在上面列出了勘误表、范例以及其他一些信息。网址如下:http://oreil.ly/hadoop_operations

对本书做出评论或者询问技术问题,请发送电子邮件至:bookquestions@oreilly.com

想获得更多关于我们的书籍、系列读物、学术会议以及新闻,请访问我们的网站http://www.oreilly.com

想在Facebook上联系我们,请访问:http://facebook.com/oreilly

想在Twitter上关注我们,请访问:http://twitter.com/oreillymedia

想在YouTube上观看我们的视频,请访问:http://www.youtube.com/oreillymedia


在过去的几年里,数据的存储、管理和处理发生了巨大的变化。各个公司存储的数据比以前更多,数据来源更加多样,数据格式也更加丰富。这不是因为我们变成了林鼠(译注:林鼠喜欢收集各种物品),而是因为我们想要创造出可以让我们进一步了解某一领域的产品、功能以及对其智能预测(这个领域可以是指用户、数据搜索、机器日志或者是某机构的任何信息)。为了更好地服务其成员,各组织正在寻找新的方式来使用那些曾经被认为没有什么价值或者存储起来过于昂贵的数据。采集和存储数据只是其中的一部分工作,但现在处理这些数据并从中挖掘有用信息已经成为每一个现代商业组织日常运营中的重要工作。

数据的存储、处理存在困难,并不是个新问题。在近几十年里,商业金融机构防欺诈、运营机构发现异常、广告组织做人口统计分析……很多类似的情况下,我们都不得不存储处理大量的数据。但是近来,数据的容量、处理的速度、数据的种类正在变化,某些情况更是加剧了变化。这很有意义,因为不少算法的发展得益于此。比如,电商的产品推荐,可以向到访者展示他想购买的产品列表,希望其中总有一款可以满足他的需求。这明显不是一个明智的策略,不过这是一个好的开始。我们怎样才能向他们只展示正确的产品?基于他们以前的浏览记录也许更有意义。如果知道他们已经购买的产品会更有帮助,例如知道买家已经购买过某个品牌的电脑,也许他会对相应的配件以及升级换代的新产品更加感兴趣。[1]一个常用的技术是通过相似行为(例如购买模式)来对用户进行分类,对同类人群推荐其他的人购买的产品,无论是什么样的解决方案,背后的推荐算法都必须处理大量数据,对问题空间越了解就越容易得出更好的结论(算法有更好的功效),同时,客户更满意,商家挣更多的钱,减少欺诈,网络环境更加健康安全。

Apache Hadoop能为刚才提到的各种应用提供一个可编程的、经济的、可伸缩的平台。这个分布式系统由分布式文件存储系统(HDFS)以及计算框架(Map/reduce)组成。HADOOP是一个开源项目,能为大量数据集提供批量数据处理能力。Hadoop被设计成不光要容忍软硬件的不可靠,还要对此习以为常。Hadoop使用没有特殊硬件或特殊网络基础设施的普通的服务器群来形成一个逻辑上可存储计算的集群,这个集群可以被很多团体和个人共享。Hadoop Map/Reduce提供并行自动计算框架,这个框架隐藏了复杂的同步及网络通信,呈现给程序员的是简单的、抽象的接口。跟其他分布式数据处理系统不一样, Hadoop在数据存储的机器上运算用户提供的数据处理逻辑,而不是通过网络来搬动这些数据,这对性能来说是一个巨大的利好。

下面介绍一下Hadoop的历史。Hadoop 基于谷歌的两篇论文,当时许多公司都遇到了密集型数据的处理问题,Google也是其中之一。一篇发表于2003年的论文描述了一个用来存储海量数据、可编程、可伸缩的分布式文件系统,该文件系统被称为Google文件系统,或简称GFS。除了支持数据存储,GFS还支持大规模的密集型数据的分布式处理应用。接下来的一年,另外一篇名为“MapReduce:大集群中一种简单的数据处理框架”的论文被发表了,该论文定义了一种编程模型及其相关的框架,它能够成规模地以一个单独的任务通过上千台的机器处理上百TB的数据,并能提供自动并行计算和容错性。GFS和MapReduce相互协同,可在相对便宜的商用机器上构建大数据处理集群。这两篇论文极大地促进了Hadoop分布式文件系统及MapReduce的开发。

业界对Hadoop的兴趣和投资促成了开源和商业软件生态系统的形成,仅Apache软件基金会,使用Hadoop或者与之集成的项目就不断涌现。其中一些项目使得编写MapReduce任务更加简单以及更容易理解,而其他的项目则专注于如何通过HDFS存取数据、简化操作、使之能在云环境下部署等。以下是一些应当了解的流行项目。

Apache Hive

Hive是一种类关系型数据库的抽象,给程序员提供类SQL的接口,并把类SQL语句转换成一个或多个可在集群上执行的MapReduce任务。SQL则是不少开发人员、分析师、第三方软件大量运用的语言(Hive的SQL又称HiveQL,是实现了通用SQL标准的一个子集)。Hive利用了SQL的优势,为使用Hadoop及编写MapReduce任务提供了一条学习捷径。正是因为这个原因,Hive是至今Hadoop生态系统中最流行的项目之一。Hive将HDFS文件定义成类似表的结构,当运行一个查询的时候则从那些文件里面抽取记录,但数据实际上并没有改变,只是被解析而已。HiveQL语句在运行时被解释成为预编译的MapReduce组件的集合,执行这个集合相当于运行SQL语句。

类似于Hive,Apache Pig 用于简化MapReduce代码的编写,因此无需人人都会写Java。用户用高级脚本语言设计数据处理任务,Pig用于建立一个执行计划并执行一系列的MapReduce任务来完成那些繁重的工作。万一Pig不满足特定功能,开发人员亦可以用Java来编写自定义函数以扩展原生函数及操作。Hive也支持类似扩展,如果熟悉Perl、Python、Ruby、javascript,甚至是Shell脚本,那么早上学习Pig的语法,中午就可运行MapReduce运算任务了。

Apache Sqoop

Hadoop并不想取代数据库,相反它想成为数据库的朋友。能否与关系型数据库交换数据成为与Apache Hadoop集成的关键点。Sqoop是“SQL至Hadoop”的简写,提供Hadoop和几乎所有有JDBC驱动的数据库之间的双向数据传输。利用MapReduce,Sqoop不用写一行代码就能并行完成这些操作。

为取得更好的性能,Sqoop支持数据库特定的插件,这些插件可以利用关系数据库管理系统(RDBMS)的原生功能,无需因使用JDBC而带来开销。很多连接器是开源的,当然也有免费或付费版。现在,Sqoop支持MySQL和PostgreSQL之间的原生连接器;也有免费连接器支持Teradata、Netezza、 SQL server、Oracle,可以从软件提供商的网站下载得到。

Apache Flume

Apache Flume是一种流数据的收集和汇聚系统,用来传输海量数据到像Hadoop这样的系统中去。它支持原生连接并支持向HDFS直接进行写操作,能简化来自于RPC服务、log4j附加器、syslog甚至操作系统命令输出的流数据的传输。数据可以按特定路线发送、负载均衡、备份到多个目的地,并通过一层代理将来自数千节点的数据进行汇聚。

Apache Oozie

在大型运算集群中,一个工作流中有大量MapReduce任务需要相互协作是非常常见的。Apache Oozie是一种工作流引擎和调度器,可以在Hadoop集群上管理协调大规模计算任务。工作流可以被时间或者事件触发,比如数据到达某个目录,也可以制定一些策略,比如错误处理逻辑。Oozie是一种REST服务,即可编程控制工作流和状态显示。

Apache Whirr

Apache Whirr是为了简化在类似亚马逊的AWS云环境上搭建和部署临时集群的复杂度而开发的。Whirr在本地或云中以命令行方式运行——创建实例、部署Hadoop、配置软件,也能灵活地销毁实例。Whirr在内部实现上使用了强大的jclouds库,因此它是云平台中立的。开发人员使Whirr同时支持亚马逊EC2和Rackspace云。除了Hadoop,Whirr也能配置Apache Cassandra、Apache ZooKeeper、Apache Hbase、ElasticSearch、Voldemort和Apache Hama。

Apache HBase

Apache HBase 是建立在HDFS上的低延时、分布式的非关系型数据库。HBase模仿Google的BigTable,提出了一个灵活的数据模型,拥有额外的属性和简单的API。HBase数据以一种横向为区域(region)、纵向为列族的表的形式存储。HBase中的表有数百TB甚至PB是很普遍的。过去的几年里,HBase从Facebook类知名消息平台网站那里获益良多。而今,HBase已成为主流产品中处理实时海量数据的利器。

Apache ZooKeeper

Apache ZooKeeper是一匹吃苦耐劳的驮马,它是一个可靠的分布式协同工作系统,支持分布式应用群。这些应用群需要一系列服务,如领导选举、加锁、群组会员、位置服务、配置维护。使用ZooKeeper可以不用重新实现随之而来的复杂的协同工作和错误处理功能。事实上,这正是不少Hadoop生态系统中的项目选择ZooKeeper的原因(最有名的案例就是HBase)。

Apache HCatalog

生态系统的新兵——Apache HCatalog向生态系统内的各类应用提供共享模式和数据存取的机制(译注:这是基于Apache Hadoop之上的数据表和存储管理服务)。HCatalog的长期目标是让一些工具能互操作,如Apache Hive和 Pig可以共享元数据。

Hadoop的生态系统在商业世界里日益繁荣,不少公司(如Oracle、SAS、MicroStrategy、 Tableau、Informatica、Microsoft、Pentaho、Talend、HP、DELL)在他们的产品中对Hadoop进行了支持或集成。Hadoop很快会成为数据中心处理海量数据的事实标准,或者说越来越多的人相信Hadoop已经是标准了。

如果你在阅读本书,那么你可以能是开发者,想了解在产品开发环境下的系统管理;也可能是应用或系统管理员,计划部署或运营集群,想寻找其他系统解决方案。本书不会过多地谈论如何编写应用、API调用或烦人的代码开发问题。如果你有这方面的需求,另一本好书《Hadoop Definitive Guide》(《Hadoop权威指南》,作者为Tom White,由O’Reilly出版)可能更加适合你。不过,管理员确实是计划、安装、配置、维护、监控Hadoop集群的重要角色。Hadoop是相对低级的系统,它的许多功能严重依赖于宿主机的操作系统,开发人员和管理员协同工作才能将其功效最大化。对Hadoop的操作会直接影响最终结果。

了解和接触Apache Hadoop是一件特别令人兴奋的事情,诚然,大数据正时髦,但更重要的是,Hadoop本身处在迅猛发展变化的上升期。这一两年来每个新版本总会给开发和管理人员带来许多新功能。所以说Hadoop正处在青春期,快速地成长和推广会让我们受益,但偶尔也会带来尴尬。通过本书你会发现,次要版本之间也存在显著的变化。无可否认,你得跟上变化的节奏而不要让其成为障碍。如果需要,第4章值得你花些时间阅读,这里会介绍常用的一些版本。

本书希望成为产品开发环境下应用Hadoop的实用指南。已经熟悉Hadoop的人可能已经知道安装方法或者对基于CPU利用率来优化调整Map数量持不同的意见,这很好,也是我们所期待的。本书的目标不是列举所有可能的应用场景,而是把注意力集中在部署过程中的关键步骤。

第2、3章提供了一些必要的背景知识,比如HDFS和Mapreduce是什么,为什么会存在,原理上他们如何工作。第4章会从硬件选型、基本资源计划、操作系统选择和配置、Hadoop版本选择、Hadoop集群的网络配置等方面给予Hadoop部署详细说明。第5章是最重要的部分,讲述Hadoop安装配置,安排了一些专题来列举关键属性。如果你对安全要求比较高或想了解Hadoop的身份确认、接入、授权等问题则需要仔细阅读本章。第6、7章介绍了多用户群组共享一个大的集群的基本要点,以及如何遵从服务协议管理和分配资源并从中受益。第8章阐述运维中一些常见的操作及任务。第9章是以备不时之需的,覆盖复杂分布式系统(如Hadoop)故障排查的理论和实践,包括一些实战例子。第10章讲解怎样有效监控Hadoop 集群。第11章提供了一些基本的工具和技术进行备份Hadoop和处理灾难性故障。

[1] 我曾经在一家化妆品公司上班,工作在一个数据驱动的市场营销项目上。利用所有顾客在一段较长时间内的购买交易记录,该公司便可以预测:曾经购买过某产品的顾客什么时候将会用完该产品。结果,我们只需在顾客用完产品的大概一周前向其推销同样的产品,就能在销售上带来(非常)引人注目的提升。


Apache Hadoop的重要组成部分是Hadoop分布式文件系统(HDFS,Hadoop Distributed Filesystem)。HDFS的设计初衷是为了支持高吞吐和超大文件的流式读写操作。传统的大型存储区域网络(Storage Area Network, SAN)和网络附加存储(Network Attached Storage, NAS)给TB级的块设备或文件系统提供了一种集中式的低延时数据访问解决方案。因为SAN和NAS支持全功能POSIX语法,具有很好的存储伸缩性和低延时访问等优点,所以可以完美地满足关系数据库、内容交付系统及类似数据的块存储要求。然而,试想一下这样的场景:成千上万台机器同时启动,并从集中式存储系统中同时读取成百TB的数据。传统存储技术不可能达到这样的规模!

为了解决这个问题,我们可以用一些独立的机器搭建一个高性价比系统。这个系统中的每台机器都拥有自己的I/O子系统、磁盘、RAM、网络接口、CPU,且支持部分POSIX功能(或按需求裁剪)。以下就是HDFS的一些特定目标。

尽管HDFS可以不依赖MapReduce而独立应用于大型数据集的存储,但如果将它们结合在一起,系统就会如虎添翼。例如,利用HDFS将输入数据分割成数据块分别存储在不同机器上的特点,MapReduce可以将计算任务分配给数据块所在的机器,从而实现数据读取的本地化,提高系统的效率。

HDFS在很多方面都遵循了传统文件系统的设计思想。譬如文件以不透明的数据块形式存储,通过元数据管理文件名和数据块的映射关系、目录树结构、访问权限等信息。这些和普通的Linux文件系统(如ext3)是非常相似的。那么,HDFS又有什么与众不同的地方呢?

传统文件系统是内核模块(至少在Linux中是这样的)和用户空间工具,然后通过挂载的形式提供给终端用户使用。但是HDFS却是一种用户空间文件系统。具体来说,文件系统代码以OS进程和扩展的形式运行在内核之外,而无须注册在Linux VFS层,所以,HDFS是一种更加简单、更加灵活和更加安全的实现方式。HDFS不像ext3文件系统那样需要挂载,只要应用程序显式地编译它即可。

HDFS除了是用户空间文件系统外,它还是一种分布式文件系统。分布式文件系统突破了单机或单个磁盘物理存储空间的限制,其主要思想是集群中的各个主机只存储文件系统的一个数据子集,当需要存储更多数据块时,只需要添加更多挂载了多个物理磁盘的主机便可以实现。文件系统的元数据存储在中央服务器中,提供数据块的目录结构,并维护着整个文件系统的全局状态。

HDFS与其他文件系统的另一个主要区别是基本数据块的大小。传统文件系统的数据块大小一般是4KB或8KB,而Hadoop的数据块就大得多,默认为64MB,系统管理员可以根据需要选择配置成128MB、256MB、甚至1GB。增大数据块大小意味着数据可以被写入到磁盘中更大的连续块中,这也意味着数据的读写操作可以采用更大、更连续的方式进行,这样就可以减少磁盘的查找操作,而查找是机械式硬盘运行中最慢的一种操作,因此也就提升了处理大型数据流I/O操作的效率。

传统文件系统依赖特殊的存储子系统实现对数据的保护。HDFS则不同,它可以将数据的多个副本分别存储到集群的多台不同主机上,从而实现对数据的保护。默认情况下,每一个数据块会被复制三份,因为HDFS的文件具有“只写次”的特点,每个副本一旦写入完成,就不可能再被更改,所以根本无须考虑各数据副本的一致性问题。应用程序读取数据块的任何一个可用的副本都可以实现对文件的访问。因为数据块拥有多个副本,所以因主机故障而导致的数据丢失也可以很容易恢复,同时网络中的应用程序也更有可能从离其最近的主机中读取数据。HDFS会主动跟踪并管理可用数据块副本的数量。当副本的数目低于配置的复制因子时,文件系统会自动从剩下的副本中创建一个新的副本。在本书中,我们会频繁地使用副本(replica)来表示HDFS数据块的复制。

当然,应用程序并不希望太过关注数据块、元数据、磁盘、扇区以及其他底层系统的具体实现细节。相反,开发人员更希望通过诸如文件和流等高层抽象接口来实现I/O操作。HDFS提供给开发人员的文件系统是一套高级的、类似POSIX那样的程序员比较熟识的API。

一个标准HDFS集群由3个守护进程组成,如表2-1所示。

表2-1 HDFS守护进程

守护进程

集群中的数目

用  途

NameNode

1

存储文件系统的元数据,存储文件与数据块映射,并提供文件系统的全景图

次NameNode

1

处理NameNode内事务日志检查点

DataNode

多个

存储块数据(文件内容)

数据块可以理解为二进制数据文件的主要组成单元。在HDFS中,负责数据存储和获取的守护进程就是DataNode,简称(DN)。数据节点可以直接访问本地挂载的一个或多个磁盘,通常又称数据磁盘。这些挂载在服务器上的磁盘可以用来存储块数据。在产品系统中,这些磁盘通常为Hadoop独有。通过在集群中增加数据节点或者给现有数据节点添加磁盘,就可以轻松实现系统存储空间的扩容。

HDFS的另一个最显著优点是它存储数据块时并不需要RAID的支持,这就可以达成只需要使用低成本商用硬件的设计目标,减少集群扩容的成本。数据块的安全可以通过在多台机器同时保留多份数据块副本得以保证,而不需要依赖磁盘阵列(RAID)。增加数据块副本的方案可能因安全考量增加了原始数据的存储成本,但也因此提升了处理效率。将数据块的多个副本保存在多台机器上,既避免了数据块因机器故障而丢失,同时又可以在处理数据时使用该数据的任何一个副本。因为有多份数据可供选择,调度器在调度任务时,可以更灵活地将计算任务安排在拥有数据备份的机器上。详细情况,请阅读第3章。

放弃使用RAID是有争议的,很多人认为RAID就像一个神奇的加速按钮,可以让磁盘运行更快。然而,事实并非如此。在Hadoop特定的应用场景中,数量巨大的独立磁盘,搭配独立I/O队列,能承受巨量的顺序I/O操作,其性能往往会比RAID高出许多。通常,DataNodes拥有大量的独立磁盘,每块磁盘都保存着完整的数据块。相关话题的深入讨论请参见4.2.4节“刀片服务器,存储区域网络(SANs)和虚拟化”。

DataNode守护进程负责存储数据块,而NameNode(或简写成NN)守护进程则负责保存文件系统的元数据,并维护文件系统全景图。尽管用户是连接在NameNode上进行文件系统操作的,但正如我们稍后将要看到的那样,数据块是直接流入和流出DataNode的,因此单个节点不会成为整个系统的瓶颈。DataNode通过周期性心跳向NameNode报告各自的状态。因而,在任何时刻,NameNode都掌握着整个集群中每个DataNode的状态:它们是否工作正常,哪些数据块是可用的等。图2-1给出了一个HDFS架构的实例。

图2-1 HDFS架构

在DataNode初始化的过程中,以及之后每隔1小时,都会向NameNode发送一个块报告(block report)。所谓“块报告”,就是一个包含DataNode磁盘中所有数据块信息的列表,这样NameNode就可以跟踪数据块的任何变化。块报告是非常重要的,因为在NameNode磁盘中保存了文件与数据块的映射关系,却并不保存数据块的位置信息。这乍看起来似乎有悖常理,但这种设计的优点就是即便DataNode的IP地址或主机名发生了改变,也不会影响文件系统中元数据的存储。这样做还有一个附带的好处,当一个DataNode的主板发生故障时,管理员只需拆下硬盘,将它们插入新的机箱,然后启动新机器,这依然不会影响元数据的存储,在NameNode中看到的就是数据块迁移到了一个新的DataNode上。当然这样做也有副作用,当全新初始化启动一个集群(在这种情况下,重启集群也是一样的),NameNode必须收集齐所有DataNode的块报告后才能知道所有数据块的存在。

为了快速查找和获取文件信息,NameNode文件系统的元数据全部保存在RAM中。当然这样做就会限制NameNode能处理的元数据的大小。粗略地估计,1GB的内存可以管理大约100万个数据块(更多内容请参见4.2节“硬件选型”)。稍后我们将讨论如何突破这种限制。当然这种突破也不常发生,只有在超大规模的集群中(上万个DataNodes),才有可能需要这种突破。

HDFS第三个守护进程就是次NameNode,它主要负责NameNode内部的维护清理工作。可千万不要受这个名字迷惑,次 NameNode可不是NameNode的备份进程,它的功能与NameNode 也完全不同。


次NameNode可能是计算机历史上对进程的最糟糕的命名之一。很多Hadoop的初学者可能会受到这个名字的欺骗,误以为在NameNode出现故障而不能正常工作时,次NameNode会自动成为新的NameNode,这样集群就可以继续运作。其实不然,稍后将介绍次 NameNode的功能。这里只是提请读者注意,在关注次NameNode是什么的同时,也要记住它们不是什么。

客户端可以通过多种不同的工具和应用程序接口(参见2.8节“访问与集成”)对HDFS进行读写操作,这些操作都遵循着同样的流程。在某些层面,客户端可能要使用到Hadoop库函数,因为只有Hadoop库函数才清楚知道HDFS的具体细节和相关语法。函数库封装了大部分与NameNode 和DataNode通信相关的细节,同时也考虑了分布式文件系统在诸多场景中的错误处理机制。

首先,我们来看一下HDFS数据读取操作的处理逻辑。假设,HDFS中已经存储了一个文件/user/esammer/foo.txt,要读取文件,Hadoop客户端程序库(通常是Java的JAR文件)是必不可少的。同时,客户端还必须有集群配置数据的副本,因为它包含了NameNode的位置信息(参见第5章)。如图2-2所示,客户端首先要访问NameNode,并告诉它所要读取的文件,当然,这之前必须对客户的身份进行确认。客户身份确认有两种方式:一种是通过信任的客户端,由其指定用户名;第二种方式是通过诸如Kerberos(参见第6章)等强认证机制来完成。接下来还必须检查文件的所有者及其设定的访问权限。如果文件确实存在,而且用户对这个文件有访问权限,这时NameNode就会告诉客户端这个文件的第一个数据块的标号以及保存有该数据块的DataNode列表。这个列表是根据DataNode与客户端间的距离进行了排序的。客户端与DataNode之间的距离是根据Hadoop集群的机架拓扑结构计算得到的。机架拓扑结构记录了主机机架位置的配置信息(有关机架拓扑配置的更多详情,请参见第5.9节“机架拓扑”)。


在NameNode因为自身原因或网络故障无法访问时,客户端会收到超时或异常出错消息,数据读取操作也就无法继续。

有了数据块标号和DataNode的主机名,客户端便可以直接访问最合适的DataNode,读取所需要的数据块。这个过程会一直重复直到该文件的所有数据块读取完成或客户端主动关闭了文件流。

图2-2 HDFS数据读取流程

从DataNode读取数据时,可能会发生进程或主机异常结束的情况。这时,数据读操作不会停止,HDFS 程序库会自动尝试从其他有数据副本的DataNode中读取数据。如果所有数据副本都无法访问,则读取操作失败,客户端收到异常出错消息。还有一种情况,当客户端试图从DataNode中读取数据时,NameNode返回的数据块位置信息已经过期。这时如果还有其他DataNode保存有该数据块副本,客户端会尝试从那些DataNode中读取数据,否则至此读取操作就会失败。这些情况很少发生,但对Hadoop这样的大规模分布式系统而言,一旦发生,调查分析过程就会异常复杂。第9章将介绍什么情况可能导致出错以及如何诊断这类问题。

HDFS写数据操作比读取数据操作要相对复杂些。我们先来看个最简单的例子:客户端要在集群中创建一个新文件,当然客户端并不一定要真正实现这里介绍的逻辑,在这里只是作为一个例子来介绍Hadoop库函数是如何将数据写入到集群中的。其实应用程序开发人员可以像操作传统的本地文件一样,用他们熟悉的应用程序接口(API)打开文件、写入流,然后关闭流即可。

首先,客户端通过Hadoop文件系统相关API发送请求打开一个要写入的文件,如果该用户有足够的访问权限,这一请求就会被送到NameNode,并在NameNode上建立该文件的元数据。刚建立的新文件元数据并未将该文件和任何数据块关联,这时客户端会收到“打开文件成功”的响应,然后就可以开始写入数据了。当然在API层面会返回一个标准的Java流对象,这一实现只是针对HDFS的。当客户端将数据写入流时,数据会被自动拆分成数据包(这里,不要和TCP数据包或HDFS数据块混淆),并将数据包保存在内存队列中。客户端有一个独立的线程,它从队列中读取数据包,并同时向NameNode请求一组DataNode列表,以便写入下一个数据块的多个副本。接着,客户端直接连接到列表中的第一个DataNode,而该DataNode又连接到第二个DataNode,第二个又连接到第三个上……这样就建立了数据块的复制管道,如图2-3所示。数据包以流的方式写入第一个DataNode的磁盘,同时传入管道中的下一个DataNode并写入其磁盘,依此类推。复制管道中的每一个DataNode都会确认所收数据包已经成功写入磁盘。客户端应用程序维护着一个列表,记录哪些数据包尚未收到确认消息。每收到一个响应,客户端便知道数据已经成功地写入到管道中的一个DataNode。当数据块被写满时,客户端将重新向NameNode申请下一组DataNodes。最终,客户端将剩余数据包全部写入磁盘,关闭数据流并通知NameNode文件写操作已经完成。

图2-3 HDFS写路径

然而,凡事绝非如此简单,出现问题在所难免。最常见的情况是,复制管道中的某一DataNode无法将数据写入磁盘(磁盘翘了辫子或DataNode死机)。发生这种错误时,管道会立即关闭,已发送的但尚未收到确认的数据包会被退回到队列中,以确保管道中错误节点的下游节点可以获得数据包。而在剩下的健康数据节点中,正在写入的数据块会被分配新的ID。这样,当发生故障的数据节点恢复后,冗余的数据块就好像不属于任何文件而被自动丢弃,由剩余数据节点组成的新复制管道会重新开放,写入操作得以继续。此时,雨过天晴,写操作将继续直至文件关闭。NameNode如果发现文件的某个数据块正在复制,就会异步地创建一个新的复制块,这样,即便集群的多个数据节点发生错误,客户端仍然可以从数据块的副本中恢复数据,前提是满足要求的最少数目的数据副本已经被正确写入(默认的最少数据副本是1)。

NameNode将文件系统的元数据以不同的文件保存在本地磁盘中,其中最重要的两个文件是fsimageedits。和数据库一样,fsimage包含文件系统元数据的完整快照,而edits仅包含元数据的增量修改。对高吞吐率的数据存储而言,一个常用方法是使用预写日志(WAL),如edits文件,实现顺序增加操作来减少I/O操作(在NameNode中,所有操作都在RAM中完成),从而避免高消耗的查找操作,获取更好的整体性能。NameNode启动后,直接加载fsimage到RAM,再通过回放引入edits的增量变化,最终在内存中建立拥有最新信息的文件系统视图。

在Hadoop较新的几个版本中(具体地说,就是Apache Hadoop 2.0和CDH4;有关Hadoop更多版本信息,请参见4.1节“挑选Hadoop的发行版本”),底层元数据的存储拥有更好的可恢复性和支持NameNode的高可用性。在概念上,元数据的存储和以前的版本是类似的,除了事务不再保存在单一的edits文件中以外。在新版本中,NameNode周期性轮换edits文件(关闭一个文件,然后打开一个新文件),用事务ID号来标识。这样就提供了一种可能:NameNode可以保留旧的fsimageedits文件备份,从而可以更好地支持数据的回滚功能。大部分的这类改变对使用者几乎没有什么影响。之所以在这里提起是为了让读者能更好地理解磁盘上这些文件的用途,同时提醒读者不要轻易改动这些文件,除非你十分清楚你在干什么。本书接下来的章节提到这些文件的时候会使用它们的名字,分别用fsimage和edits来表明它们的功能。

NameNode只将改动内容写入WAL,即edits。随着时间的推移,edits文件会像其他的日志系统文件一样变得越来越大,当服务器发生故障时就需要很长的时间来回放。所以像传统的关系数据库那样,需要定期将edits文件引入到fsimage文件中。这样就带来了新的问题,NameNode在为集群提供服务时可能无法提供足够的资源——CPU或RAM来支持此运算。为了解决这一问题,引入了次NameNode。

NameNode和次NameNode之间的交互如图2-4所示。[1]

1. 次NameNode引导NameNode滚动更新edits文件,并开始将新的内容写入edits.new

2.次NameNode将NameNode的fsimageedits文件复制到本地的检查点目录。

3.次NameNode载入fsimage文件,回放edits内容,将其合并到fsimage,将新的fsimage文件压缩后写入磁盘。

4.次NameNode将新的fsimage文件送回NameNode,NameNode在接收新的fsimage文件后,直接加载和应用该文件。

5.NameNode将edits.new更名为edits

图2-4 元数据检查点处理过程

默认情况下,该过程每小时发生一次,或者当NameNode的edits文件大小达到默认的64MB时也会被触发。尽管后面我们会研究如何改变这些配置,但通常来说无需改变。在新版本的Hadoop中,通过使用预定义的事务次数而不是文件大小来触发该过程。

因为管理员的主要职责是确保大规模系统的服务质量和可用性,单点故障(single point of failure)可能会给我们带来麻烦,甚至带来非常糟糕的后果。不幸的是,长期以来,HDFS的NameNode就是困扰我们的单点故障问题。近来,Hadoop社区投入大量的人力来提升NameNode的高可用性,使Hadoop可以在更多重要应用场景下部署。

NameNode 高可用性(或称HA)是通过部署一对主/备NameNode的方式来实现的。主/备NameNode都需要能访问到edits的WAL,因此edits通常保存在一个共享的存储设备上。目前,是用NFS文件系统实现这种共享存储的,当然消除对NFS的依赖也已经在计划当中[2]。当主NameNode写入edits日志时,备用NameNode会即时重放事务以确保数据的完全同步,并在主NameNode发生故障时,随时接管它的工作。通过高可用性配置,集群中所有DataNode都知道主/备NameNode对的存在,它们会同时向这两台服务器发送块报告。

高可用性的主/备NameNodes对可以配置为手动或自动故障切换模式。在默认情况下,采用的是手动模式,需要用命令来触发NameNode状态的变更。当配置成自动模式时,这两个NameNode都会运行一个名为“切换控制器”的进程,来监管其他进程的状态并协调NameNode状态的变更。和其他高可用性系统一样,hadoop也有两种主要的故障切换模式:管理员主导的优雅故障切换模式(graceful failover)和由运行过程中发生的故障触发的非优雅故障切换模式(non-graceful failover)。然而,不管是哪一种模式,都很难确定主NameNode是否确实已经退出了活动状态,也许仅仅是因为备用NameNode访问不到它。这时,如果允许主、备NameNode进程同时工作,就有可能因同时写入共享文件而破坏文件系统的元数据,这一场景通常被称为脑裂(split brain)。因此,为了应对这样的情况,系统可以通过一系列严厉的手段来确保故障节点(可能还是活动的)真正停止工作。刚开始时可以用RPC来要求其停止工作,实在无效时可以使用“爆头”(Shoot The Other Node In The Head)技术,即通过IPMI 来重启机器。如果电源模块支持这项功能,甚至可以通过程控电源短时掉电的方式来完成。大部分管理员希望通过自动故障切换模式来实现系统的高可用性。图2-5所示为一个自动故障切换实例。

在高可用模式下,备用NameNode同时也会承担次NameNode的角色。也就是说,在HA集群中不会有单独的次NameNode进程,而只有一对NameNode进程。大多数情况下,已经通过专用主机部署次NameNode的Hadoop集群可以将该主机配置成备用NameNode。高可用性的不同配置选项可以参见5.6节“NameNode的高可用性”。

图2-5 自动故障切换模式的主/备NameNode配置

在写本书时,Apache Hadoop 2.0和CDH4已经支持NameNode的高可用性(简称NNHA)。

为什么不使用某个HA包?


熟悉Linux HA项目的用户可能会问:为什么不简单地写些脚本,像Linux HA那样解决HDFS NameNode高可用性的问题?虽然那些工具已经支持状态检测、带内/外

通信和保护插件等,但不幸的是,高可用性是个很复杂的问题,绝不仅仅是杀死一个进程而后在另一个地方重启一个新进程那么简单。

NameNode 高可靠性真正的挑战来自于DataNode—块报告只是写入NameNode内存而不是磁盘。换而言之,即便用这些系统搭建好一个集群、写入合适的健康检查报告、检测到错误、发起故障切换、激活备机,系统还是无法知道应该从哪儿找到数据块,仍然无法给HDFS客户端提供服务。当然,DataNodes或许可以通过一个虚拟IP(VIP)联系到NameNode,但它无法知道已经发生了故障切换,也无法向新NameNode发送块报告而使它快速获得集群最新状态。之前我们看到,接收和处理成百上千台DataNodes发送过来的块报告,实际上是集群启动过程中比较耗时的部分,需要数十分钟或更多的时间,而这种开销对于时间敏感的系统而言是无法接受的。

Linux-HA适合于无状态的业务处理类型,对于如NameNode的有状态业务是远远不够的。

很多Hadoop用户心里一直不爽:对存储在NameNode内存中的元数据大小有限制。为了冲破单个NameNode服务器中物理内存的限制,需要一种大规模系统来取代之前的按比例增长模式。正如HDFS的块存储一样,可以将文件系统元数据分布存储在多台主机上,这一技术被称之为命名空间联盟(Namespace Federation),即通过一组自治系统来组织一个逻辑名字空间。Linux文件系统是一个例子:多个设备被动态地配置在一个名字空间下,客户端可以方便地通过寻址访问就该名字空间而无需关注数据到底存储在哪个底层设备上。

NameNode联盟(如图2-6所示)将文件系统名字空间分片并分散存储到多台NameNode上,这样就绕开了单个NameNode内存限制的问题。顾名思义,NameNode联盟由一组各自独立的NameNode组成,每一个NameNode负责管理目录结构的不同部分。与相互隔离集群的最主要区别在于,由NameNode联盟管理的集群中每个DataNode可以给多个NameNode存储数据块。更确切地说,每个DataNode为每个名字空间维护一个数据块池(Block Pool)。尽管来自不同数据块池的数据块可以存储在同一个物理磁盘中,但在逻辑上它们是独立的。每个DataNode同时发送心跳报文和块报告给每一个NameNode。

客户端通常不关心存在多少个NameNode,因此引入ViewFS API来映射文件系统片与NameNode的关系。理论上,与Linux的/etc/fstab文件的功能是一样的,ViewFS除了映射路径和物理设备的关系,还映射路径和HDFS NameNode的关系。例如,ViewFS将NameNode1映射到路径/logs,NameNode2映射到路径/hbase。NameNode联盟还允许基于名字空间分区来控制系统可用性和文件系统片的容错性。如前所述,/hbase可能需要非常高的可靠性,而/logs仅仅需要支持MapReduce的批处理。

图2-6 NameNode联盟概况

最后,请注意高可用性和NameNode联盟是两个互相独立的功能,因为它们是针对不同的问题的。可以分别激活它们而互不影响,也就是说,名字空间可以被分区,其中部分分区(或全部分区)可以给一对高可用的NameNode提供服务。

本地访问HDFS的唯一方式是通过其提供的Java应用程序接口,其他的访问方式都是经过定义并建立在这些应用程序接口之上的,而且只能提供这些接口所允许的功能。为了使应用更容易使用和开发,HDFS借用了大量像Java I/O流这样的概念,因而HDFS 应用程序接口对开发者来讲非但不陌生,而且还非常简单。当然HDFS也对这些应用程序接口做了一些改动,以确保提供其所宣称的那些功能,但大部分的改动很容易理解,而且有很详细的文档。

为了访问HDFS,客户端——也就是用应用程序接口编写的应用程序——必须拥有一份配置数据副本,以获取NameNode的位置信息。这有些类似于Oracle客户端应用程序必须要有tnsname.ora文件一样。每个应用程序也必须能访问Hadoop程序库JAR文件,这也正如数据库应用必须依赖JDBC驱动程序JAR文件一样。多个客户端可以运行在集群里的任意物理主机上,也可以在集群之外。例如,MapReduce任务和HBase 区域服务器可以像任何其他客户程序一样访问HDFS,而有时它们也可以碰巧运行在同一台物理机器上,因为HDFS正好在这台机器上存储它们所需要的数据块。

在这里必须说明,为满足客户端直接访问DataNode的通信需要,客户程序与集群中所有节点相关端口间的网络连接必须保持畅通。这就隐含了网络规划、安全和带宽方面的要求,详情请参考4.6节“网络设计”。

Hadoop自带一组命令行工具,以便进行基本的文件系统操作。像所有的Hadoop工具一样,HDFS命令是hadoop命令行工具集的子集。运行hadoop fs可以显示基本的使用信息,如例2-1所示。

例2-1 hadoop fs帮助信息

[esammer@hadoop01 ~]$ hadoop fs
Usage: java FsShell
              [-ls <path>]
              [-lsr <path>]
              [-df [<path>]]
              [-du <path>]
              [-dus <path>]
              [-count[-q] <path>]
              [-mv <src> <dst>]
              [-cp <src> <dst>]
              [-rm [-skipTrash] <path>]
              [-rmr [-skipTrash] <path>]
               [-expunge]
               [-put <localsrc> ... <dst>]
               [-copyFromLocal <localsrc> ... <dst>]
               [-moveFromLocal <localsrc> ... <dst>]
               [-get [-ignoreCrc] [-crc] <src> <localdst>]
               [-getmerge <src> <localdst> [addnl]]
               [-cat <src>]
               [-text <src>]
               [-copyToLocal [-ignoreCrc] [-crc] <src> <localdst>]
               [-moveToLocal [-crc] <src> <localdst>]
               [-mkdir <path>]
               [-setrep [-R] [-w] <rep> <path/file>]
               [-touchz <path>]
               [-test -[ezd] <path>]
               [-stat [format] <path>]
               [-tail [-f] <file>]
               [-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]
               [-chown [-R] [OWNER][:[GROUP]] PATH...]
               [-chgrp [-R] GROUP PATH...]
               [-help [cmd]]

对于拥有基本shell经验的管理员而言,这些命令非常直观。主要的差别在于,因为HDFS是用户空间文件系统,所以没有当前工作目录的概念。所有路径要么是用户home目录下的绝对路径(推荐),要么是其相对路径[3]。绝对路径可以是/logs/2012/01/25形式,也可以是包含标明NameNode位置的完整URL,如hdfs://myNameNode.mycompany.com: 8020/logs/2012/01/25/。如果不使用完整URL语法,NameNode地址就是从core-site.xml的fs.default.name变量中获取的(参见例2-2)。

例2-2 列出HDFS文件和目录

[esammer@hadoop01 ~]$ hadoop fs -ls /user/esammer
Found 4 items
drwx------  - esammer supergroup   0 2012-01-11 15:06 /user/esammer/.staging
-rw-r--r--  3 esammer supergroup 2788889 0 2012-01-10 13:41 /user/esammer/data.txt
drwxr-xr-x  - esammer supergroup           0 2012-01-11 13:08 /user/esammer/teragen
drwxr-xr-x  - esammer supergroup           0 2012-01-11 15:06 /user/esammer/terasort

为了证明HDFS名字空间与主机OS是完全独立的,可以尝试用标准的ls命令列出相同路径信息(参见例2-3)。

例2-3 尝试在OS中列出HDFS路径

esammer@hadoop01 ~]$ ls /user/esammer
ls: /user/esammer: No such file or directory

在很多方面,HDFS较之于本地OS文件系统更像一个远程文件系统。对HDFS文件的复制操作更像SCP或FTP操作,而非NFS上的文件系统操作。文件上传使用-put或-copyFromLocal,文件下载使用-get或-copyToLocal。为了方便,-copyFromLocal和-copyToLocal分别用来从本地复制文件到HDFS或将HDFS文件复制到本地,然后自动删除源文件(参见例2-4)。

例2-4 复制文件到HDFS和从HDFS复制文件

[esammer@hadoop01 ~]$ hadoop fs -ls /user/esammer/
Found 2 items
drwx------     - esammer supergroup            0 2012-01-11 15:06 /user/esammer/.staging
-rw-r--r--     3 esammer supergroup   2788889 0 2012-01-10 13:41 /user/esammer/data.txt
[esammer@hadoop01 ~]$ hadoop fs -put /etc/passwd /user/esammer/
[esammer@hadoop01 ~]$ hadoop fs -ls /user/esammer/
Found 3 items
drwx------     - esammer supergroup            0 2012-01-11 15:06 /user/esammer/.staging
-rw-r--r--     3 esammer supergroup   2788889 0 2012-01-10 13:41 /user/esammer/data.txt
-rw-r--r--     3 esammer supergroup         2216 2012-01-25 21:07 /user/esammer/passwd
esammer@hadoop01 ~]$ ls -al passwd
ls: passwd: No such file or directory
[esammer@hadoop01 ~]$ hadoop fs -get /user/esammer/passwd ./
[esammer@hadoop01 ~]$ ls -al passwd 
-rw-rw-r--+ 1 esammer esammer 2216 Jan 25 21:17 passwd
[esammer@hadoop01 ~]$ hadoop fs -rm /user/esammer/passwd
Deleted hdfs://hadoop01.sf.cloudera.com/user/esammer/passwd

HDFS的另一特别之处在于能够设置文件的复制因子。用-setrep命令,加上复制因子和可选标志(-R)表示要递归执行该操作(参见例2-5)。

例2-5 修改HDFS文件的复制因子

[esammer@hadoop01 ~]$ hadoop fs -setrep 5 -R /user/esammer/tmp/
Replication 5 set: hdfs://hadoop01.sf.cloudera.com/user/esammer/tmp/a
Replication 5 set: hdfs://hadoop01.sf.cloudera.com/user/esammer/tmp/b
[esammer@hadoop01 ~]$ hadoop fsck /user/esammer/tmp -files -blocks –locations
FSCK started by esammer from /10.1.1.160 for path /user/esammer/tmp at
Wed Jan 25 21:57:39 PST 2012
/user/esammer/tmp <dir>
/user/esammer/tmp/a 27888890 bytes, 1 block(s):  OK
0. blk_2989979708465864046_2985473 len=27888890 repl=5 [10.1.1.162:50010,
10.1.1.161:50010, 10.1.1.163:50010, 10.1.1.165:50010, 10.1.1.164:50010]
/user/esammer/tmp/b 27888890 bytes, 1 block(s):  OK
0. blk_-771344189932970151_2985474 len=27888890 repl=5 [10.1.1.164:50010,
10.1.1.163:50010, 10.1.1.161:50010, 10.1.1.162:50010, 10.1.1.165:50010]

在例2-5中,tmp目录下的文件ab的复制因子被修改成为了5。然后,用fsck命令(请参见8.2.3节“用fsck来检查文件系统的一致性”)检查文件正确性,fsck命令的另一个好处是可以同时显示每个文件的块位置信息。在这个例子里,每个数据块的5个副本分别存储在集群中5个不同的DataNode中。注意,只有文件才有数据块列表,HDFS中的目录纯粹是元数据,并没有任何数据块。

用户空间文件系统(FUSE),是一种允许开发者在用户空间实现的可安装文件系统的系统,不需要对内核模块进行开发。这样不仅可以让开发人员的工作变得更加简单,因为可以使用熟悉环境下的标准库;而且更加安全,因为开发人员引入的软件错误不会影响到内核。

Apache Hadoop和CDH都支持HDFS用户空间文件系统。你可能已经猜到,这样不仅可以将HDFS分布式文件系统挂载到任何其他的设备上,还可以兼容那些老的应用和系统,对Linux服务器上的普通目录文件进行读写,而其背后实际上是挂载了HDFS的设备。尽管FUSE很方便,但它并不是万能的,它有HDFS的所有属性,如不支持对文件进行修改、较大的处理延时、低效的随机访问、对大型流操作做了的一些优化以及支持大规模扩展。说得更清楚点,FUSE并没有将HDFS变成兼容POSIX的文件系统,而仅仅是加了一个兼容层,可以让应用通过使用HDFS来做一些基本的文件操作。

过去的几年中,表示性状态传输(Representational State Transfer,REST)作为一种与语言无关的方式被越来越广泛地应用,并与各种业务进行交互。Hadoop的所有原始的应用程序接口都是基于Java的,对于非Java的客户程序就会存在问题。应用程序可以通过hadoop fs命令行的方式解决问题,但是效率不高,而且容易发生错误。从Apache Hadoop 1.0.0和CDH4开始,WebHDFS(一种用于HDFS的REST API)已经成为标准软件的一部分。WebHDFS利用Hadoop HDFS守护进程中内嵌的Web服务器运行一套REST应用程序接口,模仿Java文件系统API(包括读/写操作)。WebHDFS支持包括Kerberos SPNEGO在内的完整的鉴权功能。 例2-6给出了一个基于WebHDFS的hadoop fs –ls /hbase的操作例子。

例2-6 用WebHDFS REST显示文件目录

[esammer@hadoop01 ~]$ curl http://hadoop01:50070/webhdfs/v1/hbase /?op= liststatus
{"FileStatuses":{"FileStatus":[
{"accessTime":0,"blockSize":0,"group":"hbase","length":0,"modificationTime":
1342560095961,"owner":"hbase","pathSuffix":"-ROOT-","permission":"755",
"replication":0,"type":"DIRECTORY"},
{"accessTime":0,"blockSize":0,"group":"hbase","length":0,"modificationTime":
1342560094415,"owner":"hbase","pathSuffix":".META.","permission":"755",
"replication":0,"type":"DIRECTORY"},
{"accessTime":0,"blockSize":0,"group":"hbase","length":0,"modificationTime":
1342561404890,"owner":"hbase","pathSuffix":".logs","permission":"755",
"replication":0,"type":"DIRECTORY"},
{"accessTime":0,"blockSize":0,"group":"hbase","length":0,"modificationTime": 
1342561406399,"owner":"hbase","pathSuffix":".oldlogs","permission":"755",
"replication":0,"type":"DIRECTORY"},
{"accessTime":1342560093866,"blockSize":67108864,"group":"hbase","length":38,
"modificationTime":1342560093866,"owner":"hbase","pathSuffix":"hbase.id",
"permission":"644","replication":3,"type":"FILE"},
{"accessTime":1342560093684,"blockSize":67108864,"group":"hbase","length":3, 
"modificationTime":1342560093684,"owner":"hbase","pathSuffix":"hbase.version",
"permission":"644","replication":3,"type":"FILE"}
]}}

与此同时,一个名为HttpFS的单独的REST HDFS代理服务也被开发出来。初看起来,似乎WebHDFS和HttpFS是用来解决同一个问题的,其实不然。虽然HttpFSAPI与WebHDFS完全兼容,但它们解决的是两种不同的架构问题。要使用每个守护进程的内嵌Web服务器,WebHDFS客户程序必须可以和集群中的所有节点进行通信,就像JAVA客户端一样。HttpFS的存在主要是为了解决这个问题,它更像一个跨不同网段的网关,客户程序只需和HttpFS守护进程连接,而由该守护进程使用标准JAVA API与HDFS集群进行通信。HttpFS的优点是可以减少与集群通信的数量,但代价是集群的总体规模和能力会受到限制,因为所有客户程序和HDFS之间的数据交换都是通过一个节点完成的。当然,设置多个HttpFS代理可以很好地解决单节点带宽限制的问题。另外,因为WebHDFS和HttpFS的API是完全兼容的,程序员在开发应用程序时需要充分考虑上述细节。最终的决策需要考虑数据吞吐率、网络规划和安全等方面。

[1] 对Apache Hadoop 和CDH4来说,这个过程略有不同,但在概念上是等同的。

[2] 请参考Apache JIRA HDFS-3077。

[3] 在HDFS中,用户默认的home目录是/user/<username>。


相关图书

Hadoop虚拟化
Hadoop虚拟化
大数据开发者权威教程:NoSQL、Hadoop组件及大数据实施
大数据开发者权威教程:NoSQL、Hadoop组件及大数据实施
Hadoop海量数据处理:技术详解与项目实战(第2版)
Hadoop海量数据处理:技术详解与项目实战(第2版)
Hadoop海量数据处理:技术详解与项目实战
Hadoop海量数据处理:技术详解与项目实战
Hadoop MapReduce实战手册
Hadoop MapReduce实战手册
Hadoop MapReduce性能优化
Hadoop MapReduce性能优化

相关文章

相关课程