我一直都对分布式文件系统非常感兴趣,特别喜欢研究如何在庞大的廉价的异构系统集群上进行容错性良好的分布式存储。这些话题总是能吸引我的注意力。记得2002年的时候因公司的需要有机会实践了一把 OpenAFS 和 Coda ,印象深刻,呵呵。好了,闲话少叙,今天将要谈论的是后起之秀 Hadoop 。
Hadoop 是大名鼎鼎的 Lucene 旗下的子项目,它原先是 Nutch 项目的组成部分,于2006年初从 Nutch 中分离出来成为一个独立的项目。Hadoop 其实并非一个单纯用于存储的分布式文件系统,而是一个被设计用来在由普通硬件设备组成的大型集群上执行分布式应用的框架(framework)。 Hadoop 包含两个部分:一个分布式文件系统 HDFS (Hadoop Distributed File System),和一个 MapReduce 实现。因此,Hadoop 的目标是为开发分布式应用提供一个框架,而不是像 OpenAFS, Coda 那样为存储提供一个分布式文件系统。搜索引擎就是一种典型的分布式程序,Nutch 就是基于 Hadoop 开发的。
本文的目标是描述如何安装和使用 Hadoop 0.9.2,不涉及如何使用 Hadoop 框架来开发分布式程序(此话题我将在 Part 2 中介绍之)。
本文内容:
1. 环境
2. 约定
3. SSH 设置
4. Hadoop 环境设置
5. 指定次节点
6. Hadoop 配置
7. 部署 Hadoop 到其他机器
8. 格式化 namenode
9. 启动 Hadoop
10. 停止 Hadoop
11. 几个简单地 HDFS 操作
12. 附录
1 环境
我使用了两台机器,都是很普通的PC机:
devh1 使用的是 Ubuntu Linux 6.10 系统,IP 地址是 192.168.96.48
devh2 使用的是 SuSE Linux Enterprise Desktop 10 系统,IP 地址是 192.168.96.198
请务必确保所有机器的主机名和它的 IP 之间解析正确,这很重要。
从 HDFS 的角度来看,Hadoop 有两种节点:namenode,datanode。其中 namenode 有且只有一个,datanode 可以有很多。从 MapReduce 角度来看,Hadoop 有两种节点:jobtracker,tasktracker。其中 jobtracker 有且只有一个,tasktracker 可以有很多。
在本文中,我将把 namenode, jobtracker 设置到 devh1 上,同时 devh1 和 devh2 都是 datanode, tasktracker。
2 约定
Hadoop 要求所有机器上都有一个相同用户名的帐号(密码可以不同),且 Hadoop 部署的目录结构在各台机器亦需相同,为行文方便,做如下约定:
在这两台机器都存在一个帐号 huangys ,其宿主目录均为 /home/huangys
Hadoop 部署目录结构为:
/home/huangys/hadoop-deployed
/filesystem
(filesystem is the root of the HDFS)
/hadoop-0.9.2
(hadoop 0.9.2 installation goes here)
/java
(JDK installation goes here. It's OK to create a symbol link to an actual JDK installation.)
两台机器上都安装了 JDK。为了方便使用,我在部署目录下创建了一个 symbol link.
3 SSH 设置
所有机器上必须都安装了 SSH 服务器,且它们都监听默认端口 22,因为 Hadoop 通过 SSH 来启动和停止各个节点上的各种守护进程。另外, Hadoop 在节点之间执行指令时必须是不用输入密码的方式,所以我们需要配置 SSH 使用公钥方式来认证身份。在本文中,devh1 是我们的主节点(因为 namenode, jobtracker 均运行于其上),因此我们只需要为 huangys@devh1 产生密钥对,并把它的公钥加入到 huangys@devh2 的认证文件中。
huangys@devh1:~$ ssh-keygen -t rsa
这将为 devh1 上的用户帐号 huangys 生成其身份标识密钥对。当提示为生成的密钥对输入 passphrase 时,直接回车,即保持访问密码为空。
生成的密钥对有两个文件 id_rsa, id_rsa.pub,默认存储在 /home/huangys/.ssh/ 下。
然后把 id_rsa.pub 的内容(就一行,不过很长,想乱码一样)复制到所有机器(包括 devh1 自己)的 /home/huangys/.ssh/authorized_keys 文件中。若这个文件不存在,就创建一个好了。
这时可以再试试从 devh1 上 ssh 到 devh2 ,就不用输入密码了,直接通过公钥方式认证身份了。
4 Hadoop 环境设置
Hadoop 的相关环境变量是通过 conf 目录下的文件 hadoop-env.sh 完成的,这个文件总是会被其他指令在执行期调用。除了 JAVA_HOME 是必须的,其余皆是可选。
我设置了如下两项:
export HADOOP_HOME=/home/huangys/hadoop-deployed/hadoop-0.9.2
export JAVA_HOME=/home/huangys/hadoop-deployed/java
5 指定次节点
在 conf 目录下还有一个配置档 slaves ,该文件用来指定集群中的次节点,一行一个,指定主机名即可。在本文中,这两台机器都充当了次节点,所以我加入了如下两行:
devh1
devh2
注意, slaves 文件缺省有一行 localhost ,将它删除,因为本文中 Hadoop 运行在多个节点上。
Hadoop 也可以运行在单节点上,此时 slaves 文件中就不用修改了。
6 Hadoop 配置
hadoop-default.xml 包含了全部的 Hadoop 配置项,不过直接修改这个文件是非常不推荐的。如果我们需要调整某项的设置,就把该项在 hadoop-site.xml 中重新定义,其值将会覆盖 hadoop-default.xml 定义的默认值。
以下是我的 hadoop-site.xml 档:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<!-- Put site-specific property overrides in this file. -->
<configuration>
<property>
<name>fs.default.name</name>
<value>devh1:9000</value>
<description>The name of the default file system. Either the literal string "local" or a host:port for DFS.</description>
</property>
<property>
<name>mapred.job.tracker</name>
<value>devh1:9001</value>
<description>The host and port that the MapReduce job tracker runs at. If "local", then jobs are run in-process as a single map and reduce task.</description>
</property>
<property>
<name>mapred.map.tasks</name>
<value>3</value>
<description>The default number of map tasks per job. Typically set to a prime several times greater than number of available hosts. Ignored when mapred.job.tracker is "local". </description>
</property>
<property>
<name>mapred.reduce.tasks</name>
<value>2</value>
<description>The default number of reduce tasks per job. Typically set to a prime close to the number of available hosts. Ignored when mapred.job.tracker is "local".</description>
</property>
<property>
<name>dfs.name.dir</name>
<value>/home/huangys/hadoop-deployed/filesystem/name</value>
<description>Determines where on the local filesystem the DFS name node should store the name table. If this is a comma-delimited list of directories then the name table is replicated in all of the directories, for redundancy. </description>
</property>
<property>
<name>dfs.data.dir</name>
<value>/home/huangys/hadoop-deployed/filesystem/data</value>
<description>Determines where on the local filesystem an DFS data node should store its blocks. If this is a comma-delimited list of directories, then data will be stored in all named directories, typically on different devices. Directories that do not exist are ignored.</description>
</property>
<property>
<name>mapred.system.dir</name>
<value>/home/huangys/hadoop-deployed/filesystem/mapred/system</value>
<description>The shared directory where MapReduce stores control files.</description>
</property>
<property>
<name>mapred.local.dir</name>
<value>/home/huangys/hadoop-deployed/filesystem/mapred/local</value>
<description>The local directory where MapReduce stores intermediate data files. May be a comma-separated list of directories on different devices in order to spread disk i/o. Directories that do not exist are ignored.</description>
</property>
<property>
<name>dfs.replication</name>
<value>2</value>
<description>Default block replication. The actual number of replications can be specified when the file is created. The default is used if replication is not specified in create time.</description>
</property>
</configuration>
根据实际开发的分布式程序的需求不同、所有拥有的机器数量不同,这个配置档可以有很大的差异,具体情况具体分析。
7 部署 Hadoop 到其他机器
完成对 hadoop-env.sh, slaves, hadoop-site.xml 的设置后,我们的 Hadoop 就完成配置了,下面需要将此配置完好的 Hadoop 部署到其他所有机器上去,还记得前面所说,部署目录结构必须完全一致。
huangys@devh1:~$ cd hadoop-deployed
huangys@devh2:~/hadoop-deployed$ scp -r hadoop-0.9.2 huangys@devh2:/home/huangys/hadoop-deployed
8 格式化 namenode
在正式启动 Hadoop 之前需要格式化 namenode ,很简单的一句指令:
huangys@devh1:~$ cd hadoop-deployed/hadoop-0.9.2
huangys@devh1:~/hadoop-deployed/hadoop-0.9.2$ bin/hadoop namenode -format
看屏幕信息,是否正确完成格式化,若有错误,到 logs 目录下看出了什么错。通常是不是有异常的。
9 启动 Hadoop
哈哈,终于到了启动的时刻了 ^o^ ,Hadoop 提供了好些个启动脚本,打开看看就知道何时用哪个了。这里我们使用最便捷的 *-all.sh
huangys@devh1:~$ cd hadoop-deployed/hadoop-0.9.2
huangys@devh1:~/hadoop-deployed/hadoop-0.9.2$ bin/start-all.sh
完成启动后,可以通过用 lsof 指令检查我们在配置档中指定端口 9000, 9001 是否正常打开来判断是否正常启动了 Hadoop :
huangys@devh1:~$ lsof -i:9000
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
java 14133 huangys 9u IPv6 53226 TCP devh1:9000 (LISTEN)
java 14133 huangys 12u IPv6 78642 TCP devh1:9000->devh2:1279 (ESTABLISHED)
java 14133 huangys 14u IPv6 78649 TCP devh1:9000->devh1:48692 (ESTABLISHED)
java 14215 huangys 6u IPv6 78648 TCP devh1:48692->devh1:9000 (ESTABLISHED)
huangys@devh1:~$ lsof -i:9001
COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME
java 14301 huangys 8u IPv6 53647 TCP devh1:9001 (LISTEN)
java 14301 huangys 11u IPv6 75326 TCP devh1:9001->devh2:1551 (ESTABLISHED)
从以上输出可以看出,9000, 9001 端口都在正常的监听中了。
10 停止 Hadoop
与启动对应,停止指令是:
huangys@devh1:~$ cd hadoop-deployed/hadoop-0.9.2
huangys@devh1:~/hadoop-deployed/hadoop-0.9.2$ bin/stop-all.sh
11 几个简单地 HDFS 操作
好了,终于可以开始尝试使用 Hadoop 了,运行 bin 目录下的 hadoop 指令可以打印出 Hadoop 支持的操作和用法。这里我就以 dfs 为例来介绍一下文件系统的操作。
建立目录:
$ hadoop dfs -mkdir testdir1
在 HDFS 中建立一个名为 testdir1 的目录。
复制文件:
$ hadoop dfs -put /home/huangys/soong.mp3 soong.mp3
把本地文件 soong.mp3 复制到 HDFS 的根目录下,文件名为 soong.mp3
查看现有文件:
$ hadoop dfs -ls