hadoop知识点收拾

hadoop知识点整理1. Hadoop 是什么?Hadoop 是一种使用 Java 编写的分布式计算平台。它吸收了 Google 文件系

hadoop知识点整理

1. Hadoop 是什么?

Hadoop 是一种使用 Java 编写的分布式计算平台。它吸收了 Google 文件系统和 MapReduce 等产品的特性。详情参见 HadoopMapReduce。

2. Hadoop 运行于什么平台?

1. Java 1.5.x 或更高版本(推荐使用 Sun 的实现版本);
2.

支持 Linux 与 Windows 操作系统。在 BSD、Mac OS/X 及 OpenSolaris 上也可工作。(对于 Windows,需要安装 Cygwin)。

2.1 在 Windows 上构建、测试 Hadoop

在 Windows 上构建的 Hadoop 可以在 Windows 命令行窗口(并非 cygwin)中运行。

需要在批处理文件或“系统-属性-高级-环境变量”中设置以下环境变量:

set ANT_HOME=c:\apache-ant-1.7.1
set JAVA_HOME=c:\jdk1.6.0.4
set PATH=%PATH%;%ANT_HOME%\bin

打开一个命令行窗口,切换到你的工作目录(此例中为 c:\workspace\hadoop),执行 ant 命令。例如我对运行 test-contrib 这个例子有兴趣,可以这样做:

ant -l build.log -Dtest.output=yes test-contrib

对于其它的工作,做法类似。我想记下这点,因为我花了点工夫尝试找出为什么 ant 构建工作无法在 cygwin 命令窗口中完成。如果你正在 Windows 上构建、测试 Hadoop,却没有找到这个问题的答案,也许我的回答能助你启程。

3. Hadoop 的可扩展性如何?

Hadoop 的性能已经在多达 2000 个节点的机群上得以验证。排序程序的性能在 900 个节点的机群上表现很好(在 900 个节点上对 9TB 数据进行排序消耗 1.8 小时)。我们使用以下非默认的参数对性能进行优化:

*

dfs.block.size = 134217728
*

dfs.namenode.handler.count = 40
*

mapred.reduce.parallel.copies = 20
*

mapred.child.java.opts = -Xmx512m
*

fs.inmemory.size.mb = 200
*

io.sort.factor = 100
*

io.sort.mb = 200
*

io.file.buffer.size = 131072

在 1400 个节点和 2000 个节点的机群上,排序程序的性能依然不错。1400 个节点排序 14TB 数据消耗 2.2 小时;2000 个节点排序 20TB 数据消耗 2.5 小时。与上面不同的参数是:

*

mapred.job.tracker.handler.count = 60
*

mapred.reduce.parallel.copies = 50
*

tasktracker.http.threads = 50
*

mapred.child.java.opts = -Xmx1024m

强烈推荐使用 JRE 1.6 或更高的版本。原因之一是它在处理大量连接时更加高效。

4. 必须使用 Java 编写应用程序吗?

不。有几种办法让非 Java 代码与 Hadoop 协同工作。

*

HadoopStreaming 允许用任何 shell 命令作为 map 或 reduce 函数。
*

libhdfs 是一种基于 JNI 的 C 语言版 API(仅用于 HDFS)。
*

Hadoop Pipes 是一种兼容 SWIG 的 C++ API (非 JNI),用于编写 MapReduce 作业。

5. 如何能帮助 Hadoop 变得更好?

如果你在使用 Hadoop 过程中遇到了问题,尔后找到了解决方法(或许是借助了邮件列表),希望你把从中得到的知识写到这个 wiki 上。

如果你对某些问题希望有更好的解决方案,并知道如何修改,建议你阅读 HowToContribute,提供patch,为 Hadoop 贡献一份力量。

6. HDFS. 如果为机群增加新的数据节点,HDFS 会将数据块移动到新近增加的节点中吗?这样可以平衡节点之间的磁盘空间使用。

不会。HDFS 不会自动地将数据块移动到新的节点。不过,新创建的文件的数据块有可能存储在新增加的节点上。

有几种途径可以手工平衡机群上的存储负载:

1. 选择磁盘上适当比例的一组文件,将它们复制到 HDFS 中新的位置。删除原有的文件副本,将新的副本重命名为原来的名字。
2. 一种更简单、不影响服务的方式:开启文件副本功能,等待传输趋于稳定,然后关闭文件副本功能。
3. 另一种平衡数据负载的方法:关闭存储已满的数据节点,等待它上面的数据块向其它节点做完复制,然后重新启用这个节点。此时系统中过多的副本会随机地从不同的节点删除,所以节点间的负载真正得到了平衡,而不仅仅是删除了当前节点上的副本。
4. 最后,你也可以使用 bin/start-balancer.sh 命令来执行一个平衡过程,该程序自动地在机群的节点之间移动数据块。

7. HDFS. 使用次名字节点的目的是什么?

“次名字节点”一词有点误导。次名字节点实际上无法起到名字节点的作用,因为数据节点不允许连接到它。当主名字节点失效时,次名字节点也不会取而代之。

引入次名字节点的唯一目的是实现周期性的检查点。次名字节点周期性地下载当前名字节点的映像和编辑日志文件,将它们合并为新的映像,上传回唯一的主名字节点。请参考用户手册。

如果名字节点失效,只需要在同一个物理节点上重新启动名字节点,无须关闭相应数据节点。如果原有节点已无法使用,就需要从其它某些地方复制最近一次映像。主名字节点失效之前,最近的映像可以从主名字节点找到,否则,就只能在次名字节点上寻找映像。后者是不包含编辑日志文件的检查点,名字空间最近的修改有可能就此丢失。在这种情况下,恢复之后也需要重新启动整个机群。

8. MR. 分布式缓存的用途是什么?

分布式缓存用于分发机群中 MapReduce 作业所需的大的只读文件。某个节点上作业的任何任务执行之前,Hadoop 框架会将所需的文件从其源 URL(hdfs 或 http)复制到该节点。这些文件为每个作业只复制一次,应用程序不应该修改文件内容。

9. MR. 我能在 Map 或 Reduce 任务中直接创建或写入 HDFS 上的文件吗?

可以。(显然,你需要这样做,因为你需要创建或写入文件,而不是想通过 OutputCollector 写输出文件)

警告:

<glossary>

${mapred.output.dir} 是作业的最终输出目录(JobConf.setOutputPath / JobConf.getOutputPath)。

${taskid} 是单个 task-attempt 的实际 ID(例如 task_200709221812_0001_m_000000_0),TIP 表示一系列 ${taskid}(例如 task_200709221812_0001_m_000000)。

</glossary>

当 speculative-execution 设置为 on 时,具有相同 TIP(同时运行)的两个实例在试图打开或写入 HDFS 上相同的文件(或路径)时可能会引发问题。因此,写者进程不仅要对每个 TIP 使用唯一的名字,而且必须给每个 task-attempt 设置唯一的名字(比如像 task_200709221812_0001_m_000000_0 这样完整的 taskid)。(显然,即使用户不直接通过 reduce 任务创建、写入文件,这样做也是必须的。)

为解决此问题,Hadoop 框架为每个 task-attempt 在 HDFS 上维护一个特定的 ${mapred.output.dir}/_${taskid} 子目录,保存 reduce 的 task-attempt 的输出。在 task-attempt 成功完成后,${mapred.output.dir}/_${taskid}(仅针对成功的 taskid)子目录下的文件会被移动到 ${mapred.output.dir} 目录。当然,Hadoop 框架会丢弃不成功的 task-attempt 的相应子目录。这个过程对应用程序来说是完全透明的。

写者进程可以利用这一特性。执行 reduce 任务时,在自己的子目录下创建本来需要放在 ${mapred.output.dir} 目录的临时文件,Hadoop 框架会自动将它们移出去——这样不需要为每个 task-attempt 手工指定唯一路径。

备注:在执行特定的 task-attempt 时,${mapred.output.dir} 的值事实上是 ${mapred.output.dir}/_{$taskid},而不是在 JobConf.setOutputPath 中设置的值。所以,充分利用这一特性,在 reduce 任务中尽管向 ${mapred.output.dir} 目录写入你所需要的 HDFS 文件吧!

对于 reducer=NONE(即 0 个 reduce )的作业的 map 任务,上述所有的讨论仍然成立。因为这种情况下 map 的输出将直接写入 HDFS。

10. MR. 如何使我的多个 map 任务工作于同一个完整的输入文件,而不允许框架切分输入文件?

作业的输入实际上是以 InputFormat(接口)/FileInputFormat(基类)指定的格式表示的。

为了达到此目的,我们需要“不可切分的” FileInputFormat 类,也就是说,建立一种让 MapReduce 框架不做切分处理的输入格式。为此,可以对特定的输入格式类实现 isSplittable 函数,让它返回 false。

例如 src/test/org/apache/hadoop/mapred/SortValidator.java 中的 org.apache.hadoop.mapred.SortValidator.RecordStatsChecker.NonSplitableSequenceFileInputFormat 就是这样。

除了实现 InputFormat 接口,提供带有返回 false 的 isSplitable(…) 函数,我们还需要同时实现 RecordReader 接口,返回输入文件的全部内容。(默认情况实现的是 LineRecordReader,它把文件切分为独立的行)

此外,另一种快捷的实现方式是把 mapred.min.split.size 设置为足够大的值。

11. 在 jobdetails.jsp 页面中为什么会看到残缺的图像?

在 Hadoop 0.15 中加入了 MapReduce 任务完成情况图表。其中的图像是用 SVG(Scalable Vector Graphics)格式的,SVG 本质上是嵌入在 HTML 内容中的 XML 文件。这些图像在 Ubuntu 和 MAC OS 上的 Firefox 2 中经过测试,显示正常。不过,如果使用其它浏览器,需要安装相应的插件以显示 SVG 图像。Adobe 的 SVG Viewer 可以在 http://www.adobe.com/svg/viewer/install/ 下载。

12. HDFS. 所有未复制的文件完成完全复制之前,名字节点是否一直处于安全模式?

不是。安全模式下禁止复制数据块。名字节点会待续等待,直到全部或大部分数据节点上报它们的数据块。

依据安全模式参数配置的不同,名字节点在安全模式下等待系统中指定比例的数据块完成最小复制(dfs.replication.min)。如果安全模式的阈值(dfs.safemode.threshold.pct)设置为 1,所有文件的所有块都应该完成最小复制。

最小复制并不意味着完全复制。有的副本有可能被忽略,名字节点需要离开安全模式来完成这些复制任务。

有关安全模式的更多信息,参考这里。

13. MR. 我发现每个 TaskTracker 最多并发生成 2 个 map 或 reduce 任务,应当如何增大数量?

通过 mapred.tasktracker.map.tasks.maximum 和 mapred.tasktracker.reduce.tasks.maximum 这两个参数配置 TaskTracker 并发生成 MapReduce 的数目。它们的默认值是 2,所有通常看到每个 TaskTracker 最多并发生成 2 个 map 和 2 个 reduce。

可以根据硬件条件,为每个 TaskTracker 精确地设置这些参数(即为强大的 TaskTracker 设置更大的参数值)。

14. MR. 以不同的用户身份提交的 MapReduce 作业不工作?

问题的原因是没有把 MapReduce 系统目录设置为一个固定的位置。默认的配置面向单个节点的系统,而不是面向“真正的”机群。可以使用以下配置:

<property>
<name>mapred.system.dir</name>
<value>/hadoop/mapred/system</value>
<description>The shared directory where MapReduce stores control files.
</description>
</property>

注意,上面的目录要在你的默认文件系统中,客户端和服务器机器都要有访问权限,通常放在 HDFS。

15. HDFS. 如何配置 Hadoop 节点使用多个卷?

数据节点可以在位于不同的本地磁盘驱动器中的多个目录下存储数据块。为设置多目录存储,可以把 dfs.data.dir 参数设置为由逗号分隔的路径名列表。数据节点会尽量在每个目录下保存等量的文件。

名字节点也支持在多个目录下存储名字空间镜像和编辑日志文件。通过 dfs.name.dir 参数可以设置目录。这些目录通常用于镜像和日志副本的存储,以便在其中一份失效时能够从其余的卷中恢复。

16. HDFS. 如果一个 Hadoop 客户端对某个文件或目录重命名,而另一个客户端正在写入这个文件或目录,会有什么情况发生?

自 Hadoop 0.15 起,文件一旦创建就出现在名字空间中了。如果一个客户端正在写一个文件,而另一个客户端对这个文件或其路径中的任何一级目录进行了重命名,原来的那个写者会在当前块写入完成或关闭文件时收到一个 IOException 异常。

17. HDFS. 我想通过同时移除一批节点的方式把一个大机群缩小,这项任务如何完成?

从一个大机群中移除一两个数据节点不会导致任何数据丢失,因为名字节点在检测到数据节点失效时,会从别处复制它们所保存的数据块。如果有大量节点移除或崩溃,数据丢失的概率就增大了。

Hadoop 提供清退(decommission)机制以便从机群中安全地移除一批已存在的数据节点。方法是把需要移除的节点写在排除名单文件中,并把排除名单的文件名作为 dfs.hosts.exclude 的参数值。排除名单文件需要在名字节点启动时就准备好,它的长度也可以为零。在这个文件中,需要写完整的主机名、IP 或 IP:port 这样的格式。

然后调用 shell 命令:

bin/hadoop dfsadmin -refreshNodes

强制名字节点重新读取排除名单文件,执行清退操作。

清退操作不会立即执行,因为有可能有大量数据块需要做复制,我们并不希望这项工作使得整个机群不堪重负。清退过程可以通过名字节点的 web 界面进行监控。在所有的块复制完成之前,节点处于“正在清退”状态;清退完成后转入“已清退”状态。已清退的节点随时可以从机群中移除。

随时可以通过编辑配置或修改排除名单文件,并重新执行 -refreshNodes 命令来终止清退过程。

18. 怎样的硬件配置对 Hadoop 最好?

简单地说,双 CPU 或双核 CPU、4-8GB ECC 内存的机器比较合适。不要使用桌面级计算机,应当选用性价比高的相对高端的商用机,它们的价格通常是产品级应用程序服务器的 1/2 到 2/3,成本通常在 2000-5000 美元。更详细的讨论参见 MachineScaling 页面。

19. 通配符在 FsShell 中工作不正常!

有时候你需要让 FsShell 中的命令对一个以上的文件进行操作。FsShell 提供了通配符来完成这类任务。*(星号)可以代替任意字符的集合。例如,要想列出自己账户下所有以 x 开头的文件,可以使用带有 * 通配符的 ls 命令:

bin/hadoop dfs -ls x*

有时,本地操作系统的通配符处理方式会导致异常的结果。为避免这个问题,可以使用单引号或双引号包围通配符表达式,这时通配符就应该能正确地工作了:

bin/hadoop dfs -ls ‘in*’

20. GridGain 与 Hadoop 相比如何?

GridGain 不支持数据密集型作业。详情参阅 HadoopVsGridGain。

21. HDFS. HDFS 中的多个文件可以使用不同的数据块大小吗?

可以。在创建文件时,HDFS 提供了指定数据块大小的 API。

参考 FileSystem.create(Path, overwrite, bufferSize, replication, blockSize, progress)

22. HDFS 是否以记录作为分块的边界?

不。HDFS 不提供面向记录的 API,因此不知道记录及其边界。

23. Map/Reduce 的 InputSplit 处理程序如何正确地处理记录边界?

InputSplit 的 RecordReader 负责查找记录的起止边界。对于 SequenceFile,每 2K 字节之间有 20 字节的同步(sync)标记来分隔记录。RecordReader 首先定位到 InputSplit 的开头,其中记录了文件、偏移量和长度。RecordReader找到InputSplit开头之后的第一个同步标记,然后持续处理记录,直到遇到文件结束处的首个同步标记。每个文件的首次切分立即进行,不用等到首个同步标记出现之后。通过这种方式,可以保证每条记录精确地被一个 map 程序处理。

对文本文件的处理与之类似,只不过用换行符代替同步标记。

24. HDFS. 两个客户端试图写入同一个 HDFS 文件时会发生什么?

HDFS 只支持独占的写入。
第一个客户端连接到名字节点,打开待写入的文件时,名字节点授予客户端一个租约,以便其写入这个文件。第二个客户端试图以写入方式打开相同的文件时,名字节点发现此文件的租约已经授予了其它客户端,就会拒绝第二个客户端的打开请求。

25. 如何将一个新的节点加入正在运行的 Hadoop 机群?如何只在一个节点上启动服务?

这同样适用于机器崩溃或重启等情况,这时你也需要把它们重新加入机群。这类情况下不需要关闭或重启整个机群。

首先,把新节点的 DNS 名字加入主节点的 conf/slaves 文件。

然后登录新的从节点,执行以下命令:

$ cd path/to/hadoop
$ bin/hadoop-daemon.sh start datanode
$ bin/hadoop-daemon.sh start tasktracker

26. 有什么简单的方法检查机群的工作状态?

有基于 web 的 JobTracker(MapReduce 主服务器)和 NameNode(HDFS 主服务器)界面,它们显示整个系统的工作状态。默认的访问位置是 http://job.tracker.addr:50030/ 和 http://name.node.addr:50070/。

JobTracker 状态页显示所有节点的状态,作业队列以及正在运行的作业和任务的状态。NameNode 状态页显示所有节点的状态、空闲空间大小等,提供基于 web 界面浏览 DFS 的功能。

此外,也可以通过命令查看一些基本的 HDFS 机群状态信息:

$ bin/hadoop dfsadmin -report

Translated by Jian Lin <lj at linjian.cn>.

Modified by hopesophite <hopesophite at gmail.com>