用 Hadoop 进行分布式数据处理,第 1 部分: 入门

安装和配置简单的集群

本文是讨论 Hadoop 的系列中的第一篇。本文介绍 Hadoop 框架,包括 Hadoop 文件系统 (HDFS) 等基本元素和常用的节点类型。学习如何安装和配置单节点 Hadoop 集群,然后研究 MapReduce 应用程序。最后,学习使用核心 Web 界面监视和管理 Hadoop 的方法。

M. Tim Jones, 自由作家

M. Tim JonesM. Tim Jones 是一名嵌入式固件架构师,他是 Artificial Intelligence: A Systems Approach, GNU/Linux Application Programming (现在已经是第 2 版)、AI Application Programming (第 2 版)和 BSD Sockets Programming from a Multilanguage Perspective 等书的作者。他的工程背景非常广泛,从同步宇宙飞船的内核开发到嵌入式系统架构设计,再到网络协议的开发。Tim 是位于科罗拉多州 Longmont 的 Emulex Corp. 的一名顾问工程师。



2010 年 6 月 07 日

联系 Tim

Tim 是我们最受欢迎、最多产的作者之一。浏览 developerWorks 上 Tim 的所有文章。查看 Tim 的个人信息,与他和 My developerWorks 中的其他作者和读者联系。

尽管 Hadoop 是一些大型搜索引擎数据缩减功能的核心部分,但是它实际上是一个分布式数据处理框架。搜索引擎需要收集数据,而且是数量极大的数据。作为分布式框架,Hadoop 让许多应用程序能够受益于并行数据处理。

本文并不打算介绍 Hadoop 及其架构,而是演示一个简单的 Hadoop 设置。在 参考资料 中,可以找到关于 Hadoop 架构、组件和操作理论的更多信息。现在,我们来讨论 Hadoop 的安装和配置。

初始设置

Hadoop 的起源

Apache Hadoop 项目的灵感来源于 Google 的早期工作。尽管 Google 拥有这种大规模数据处理方法的专利,但是它慷慨地授予 Hadoop 许可证。详细信息见 参考资料

对于本文中的示例,我们使用 Cloudera Hadoop 发行版。Cloudera 提供对各种 Linux® 发行版的支持,所以很适合初学者。

本文假设您的系统上已经安装了 Java™(至少是 1.6 版)和 cURL。如果还没有,需要先安装它们(更多信息见 参考资料)。

因为我运行 Ubuntu(Intrepid 版),所以使用 apt 实用程序获取 Hadoop 发行版。这个过程非常简单,我可以获取二进制包,而不需要下载并构建源代码。首先,告诉 apt Cloudera 站点的信息。然后,在 /etc/apt/sources.list.d/cloudera.list 中创建一个新文件并添加以下文本:

deb http://archive.cloudera.com/debian intrepid-cdh3 contrib
deb-src http://archive.cloudera.com/debian intrepid-cdh3 contrib

如果您运行 Jaunty 或其他版本,只需把 intrepid 替换为您的版本名(当前支持 Hardy、Intrepid、Jaunty、Karmic 和 Lenny)。

接下来,从 Cloudera 获取 apt-key 以检查下载的包:

$ curl -s http://archive.cloudera.com/debian/archive.key | \
sudo apt-key add - sudo apt-get update

然后,安装采用伪分布式配置的 Hadoop(所有 Hadoop 守护进程在同一个主机上运行):

$ sudo apt-get install hadoop-0.20-conf-pseudo
$

注意,这个配置大约 23MB(不包括 apt 可能下载的其他包)。这个配置非常适合体验 Hadoop 以及了解它的元素和界面。

最后,我设置了不需要密码的 SSH。如果打算使用 ssh localhost 并请求密码,就需要执行以下步骤。我假设这是专用的 Hadoop 机器,因为这个步骤对安全性有影响(见清单 1)。

清单 1. 设置不需要密码的 SSH
$ sudo su -
# ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa
# cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys

最后,需要确保主机上有供 datanode使用的足够存储空间(缓存)。存储空间不足会导致系统表现异常(比如出现无法把数据复制到节点的错误)。


启动 Hadoop

现在可以启动 Hadoop 了,这实际上要启动每个 Hadoop 守护进程。但是,首先使用 hadoop 命令对 Hadoop File System (HDFS) 进行格式化。hadoop 命令有许多用途,稍后讨论其中一部分。

首先,请求 namenode 对 DFS 文件系统进行格式化。在安装过程中完成了这个步骤,但是了解是否需要生成干净的文件系统是有用的。

# hadoop-0.20 namenode -format

在确认请求之后,文件系统进行格式化并返回一些信息。接下来,启动 Hadoop 守护进程。Hadoop 在这个伪分布式配置中启动 5 个守护进程:namenode、secondarynamenode、datanode、jobtracker 和 tasktracker。在启动每个守护进程时,会看到一些相关信息(指出存储日志的位置)。每个守护进程都在后台运行。图 1 说明完成启动之后伪分布式配置的架构。

图 1. 伪分布式 Hadoop 配置
伪分布式 Hadoop 配置的框图

Hadoop 提供一些简化启动的辅助工具。这些工具分为启动(比如 start-dfs)和停止(比如 stop-dfs)两类。下面的简单脚本说明如何启动 Hadoop 节点:

# /usr/lib/hadoop-0.20/bin/start-dfs.sh
# /usr/lib/hadoop-0.20/bin/start-mapred.sh
#

要想检查守护进程是否正在运行,可以使用 jps 命令(这是用于 JVM 进程的 ps 实用程序)。这个命令列出 5 个守护进程及其进程标识符。

既然 Hadoop 守护进程已经在运行了,现在看看每个守护进程在 Hadoop 框架中的作用。namenode 是 Hadoop 中的主服务器,它管理文件系统名称空间和对集群中存储的文件的访问。还有一个 secondary namenode,它不是 namenode 的冗余守护进程,而是提供周期检查点和清理任务。在每个 Hadoop 集群中可以找到一个 namenode 和一个 secondary namenode。

datanode 管理连接到节点的存储(一个集群中可以有多个节点)。每个存储数据的节点运行一个 datanode 守护进程。

最后,每个集群有一个 jobtracker,它负责调度 datanode 上的工作。每个 datanode 有一个 tasktracker,它们执行实际工作。jobtracker 和 tasktracker 采用主-从形式,jobtracker 跨 datanode 分发工作,而 tasktracker 执行任务。jobtracker 还检查请求的工作,如果一个 datanode 由于某种原因失败,jobtracker 会重新调度以前的任务。

在这个简单的配置中,所有节点都驻留在同一个主机上(见 图 1)。但是,通过前面的讨论很容易看出 Hadoop 如何提供并行处理。尽管架构很简单,但是 Hadoop 能够方便地实现数据分发、负载平衡以及以容错的方式并行处理大量数据。


检查 HDFS

可以通过几个检查确认 Hadoop(至少是 namenode)已经启动并正常运行。确认所有进程都在运行之后,可以使用 hadoop 命令检查本地名称空间(见清单 2)。

清单 2. 检查对 HDFS 的访问
# hadoop-0.20 fs -ls /
Found 2 items
drwxr-xr-x   - root supergroup          0 2010-04-29 16:38 /user
drwxr-xr-x   - root supergroup          0 2010-04-29 16:28 /var
#

可以看出 namenode 已经启动,能够为本地名称空间提供服务。注意,使用 hadoop-0.20 命令检查文件系统。这个实用程序用于与 Hadoop 集群交互,包括检查文件系统、在集群中运行作业等等。请注意命令的结构:指定 hadoop-0.20 实用程序之后,定义一个命令(在这里是通用文件系统 shell)以及一个或多个选项(在这里使用 ls 请求文件列表)。因为 hadoop-0.20 是 Hadoop 集群的主要接口之一,您会看到本文中多次使用这个实用程序。清单 3 提供另外几个文件系统操作示例(创建子目录 test,列出它的内容,然后删除它),可以通过它们进一步了解这个接口。

清单 3. Hadoop 中的文件系统操作
# hadoop-0.20 fs -mkdir test
# hadoop-0.20 fs -ls test
# hadoop-0.20 fs -rmr test
Deleted hdfs://localhost/user/root/test
#

测试 Hadoop

既然已经安装了 Hadoop 并测试了文件系统的基本接口,现在就该在真实的应用程序中测试 Hadoop 了。在这个示例中,我们使用 MapReduce 处理一个小数据集。map(映射)reduce(缩减) 源自函数式编程中的函数名,但是这个应用程序的核心功能是数据缩减。映射 是指把大量输入处理成更小的子问题集(然后把这些子问题分发给并行的工作系统)。缩减 是指把子问题的答案组合成单一输出集。注意,这里没有定义处理 的含义,因为框架允许您自己定义什么是处理。典型的 MapReduce 示例是计算单词在文档集中出现的频率。

根据前面的讨论,我们需要一个输入集并产生一个输出集。第一步是在文件系统中创建一个 input 子目录,工作将放在这个目录中。使用以下命令:

# hadoop-0.20 fs -mkdir input

接下来,在 input 目录中放一些工作。在这里,使用 put 命令把文件从本地文件系统转移到 HDFS 中(见清单 4)。注意,下面的命令格式把源文件转移到 HDFS 子目录 (input) 中。完成之后,在 HDFS 中就有两个文本文件等待处理。

清单 4. 把文件转移到 HDFS 中
# hadoop-0.20 fs -put /usr/src/linux-source-2.6.27/Doc*/memory-barriers.txt  input
# hadoop-0.20 fs -put /usr/src/linux-source-2.6.27/Doc*/rt-mutex-design.txt  input
#

接下来,使用 ls 命令检查文件是否存在(见清单 5)。

清单 5. 检查 HDFS 中的文件
# hadoop-0.20 fs -ls input
Found 2 items
-rw-r--r--  1 root supergroup 78031 2010-04-29 17:35 /user/root/input/memory-barriers.txt
-rw-r--r--  1 root supergroup 33567 2010-04-29 17:36 /user/root/input/rt-mutex-design.txt 
#

确认工作已经放在 HDFS 中之后,就可以执行 MapReduce 函数了。这个函数只需要一个命令,但是需要很长的请求,见清单 6。这个命令请求执行一个 JAR。它实际上实现许多功能,但是这个示例只使用 wordcount。jobtracker 守护进程请求 datanode 执行 MapReduce 作业,这会产生相当多的输出(这里的输出比较少是因为只处理两个文件)。它显示 map 和 reduce 函数的进度,然后提供与文件系统的 I/O 和记录处理相关的统计数据。

清单 6. 执行计算单词频率的 MapReduce 作业
# hadoop-0.20 jar /usr/lib/hadoop-0.20/hadoop-0.20.2+228-examples.jar \
wordcount input output
10/04/29 17:36:49 INFO input.FileInputFormat: Total input paths to process : 2
10/04/29 17:36:49 INFO mapred.JobClient: Running job: job_201004291628_0009
10/04/29 17:36:50 INFO mapred.JobClient:  map 0% reduce 0%
10/04/29 17:37:00 INFO mapred.JobClient:  map 100% reduce 0%
10/04/29 17:37:06 INFO mapred.JobClient:  map 100% reduce 100%
10/04/29 17:37:08 INFO mapred.JobClient: Job complete: job_201004291628_0009
10/04/29 17:37:08 INFO mapred.JobClient: Counters: 17
10/04/29 17:37:08 INFO mapred.JobClient:   Job Counters 
10/04/29 17:37:08 INFO mapred.JobClient:     Launched reduce tasks=1
10/04/29 17:37:08 INFO mapred.JobClient:     Launched map tasks=2
10/04/29 17:37:08 INFO mapred.JobClient:     Data-local map tasks=2
10/04/29 17:37:08 INFO mapred.JobClient:   FileSystemCounters
10/04/29 17:37:08 INFO mapred.JobClient:     FILE_BYTES_READ=47556
10/04/29 17:37:08 INFO mapred.JobClient:     HDFS_BYTES_READ=111598
10/04/29 17:37:08 INFO mapred.JobClient:     FILE_BYTES_WRITTEN=95182
10/04/29 17:37:08 INFO mapred.JobClient:     HDFS_BYTES_WRITTEN=30949
10/04/29 17:37:08 INFO mapred.JobClient:   Map-Reduce Framework
10/04/29 17:37:08 INFO mapred.JobClient:     Reduce input groups=2974
10/04/29 17:37:08 INFO mapred.JobClient:     Combine output records=3381
10/04/29 17:37:08 INFO mapred.JobClient:     Map input records=2937
10/04/29 17:37:08 INFO mapred.JobClient:     Reduce shuffle bytes=47562
10/04/29 17:37:08 INFO mapred.JobClient:     Reduce output records=2974
10/04/29 17:37:08 INFO mapred.JobClient:     Spilled Records=6762
10/04/29 17:37:08 INFO mapred.JobClient:     Map output bytes=168718
10/04/29 17:37:08 INFO mapred.JobClient:     Combine input records=17457
10/04/29 17:37:08 INFO mapred.JobClient:     Map output records=17457
10/04/29 17:37:08 INFO mapred.JobClient:     Reduce input records=3381

处理结束之后,检查结果。这个作业的作用是计算单词在输入文件中出现的次数。输出是一个包含元组的文件,元组表示单词和它在输入中出现的次数。找到输出文件之后,可以通过 hadoop-0.20 实用程序使用 cat 命令查看数据(见清单 7)。

清单 7. 检查 MapReduce wordcount 操作的输出
# hadoop-0.20 fs -ls /user/root/output
Found 2 items
drwxr-xr-x   - root supergroup          0 2010-04-29 17:36 /user/root/output/_logs
-rw-r--r--   1 root supergroup      30949 2010-04-29 17:37 /user/root/output/part-r-00000
#  
# hadoop-0.20 fs -cat output/part-r-00000 | head -13
!= 1
"Atomic 2
"Cache 2
"Control 1
"Examples 1
"Has 7
"Inter-CPU 1
"LOAD 1
"LOCK" 1
"Locking 1
"Locks 1
"MMIO 1
"Pending 5
#

还可以使用 hadoop-0.20 实用程序从 HDFS 中提取文件(见清单 8)。只需使用 get 实用程序(它与前面在 HDFS 中写文件所用的 put 相似)。对于 get 操作,指定 HDFS 中要提取的文件(来自 output 子目录)和在本地文件系统中要写的文件 (output.txt)。

清单 8. 从 HDFS 提取输出
# hadoop-0.20 fs -get output/part-r-00000 output.txt
# cat output.txt | head -5
!= 1
"Atomic 2
"Cache 2
"Control 1
"Examples 1
#

我们再来看一个示例,它使用相同的 JAR,但是目的不同(在这里要试验并行的 grep)。对于这个测试,仍然使用现有的输入文件,但是要删除 output 子目录以便在测试时重新创建它:

# hadoop-0.20 fs -rmr output
Deleted hdfs://localhost/user/root/output

接下来,请求用于执行 grep 的 MapReduce 作业。在这种情况下,并行执行 grep(映射),然后组合 grep 的结果(缩减)。清单 9 给出这个使用模型的输出(为了简短,这里删除了一些输出)。注意,这里的命令请求是一个 grep,它从 input 子目录获取输入,把结果放在 output 子目录中。最后一个参数是要搜索的字符串(在这里是 'kernel')。

清单 9. 执行单词搜索计数的 MapReduce 作业 (grep)
# hadoop-0.20 jar /usr/lib/hadoop/hadoop-0.20.2+228-examples.jar \
grep input output 'kernel'
10/04/30 09:22:29 INFO mapred.FileInputFormat: Total input paths to process : 2
10/04/30 09:22:30 INFO mapred.JobClient: Running job: job_201004291628_0010
10/04/30 09:22:31 INFO mapred.JobClient:  map 0% reduce 0%
10/04/30 09:22:42 INFO mapred.JobClient:  map 66% reduce 0%
10/04/30 09:22:45 INFO mapred.JobClient:  map 100% reduce 0%
10/04/30 09:22:54 INFO mapred.JobClient:  map 100% reduce 100%
10/04/30 09:22:56 INFO mapred.JobClient: Job complete: job_201004291628_0010
10/04/30 09:22:56 INFO mapred.JobClient: Counters: 18
10/04/30 09:22:56 INFO mapred.JobClient:   Job Counters 
10/04/30 09:22:56 INFO mapred.JobClient:     Launched reduce tasks=1
10/04/30 09:22:56 INFO mapred.JobClient:     Launched map tasks=3
10/04/30 09:22:56 INFO mapred.JobClient:     Data-local map tasks=3
10/04/30 09:22:56 INFO mapred.JobClient:   FileSystemCounters
10/04/30 09:22:56 INFO mapred.JobClient:     FILE_BYTES_READ=57
10/04/30 09:22:56 INFO mapred.JobClient:     HDFS_BYTES_READ=113144
10/04/30 09:22:56 INFO mapred.JobClient:     FILE_BYTES_WRITTEN=222
10/04/30 09:22:56 INFO mapred.JobClient:     HDFS_BYTES_WRITTEN=109
...
10/04/30 09:23:14 INFO mapred.JobClient:     Map output bytes=15
10/04/30 09:23:14 INFO mapred.JobClient:     Map input bytes=23
10/04/30 09:23:14 INFO mapred.JobClient:     Combine input records=0
10/04/30 09:23:14 INFO mapred.JobClient:     Map output records=1
10/04/30 09:23:14 INFO mapred.JobClient:     Reduce input records=1
#

作业完成之后,检查 output 目录,找到结果文件,然后通过执行文件系统 cat 操作查看其内容(见清单 10)。

清单 10. 检查 MapReduce 作业的输出
# hadoop-0.20 fs -ls output
Found 2 items
drwxr-xr-x  - root supergroup    0 2010-04-30 09:22 /user/root/output/_logs
-rw-r--r--  1 root supergroup   10 2010-04-30 09:23 /user/root/output/part-00000
# hadoop-0.20 fs -cat output/part-00000
17 kernel
#

基于 Web 的界面

您已经知道如何检查 HDFS 了,但是如果要寻找 Hadoop 的操作的相关信息,会发现 Web 界面很有用。位于 Hadoop 集群最上层的是 namenode,它管理 HDFS。可以通过 http://localhost:50070 查看文件系统的高层信息(比如可用空间、已用空间和可用的 datanode)以及正在运行的作业。可以通过 http://localhost:50030 深入检查 jobtracker(作业状态)。注意,在这两种情况下都引用 localhost,因为所有守护进程都在同一个主机上运行。


更进一步

本文讨论了一个简单的(伪分布式)Hadoop 集群的安装和初始配置。在这里,我选用 Cloudera 的 Hadoop 发行版是因为它简化了 Hadoop 的安装和初始配置。可以在 apache.org 找到许多 Hadoop 发行版(包括源代码)。更多信息见 参考资料

但是,如果缺少硬件资源,无法扩展 Hadoop 集群以满足自己的需要,那么应该怎么办?由于 Hadoop 非常流行,可以很方便地在云计算基础设施中使用预构建的 Hadoop VM 和租用的服务器运行它。Amazon 在 Amazon Elastic Compute Cloud (Amazon EC2) 中提供 Amazon Machine Image (AMI) 和计算资源。另外,Microsoft 最近宣布将在它的 Windows® Azure Services Platform 中支持 Hadoop。

通过本文很容易看出 Hadoop 显著简化了处理大型数据集的分布式计算。本系列中的下一篇文章通过更多示例讨论如何在多节点集群中配置 Hadoop。

参考资料

学习

获得产品和技术

讨论

  • 加入 My developerWorks 社区。查看开发人员推动的博客、论坛、组和 wikis,并与其他 developerWorks 用户交流。

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


这是您第一次登陆到 developerWorks,已经自动为您创建了您的概要文件。 选择您概要文件中可以公开的信息的信息(如姓名、国家/地区,以及公司),这些信息同时也会与您所发布的内容相关联。 您可以随时更新您的 IBM 账号。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Linux, Cloud computing
ArticleID=494615
ArticleTitle=用 Hadoop 进行分布式数据处理,第 1 部分: 入门
publish-date=06072010