2.2 设置NameNode

在本节中,我们将一步一步对NameNode服务进行安装以及基本配置,其中包括高可用方案的构建。网络上许多指导和教程将NameNode高可用方案作为一项高级内容,而我们在最初就将重点放在NameNode高可用方案的设置上。原因是在Hadoop构建中NameNode扮演着重要的角色。从根本上说,NameNode是Hadoop集群中的一块短板。如果没有该项服务,用户就无法访问Hadoop分布式文件系统(HDFS)。
我们有多种方法对NameNode高可用方案进行设置。在CDH 4.1版本前,高可用方案可以通过共享存储安装实现。在本书中,主NameNode将文件系统元数据的变化写入位于共享网络存储的editlog文件中,备份NameNode将editlog文件中的变化写入到元数据快照的拷贝中。此外所有的DataNode会根据目前分块的位置更新这两种NameNode的信息,因此当主NameNode发生故障时,备份NameNode能够代替主NameNode进行工作。
在CDH 4之前,备份NameNode并不执行备份功能。它只是作为检查点进行工作。随着高可用方案的实现,备份NameNode才执行了高可用方案以及检查点功能。可将备份NameNode看做备份NameNode与备份节点的结合。
这种安装过程还有所欠缺。它要求能够快速访问的额外硬件。在CDH 4.1中发布了一种简易的NameNode安装方法,它依赖于分布式服务对两个数据节点进行同步并且无需依赖共享网络存储。这种安装方法称为Quorum Journal Manager,它引入了多种全新的组件,其中包含了两种NameNode:主节点和备份节点。这点与之前的安装类似,不同的是主NameNode将editlog文件写入到JournalNode节点集群,而不是共享网络文件中。JournalNode节点是CDH 4.1版本中新增的后台服务。JournalNode节点的工作原理是主NameNode将editlog文件的变化提交到一组JournalNode节点中,之后JournalNode节点将它们写入到本地磁盘中。当大部分JournalNode节点将文件保存在磁盘后即表示写入成功。这种方法就无需共享存储的支持,但是我们仍然需要保证editlog文件写入的稳定性以及没有单点故障的发生。JournalNode的一个巨大优势是它们的操作都是轻量级的,因此无需在单独的硬件上运行它们。
一种常见的做法是运行三个JournalNode节点(奇数个节点适合于进行仲裁)。其中的两个可以运行在和NameNode相同的服务器上,另一个则运行在JobTracker所在的服务器上。但这并不是硬性的要求,可以在集群中的任何服务器上运行JournalNode节点。在本书中我们选择这种方法进行安装。
备份NameNode从JournalNode节点集群获取editlog文件,然后将在文件系统的拷贝中进行相应的变化。备份NameNode还执行校验和功能,同时将已升级的fsimage文件传输到主NameNode上。除此之外,DataNode会向这两种节点发送有关分块分配的心跳信息。如果主NameNode发生故障,备份NameNode可以立刻取代它执行分布式文件系统操作。
为了使得整个跨节点协调正常工作,NameNode需要依赖ZooKeeper跟踪确认主要和热备份节点,以避免两个节点都作为主节点向JournalNode节点写入editlog文件。ZooKeeper是另一个Apache项目,同时也是CDH中的一部分。它提供了分布式协调服务,在多个不同节点需要分享状态、锁定数据或者其他数据信息时尤为实用。详细的信息请读者参见http://zookeeper.apache.org。NameNode高可用方案中的最新版本为ZooKeeper故障转移控制器(ZKFC)。ZKFC是运行在主要节点和热备份节点上的后台服务,它检查节点的健康以及运行状态,必要时向备份NameNode进行故障转移。在处理NameNode故障时,集群管理员有两种选择:
手动操作,从故障NameNode向备份节点进行故障转移。其中设置相对简单,但是集群管理员需要密切监视活动NameNode的健康状态并且在出现故障时快速进行故障转移响应。
自动操作,配置自动故障转移选项,依靠ZKFC监视活动NameNode的状态。在必要时ZKFC将对故障转移进行初始化并使用ZooKeeper集群作为状态同步点。
在本书中我们选择NameNode自动故障转移。
正如读者所看到的,在NameNode高可用方案的构建中有诸多灵活的部分。图2-1列出了所有涉及的组件以及它们之间的关系。

hadoop配置 主机名 hadoop配置namenode_hadoop配置 主机名

随后部分中的所有示例都运行在一个测试集群中,节点的设置和配置如下:nn1.hadoop.test.com、nn2.hadoop.test.com、jt1.hadoop.test.com。nn1和nn2分别为主要和热备份NameNode,jt1是JobTracker节点。现在我们不会对DataNode进行讨论,在本章随后的部分将对其进行讲解。

管理由多种设备组成的集群显然需要某种程度的自动化。在设置和配置集群时需要重复进行的一项任务是在不同设备间传递配置文件。Cloudera管理器能够帮助我们完成大部分的配置管理。还可以使用诸如Puppet、Chef或者Ansible这样的工具来完成任务。

下面我们开始安装nn1、nn2以及jt1中NameNode所需的包。由于要在JobTracker服务器上运行JournalNode节点,因此我们需要安装分布式文件系统包。

除了特别指定外,所有的指令都应该以root用户身份运行。

读者可以在nn1、nn2以及jt1服务器上输入yum指令:

hadoop配置 主机名 hadoop配置namenode_操作系统_02

这条指令将安装多个独立的包,下面我们对这些包进行简单的介绍:
bigtop-jsvc以及bigtop-utils:这两个包来自Apache Bigtop项目(http://bigtop.apache.org)。该项目旨在于帮助简化开发和打包Hadoop组建的过程。它负责正确的环境设置、确认JAVA_HOME在不同的系统中正确地得到了识别等等。通常来说,不必对它们过于关心,但是随着Bigtop的引入,某些配置文件的位置和用途会发生变化,因此用户还是要知道它们的存在。
Hadoop:其中包括核心hadoop组件、配置文件以及共享库。它会在所有集群节点上进行安装。
Hadoop-hdfs:提供分布式文件系统、NameNode、JournalNode节点、DataNode以及内置网页服务器等组件的配置文件。
ZooKeeper:我们在之前已经讨论过了ZooKeeper在NameNode高可用方案中的作用,同样它也应用于HBase的纵向存储中。
需要注意的是,在分布式文件系统包安装后,CDH创建一个名为hdfs的操作系统用户。所有的后台进程都应该在该用户下执行。

2.2.1 JournalNode节点、 ZooKeeper以及故障转移控制器

下面我们在所有这三种服务器上安装JournalNode安装包:

hadoop配置 主机名 hadoop配置namenode_运维_03

我们已经将ZooKeeper作为NameNode依赖项的成员进行了安装,但是同样我们还需要安装开启/关闭ZooKeeper服务器的脚本。请在nn1、nn2以及jt1上运行下列命令:

hadoop配置 主机名 hadoop配置namenode_java_04

最后需要安装故障转移控制器。该后台程序只需要运行在主要和备份NameNode上,因此我们在nn1和nn2上输入下列指令进行安装:

hadoop配置 主机名 hadoop配置namenode_运维_05

在配置NameNode以及其他组件前,需要确认ZooKeeper集群的启动和运行状态。在本例中的nn1、nn2以及jt1上我们一共运行了三个ZooKeeper节点。配置文件zoo.cfg的位置在/etc/zookeeper/conf/,设置文件如下所示:

hadoop配置 主机名 hadoop配置namenode_java_06

示例中的配置文件采用了默认设置,如果需要进行高级设定请自行进行修改。根据设置,可能需要调整dataDir选项。在上面的示例中我们需要加入最后三行代码。这些代码用于设置ZooKeeper集群。在每个server关键字之后是服务器的标识,2888和3888分别是用于连接ZooKeeper以及选择新主节点的端口。现在我们不必过于在意这些细节,但是需要注意的是应该再次确认这些端口在ZooKeeper节点上是否开启,同时客户端端口2181能够为所有需要运行ZooKeeper的服务器(比如HBase节点)所访问。

在升级完配置文件后(请不要忘记在所有节点上进行升级!),需要运行下面的命令来创建和初始化数据目录:

hadoop配置 主机名 hadoop配置namenode_java_07

我们已经将ZooKeeper作为NameNode依赖项的成员进行了安装,但是同样还需要安装开启/关闭ZooKeeper服务器的脚本。

请在nn1、nn2以及jt1上运行下列命令:

hadoop配置 主机名 hadoop配置namenode_java_08

该命令需要在nn1、nn2以及jt1上执行。它会在所有这三个节点的/var/lib/zookeeper/中创建一个名为myid的文件(具体位置取决于dataDir选项)。该文件包含了ZooKeeper节点的唯一服务器标识,这也是我们在myid选项中所提供的。ZooKeeper后台程序根据标识确认集群中的服务器身份,因此读者需要在每台服务器的myid中设置不同的值。

要开启ZooKeeper服务,请在所有这三个节点上运行下列命令:

hadoop配置 主机名 hadoop配置namenode_操作系统_09

请确认ZooKeeper默认日志文件/var/log/zookeeper/zookeeper.log中的内容。有时即使在失败的情况下,zookeeper-server 的start命令仍然会返回成功,确认服务器开启的唯一方法是对日志文件进行检查。
下面我们开始进行NameNode的配置。

2.2.2Hadoop配置文件

在详细讲解NameNode后台的配置前,我们首先对Hadoop配置文件进行简单的介绍。在Hadoop集群中有多种不同的后台程序,它们都拥有自己的配置文件。实际上核心Hadoop服务所采用的配置文件并不多。读者可能最初会对此有所困惑,因为不同作用的选项都混杂在多个文件中。

对于核心Hadoop组件主要有三个配置文件:core-site.xml、hdfs-site.xml以及mapred-site.xml。core-site.xml文件包含了所有针对集群服务器的配置选项。hdfs-site.xml和mapred-site.xml分别是集群中分布式文件系统以及MapReduce的配置文件。除此之外还有其他的配置文件控制着集群的不同功能,随后我们进行简单的讲解。CDH将这些配置文件放置在/etc/hadoop/conf目录中,同时它也是alternatives目录的符号连接(symbolic link)。CDH使用Linux Alernatives项目来维护各种不同版本的配置以及其他文件。我们无需关注具体的实现细节,因为它不会对我们构建集群的步骤产生实际影响。

可以在http://www.linuxalt.com上获取更多有关Linux Alternavies项目的信息。

下面我们来查看在NameNode服务器nn1中的/etc/hadoop/conf目录下有哪些文件:

hadoop配置 主机名 hadoop配置namenode_运维_10

可以看到core-site.xml以及hdfs-site.xml文件,但是却没有发现mapred-site.xml。其中的原因是我们在服务器上还未安装任何与MapReduce相关的包(比如JobTrakcer或者TaskTracker)。

hadoop-metrics.properties和hadoop-metrics2.properties文件对Hadoop内部参数(metrics)的显示方式进行控制。它对于配置集群监视尤为重要,我们会在第5章中对这些文件进行深入讨论。

log4j.properties配置文件用于指定Hadoop日志功能的具体细节。它具有极高的灵活性,允许用户指定保留和归档选项、日志详细程度甚至是日志格式。Hadoop默认选项已经能够满足我们的要求,因此我们不会对所有可用的选项进行讨论,如果默认选项无法满足读者的要求,请查阅Log4j以及Hadoop文档获取更多的信息。

Slaves是一个可选文件,在默认情况下为空。可以向其中写入DataNodes列表。通过该列表,脚本(比如start-all.sh)可以启动集群中所有的后台服务。相比这种方法,我们推荐读者在CDH中使用服务命令启动服务。

ssl-client.xml.example和ssl-server.xml.example为示例配置文件,它可以用于在MapReduce中创建加密的整理阶段(shuffle phase)。

除了/etc/hadoop/conf目录外,我们还有一个需要注意的地方。随着Bigtop项目的引入,一些设定都移动到了位于/etc/default目录下的命令脚本中。这些脚本用于设置不同服务采用的环境变量。下面是默认hadoop-hdfs-namenode脚本的示例(为了节省篇幅,我们没有列出头文件):

hadoop配置 主机名 hadoop配置namenode_高可用_11

可见,该文件制定了PID以及日志文件位置、用于运行NameNode后台服务的操作系统用户以及其他选项。在大部分情况下,当完成CDH包安装后无需对默认路径进行调整。唯一的非默认选项是HADOOP_NAMENODE_OPTS。该变量指定了用于启动NameNode后台服务的JVM选项列表。在本例中当NameNode JVM启动时,堆可用的最大内存为10GB。需要根据在分布式文件系统中的文件/分块数量对设置进行调整。更多有关NameNode内存使用要求的细节请参见第1章。

2.2.3 NameNode高可用方案配置

我们通过在core-site.xml文件中加入多个选项对NameNode高可用方案进行配置。下面是该步骤中的文件结构。不熟悉XML结构的读者可以从该文件获得一些初步的概念。由于篇幅原因,我们省略了头部的注释:

hadoop配置 主机名 hadoop配置namenode_运维_12


hadoop配置 主机名 hadoop配置namenode_运维_13

配置文件的格式相当清晰;变量的两边是标签,每一个变量都有名称和设定值。

在该步骤中我们只有两个需要加入的变量。fs.default.name是NameNode集群的逻辑名称(logical name)。hdfs://sample-cluster/专用于高可用方案的设置。它是NameNode集群的逻辑名称。我们将在hdfs-site.xml文件中定义组成集群的服务器。在非高可用方案配置设置中,由于集群中只有一个NameNode,该变量将会分配到NameNode的主机以及端口上。

ha.zookeeper.quorum变量定义了ZooKeeper服务器的位置以及端口。其他服务也可以使用ZooKeeper集群(比如HBase),因此我们在core-site.xml中进行定义。

下一步骤是配置hdfs-site.xml文件,加入所有分布式文件系统特定的参数。为了节省篇幅,在此我们只列出和标签,而省略标签。

hadoop配置 主机名 hadoop配置namenode_高可用_14

NameNode将使用dfs.name.dir变量指定的地点存储分布式文件系统元数据的永久快照。这也是fsimage文件的存储地点。正如之前所讨论的,该目录存在的分卷需要有磁盘阵列的支持。失去该分卷意味着完全丢失NameNode。示例中使用的路径为/dfs/nn,读者可以根据需要自行选择。实际上可以在dfs.name.dir中指定多个路径(中间用分号进行分隔)。NameNode将在每个指定的目录中对元数据文件进行快照。如果有可用的共享网络存储,那么可以将它作为分布式文件系统元数据的存储点之一,以此增加额外的离线备份。

hadoop配置 主机名 hadoop配置namenode_运维_15

dfs.nameservices变量指定了NameNode集群的逻辑名称,应该根据实际情况进行修改(比如prod-cluster或者stage-cluster)。dfs.nameservices必须和core-site.xml文件中的fs.default.name变量值相匹配。

hadoop配置 主机名 hadoop配置namenode_运维_16

我们对组成高可用方案的NameNode进行了配置。但这些都只是逻辑名称,而不是真正的服务器主机名或者IP地址。这些逻辑名称会在其他配置变量中得到引用。

hadoop配置 主机名 hadoop配置namenode_运维_17

这组变量将类似nn1和nn2这样的逻辑名称映射为实际的主机名和端口值。默认情况下,NameNode使用8020端口与客户端进行通信。请确认该端口对于集群端口保持开放状态。

hadoop配置 主机名 hadoop配置namenode_高可用_18

每个NameNode后台服务都运行有一个内置的HTTP服务器,NameNode网页接口通过它向外界显示分布式文件系统的指标以及状态信息。除此之外,备份NameNode使用HTTP调用定时从主服务器上复制fsimage文件,执行检查点操作,随后进行反馈。

hadoop配置 主机名 hadoop配置namenode_java_19

dfs.namenode.shared.edits.dir变量指定JournalNode集群的设置。在我们的配置中,nn1、nn2和nn3上总共运行有三个JournalNode节点。主节点和备份节点都通过该变量确认与哪台主机进行通信来发送或者接收editlog文件的新变化。

hadoop配置 主机名 hadoop配置namenode_java_20

JournalNode节点需要保存通过活动NameNode向它们传送的editlog文件变化。dfs.journalnode.edits.dir变量指定在本地文件系统中editlog文件变化的存储位置。请注意该路径必须存在于所有的JournalNode节点上,并且所有目录的所有者都应该设置为hdfs:hdfs(用户和群组)。

hadoop配置 主机名 hadoop配置namenode_hadoop配置 主机名_21

在高可用方案设置中,访问分布式文件系统的客户端需要确认用于联系请求的NameNode。dfs.client.failover.proxy.provider.sample-cluster变量指定Java类名称,客户端通过它确认活动NameNode。

目前可用的变量只有ConfiguredFailoverProxyProvider。

hadoop配置 主机名 hadoop配置namenode_高可用_22

dfs.ha.automatic-failover.enabled变量表示NameNode集群使用手动或者自动故障转移。

hadoop配置 主机名 hadoop配置namenode_高可用_23

在集群设置中协调故障转移是一项复杂的任务,其中涉及诸多繁琐的步骤。最为普遍的问题是“裂脑”(split-brain)案例,它不仅局限于Hadoop集群中,同时也影响所有的分布式系统。裂脑的含义是两个NameNode都准备进行工作并且开始向editlog文件写入变化。为了防止这种问题发生,高可用方案配置维护了一个名为ZooKeeper的项目,明确了活动的NameNode并且JournalNode节点只接受节点的写入。要完全避免两个NameNode同时进行工作,我们可以在故障转移中使用一种称为隔离(fencing)的技术,它的概念是在向备份节点传输活动状态前关闭活动NameNode。

目前有两种隔离技术:sshfence和shell. Sshfence。它们都要求以开启NameNode后台服务的用户身份(默认为hdfs)在活动NameNode与备份节点间进行无密码ssh访问。隔离进程会检查是否有用户在NameNode端口上使用nc命令进行监听,如果该端口处于占用状态,它会尝试关闭NameNode进程。dfs.ha.fencing.methods的另一个选项是命令解释器。它将执行特定的脚本实现隔离。请牢记当隔离失效时,故障转移同样也会失去作用。在本例中我们指定了两个选项,第二项通常都会返回成功。它是在主NameNode和ssh故障并且故障转移无法执行时的变通方案。为了避免这种问题,第二个选项必须要启动故障转移,正如之前所提到的,即使没有隔离我们的设置也应该是安全的。为了实现这一点我们指定了两种隔离方法,ZKFC会按照顺序进行启动:当一种方法失效时会采用第二种方法。在本例中,第二个选项通常都会返回成功,即使运行有主NameNode的服务器无法通过ssh进行访问,故障转移也会进行初始化。

hadoop配置 主机名 hadoop配置namenode_java_24

在NameNode高可用方案中最后需要配置的选项是sshfence使用的ssh密钥。请确认将该文件的所属用户设置为hdfs。我们需要为主名称节点和次名称节点分别生成一个密钥。我们建议读者以hdfs用户的身份分别测试与两者之间的ssh访问是否工作良好。

高可用方案设置中的hdfs-site.xml文件已经设置完毕。请不要忘记在集群中的所有节点上对配置文件进行同步。下面我们要做的是启动JournalNode节点,请以root用户在nn1、nn2和jt1上执行该条命令:

hadoop配置 主机名 hadoop配置namenode_java_25

在CDH中,建议读者使用服务命令,而不是直接调用/etc/init.d/目录内的脚本,以此保证在后台服务开启之前所有的环境变量都设置正确。请定期在日志文件中检查后台服务。
现在我们开始对分布式文件系统进行格式化。请在nn1上运行下列命令:

这条命令是对NameNode的初始化设置,因此我们无需担心会对任何分布式文件系统元数据产生影响,但是需要注意的是它会删除之前所有的元数据入口。在nn1上运行格式化命令并没有特别严格的要求,但是为了操作便捷,我们假设希望nn1变为活动NameNode。格式化指令同样会对JournalNode节点上的存储进行格式化。

下面我们要做的是在ZooKeeper中为高可用方法集群创建入口并且启动第一个NameNode和ZKFC。在本例中,我们在nn1上执行下列命令:

hadoop配置 主机名 hadoop配置namenode_运维_26

请检查ZKFC日志文件(默认位置为/var/log/hadoop-hdfs/),确认nn1已经成为活动NameNode:

为了激活备份NameNode,我们需要执行一种称为自举(bootstrapping)的操作。请在nn2上执行下列命令:

hadoop配置 主机名 hadoop配置namenode_高可用_27

该条指令从活动NameNode传输当前文件系统状态并且将备份NameNode与JournalNodes Quorum进行同步。

现在我们准备在nn2上启动NameNode和ZKFC的后台服务。使用的命令与nn1上的相同。请检查ZKFC日志文件确认nn2成功获取了备份NameNode的身份。读者应该在日志文件的末尾看到下列信息:

hadoop配置 主机名 hadoop配置namenode_hadoop配置 主机名_28

这是配置NameNode高可用方案的最后一步。我们建议读者确认自动故障转移配置是否正确,当主NameNode中断时它是否工作正常。在集群构建过程中测试故障转移比在实际阶段中更为简易和安全并且不会导致集群中断。读者可以进行一个简单的测试:关闭主NameNode的后台服务,确认备份NameNode是否接替了它的位置。之后恢复主NameNode并确认它是否替代了备份NameNode。
读者可以使用下列命令获取nn1中NameNode的当前状态:
sudo -u hdfs hdfs haadmin -getServiceState nn1 hdfs haadmin命令同样可以用于在手动故障转移中进行初始化。
现在我们已经配置好了能够正常运行的NameNode高可用方案。

2.2.4 JobTracker配置

同NameNode类似,JobTracker在MapReduce框架中也起着主导作用:从集群中的TaskTracker获取心跳信息、维护有关集群当前能力的信息并且负责调度、分配以及跟踪用户指定作业的进度。在大型集群中有许多要完成的工作,因此JobTracker会非常繁忙。同NameNode不同,JobTracker不需要维护太多有关运行作业的状态信息,同时作业日志对于永久存储的要求是最小的。

长久以来,同NameNode类似,JobTracker是Hadoop集群中的一块短板。当JobTracker进程故障时,所有正在运行或者已经分配的作业都会失败并且重启。在CDH发布后,用户需要自行监控作业状态并且在JobTracker故障时重新进行分配。在CDH 4.1中作出了针对高可用方面的尝试并且在JobTracker中加入了作业持久化(job persistence)特性。JobTracker可以自动恢复在崩溃或者重启时运行的所有作业。在CDH 4.2中引入了JobTracker高可用方案构建,它允许用户配置活动以及备份JobTracker,在活动JobTracker故障时自动进行故障转移。在配置JobTracker高可用方案时读者需要注意的是所有在故障转移时运行的作业都会在备份JobTracker上重新执行。JobTracker高可用方案使用的组件同NameNode高可用方案中类似。它使用ZooKeeper存储有关当前活动节点的信息并且依靠ZKFC后台服务监控JobTracker的健康状态以及执行自动故障转移。JobTracker会通过分布式文件系统中的文件分享作业状态信息,因此无需任何额外的存储集群(比如JournalNode)。

在本例中我们不会采用JobTracker高可用方案,但是会对作业状态信息持久化进行配置。我们这么做有诸多理由。首先JobTracker高可用方案的重要性比NameNode高可用方案低。后台服务进程的重启或者未知的服务器重启都是能够容忍的,在启动时JobTracker会自动重启作业。在服务器完全故障时,我们也能轻易构建一个新的JobTracker,因为JobTracker快速投入运作并不需要任何之前的状态信息。因此当后台服务崩溃或者重启时,JobTracker高可用方案并没有起到太大的作用,当时它能缩短节点严重故障的恢复时间。读者可以根据运行作业的服务级别协议(SLA)来确定JobTracker在集群中所处的重要性。我们在此对JobTracker高可用方案不进行详细的第二个理由是它在许多方面都与NameNode高可用方案类似:读者需要为JobTracker集群配置一个逻辑名称,在配置文件中对加入的服务器进行描述,安装ZKFC,等等。

读者可以根据CDH高可用方案指导快速地配置JobTracker高可用方案,网址为:http://www.cloudera.com/content/clouderacontent/cloudera-docs/CDH4/latest/CDH4-High-Availability-Guide/cdh4hag_topic_3.html

要安装JobTracker包,请在对应服务器上运行下列命令。在本例中,JobTracker的主机名为jt1.hadoop.test.com:

hadoop配置 主机名 hadoop配置namenode_高可用_29

该命令将hadoop-0.20-mapreduce作为独立的包进行安装,实际上其中已经包含了所有相关的. jar以及其他文件。JobTracker包只提供了默认文件和一个服务器启动脚本。因此现在读者应该了解文件的打包形式。

MapReduce指定的参数都存储在/etc/hadoop/conf/mapred-site.xml文件中,JobTracker和TaskTracker都会使用到该文件。奇怪的是JobTracker包并没有提供框架配置文件,所以需要手工进行创建。

我们首先要配置的是JobTracker的主机名和端口。TaskTracker会根据该参数定位主节点的位置:

hadoop配置 主机名 hadoop配置namenode_运维_30

正如之前所提到的,JobTracker对于本地磁盘的空间要求是最小的。除了标准的配置文件外,JobTracker同样为所有已分配的用户作业以及已完成作业的历史信息存储了配置选项。该日志文件在标准Hadoop的日志目录下,在CDH中的位置是/var/log/ hadoop-0.20-mapreduce/。此外JobTracker同样需要在本地磁盘上存储某些系统信息。这些数据并不十分重要并且通常不会占据太多的磁盘空间。下面的变量指定了本地目录的位置:

hadoop配置 主机名 hadoop配置namenode_java_31

mapred.local.dir目录应该隶属于mapred用户以及群组,它是CDH在包安装过程中所创建的用户。

MapReduce作业需要运行在大量的设备上,因此有必要传输作业共享文件以及作业配置文件、jar文件等。JobTracker使用分布式文件系统对这些文件进行存储。集群中的所有TaskTracker能够通过它轻易地访问这些共享文件。

下面的变量指定了共享目录的位置:

hadoop配置 主机名 hadoop配置namenode_运维_32

mapred-site.xml文件中的路径并没有明确指向本地文件系统或者表明正在使用分布式文件系统,因此读者有必要记住相对应的变量。

MapReduce同样将某些有关正在运行以及已完成作业的信息写入分布式文件系统,进行分配的用户能够轻易地进行访问。为了实现这点,下面的变量需要指向root用户目录,在分布式文件系统中通常为/user:

hadoop配置 主机名 hadoop配置namenode_操作系统_33

下面一组变量指定了作业状态信息在分布式文件系统中的存储方式。之前JobTracker都将作业状态信息存储在内存中,在后台服务重启时,MapReduce客户端可能无法获取已分配作业的状态。为了解决这一问题引入了Job Status Store,本质上它是分布式文件系统中的一个文件夹。为了激活Job Status Store,读者需要打开下列变量:

hadoop配置 主机名 hadoop配置namenode_高可用_34

默认情况下,作业状态信息将会写入分布式文件系统中的/jobtracker/jobsInfo目录下。读者可以通过mapred.job.tracker.persist.jobstatus.dir变量进行控制。在本例中我们将采用默认设置,因此需要在分布式文件系统中创建这些文件夹:

hadoop配置 主机名 hadoop配置namenode_hadoop配置 主机名_35

下一个变量允许在JobTracker重启或者崩溃时正在运行的作业自行恢复。JobTracker从分布式文件系统中读取作业状态并进行重启。虽然该选项增加了稳定性,同时在需要人机交互的情况下能更快地恢复失败的作业,但是应该自行决定是否在集群中使用该选项。作业自动重启可能会带来许多潜在的问题。首先某些客户端可能希望在失败时自行重启作业,这样就会导致相同的作业被提交多次。在多用户情况下很难硬性规定作业提交准则。

另一个潜在问题是JobTracker崩溃的原因可能是正在运行的作业,在没有查明导致崩溃原因前就重启JobTracker并不是最佳的方案。如果读者对于集群中的作业能够进行良好的控制,或者对于作业完成有着严格的服务级别协议,那么打开自动作业重启选项会有一定的效果。

hadoop配置 主机名 hadoop配置namenode_操作系统_36

读者同样可以通过设定下列选项控制作业状态信息在分布式文件系统中的保存时间:

hadoop配置 主机名 hadoop配置namenode_高可用_37

配置作业调度器

JobTracker的主要作用之一是对用户作业进行调度并将它们提交给TaskTracker。在实际应用的Hadoop集群中同时会运行有多个作业。在大部分情况下不同的用户会提交多个作业,因此一个实际的问题是如何为不同等级的作业分配集群资源。从MapReduce框架的角度来看,集群的能力是由可用的map和reduce空位组成的。这些参数是在TaskTracker配置过程中进行定义的,对于每个工作节点来说都是一个固定的数字。TaskTracker向JobTrakcer发送信息表示某个特定服务器当前占用map和reduce空位的数量,JobTracker调度器据此来确认如何最高效地使用这些空位。

JobTracker可以使用多种算法对并行作业进行调度。这些算法是以插件类实现的,因此需要在mapred-site.xml文件中指定。管理员应该针对特定的工作负载选择最佳的调度器,它的标识为mapred.jobtracker.taskScheduler变量(特定调度器的Java类名)。目前有多种调度器供我们选择:JobQueueTaskSchedule、 FairScheduler、以及 CapacityTaskScheduler。实现高效的集群利用率是每位Hadoop管理员的首要任务,因此我们有必要对这些调度器之间的区别进行简要讲解。

JobQueueTaskScheduler

默认采用的原始调度器是JobQueueTaskScheduler或者先入先出(FIFO)调度器。该调度器为提交的作业生成一个队列,第一个作业将占据集群中所有空闲的空位。在第一个作业完成之前,所有其他作业都必须在队列中等待。这样会产生较长的等待时间,如果小型作业位于大型作业之后也会如此。在ETL过程需要和短时间用户请求并存的环境下这种方法并不是特别理想。先入先出调度器允许为提交的作业分配不同的优先级,但是每个优先级都有各自的队列,比起较低优先级队列中的作业,高优先级队列中的作业会更快地提交到TaskTracker中。这种调度器没有合理资源管理器这样的重要特性,因此并不适用于大部分实际应用场合。

FairScheduler

第二个可供我们选择的是FairScheduler。它的主要理念是在一段时间内将集群资源平等分配给不同的作业。作业会分配在池中,每个池都会获取等量的集群空位。默认设置下FairScheduler会为每个用户都创建一个池,但是用户也可以进行其他选择。如果只有一个作业正在运行,那么它可以占用所有的可用空位,同时释放的空位也可以重新用于其他作业(某些map任务的完成速度要比其他快)。读者也可以为较为重要的池设定最低的集群资源量,例如在完成关键的生产作业时。读者同样可以配置调度器关闭运行中的任务来为高级别作业保留充足的能力。FairScheduler在多用户环境中提供了更好的集群使用策略并且有更高级的配置选项。在本书中我们将在集群中采用该调度器。

CapacityTaskScheduler

最后一个可选择的调度器是CapacityTaskScheduler。它的设计理念和FairScheduler类似,但还是存在着一些区别。在CapacityTaskScheduler中作业被分配到一组预先定义的队列中,同时每个队列都会根据管理员的设置获取一定的集群资源。即使没有运行的作业,分配到队列的资源也不会得到丢弃。在队列中作业以先入先出的方式进行调度,也就是说用户提交的作业在队列中是连续的。CapacityTaskScheduler的一个有趣特性是它可以解读来自TaskTracker的有关系统资源使用的信息(比如内存)并且根据服务器的使用情况进行调度,而不仅仅是以可用集群空位为参考。在实际中它有着广泛的应用并且对于静态负载有着有良好的表现。

正如之前所提到的,在本例中我们将使用FairScheduler。对于为每个用户创建的任务池我们将保持基本设定并且所有的池都不会配置最低的资源共享要求。首先我们要指定想要采用的调度器:

hadoop配置 主机名 hadoop配置namenode_高可用_38

下面我们配置创建池的数量。在本例中每个提交作业的用户都会获取一个单独的池:

hadoop配置 主机名 hadoop配置namenode_操作系统_39

mapred.fairscheduler.poolnameproperty变量的值可以为任何属性。例如根据操作系统用户组创建的池,读者可以将它的值设置为group.name。

管理员可以在一个名为allocations的单独XML文件中对池进行预先定义。池的其他额外属性(比如最小共享空位的数量)都可以在该文件中指定。在本例中我们允许FairScheduler为每个提交作业的用户动态地创建池,除此之外不配置任何其他选项。为了实现这一点,我们在/etc/hadoop/conf/下创建一个新文件,并且将它命名为fair-scheduler.xml,它是一个空的XML文件,其中只有下面一个部分:

hadoop配置 主机名 hadoop配置namenode_操作系统_40

现在我们需要在mapred-site.xml中指定该文件的位置:

hadoop配置 主机名 hadoop配置namenode_运维_41

由于我们希望FairScheduler动态地创建池,因此我们无需对其进行声明。我们将mapred.fairscheduler.allow.undeclared.pools变量设定为真:

hadoop配置 主机名 hadoop配置namenode_高可用_42

如果读者想要更好地控制池的功能,请参阅调度器文档中的可用选项,它的网址为:http://hadoop.apache.org/docs/r1.2.1/fair_scheduler.html

以上是所有现阶段我们需要配置的JobTracker选项。读者现在可以使用服务命令开启后台服务:

hadoop配置 主机名 hadoop配置namenode_高可用_43

2.2.5DataNode配置

我们已经完成了对Hadoop主服务、NameNode以及JobTracker的配置,现在我们开始对处理大部分数据的DataNode进行配置。

DataNode是Hadoop的工作节点,它们也是集群服务器组的主要组成部分。DataNode扮演着两种角色:作为DataNode分布式文件系统后台服务以及MapReduce框架中TaskTracker的宿主。因此MapReduce作业可以使用本地数据,在必要时避免了费时的网络传输。

下面我们开始讲解DataNode配置的细节。读者可以在集群中的所有DataNode上重复这些步骤。在下面的示例中,在集群中加入了一个新的主机:dn1.hadoop.test.com。在NameNode安装时所做的假设同样适用于该部分。对本地磁盘分卷进行格式化以及挂接、配置操作系统,对于Hadoop端口不要设置严格的防火墙限制,同时对CDH存储库进行设置。

要使用CDH包安装DataNode,请使用下列yum命令:

hadoop配置 主机名 hadoop配置namenode_操作系统_44

该命令将安装Hadoop核心、Hadoop分布式文件系统以及对应的DataNode包。实际上hadoop-hdfs-datanode包中只包含了默认的配置文件以及服务启动脚本。所有的核心组件都是作为Hadoop以及hadoop-hdfs包进行安装的。

现在我们需要在hdfs-site.xml中加入多个DataNode特定选项。其中有些选项是DataNode独占使用的,有些则是由不同的分布式文件系统客户端使用,为了保持稳定性我们对hdfs-site.xml文件进行编辑,该文件是在完成NameNode配置时生成的并且我们将它传输到集群中的所有节点上。

首先我们需要指定DataNode使用哪个分卷存储实际的分布式文件系统数据。通过对dfs.data.dir变量进行设置来完成该项内容:

hadoop配置 主机名 hadoop配置namenode_操作系统_45

该变量是每个DataNode上的分卷所组成的列表,它们之间用逗号进行分隔。由于通常在DataNode上不会配置磁盘阵列,因此这些分卷实际上是独立的磁盘。DataNode采用轮转的方式使用这些磁盘来存储分布式文件系统数据。

我们在hdfs-site.xml文件中加入的下一个变量是dfs.block.size。该变量设置了文件在分布式文件系统中存储的默认分块大小(单位是字节)。通过为某个文件指定分块大小读者可以对此设定进行修改。默认情况下,Hadoop使用的分块大小为64MB,当前在大部分实际应用中通常都采用128MB的分块大小。在使用特定的客户端选项向分布式文件系统进行上传时,读者可以针对不同的文件指定对应的分块大小。如果没有设定的选项,Hadoop将采用配置文件中的dfs.block.size变量。在本书的集群示例中,我们将分块大小设定为128MB。

hadoop配置 主机名 hadoop配置namenode_hadoop配置 主机名_46

另一个控制分布式文件系统行为的核心变量是dfs.replication。该变量指定了每个文件分块复制的次数。在大部分情况下默认的设定为3,这是在集群扩展性以及集群可用资源总和之间进行平衡的选择。和分块大小类似,分布式文件系统客户端也可以针对单个文件指定复制因子。虽然我们没有必要调整该变量,但还是建议将它加入配置文件用于了解使用的设定:

hadoop配置 主机名 hadoop配置namenode_hadoop配置 主机名_47

除此之外还有两个和dfs.replication相关的变量,dfs.replication.max表示单个分块在集群中最大的复制次数。默认情况下为512。如果读者对使用集群的客户端抱有疑虑或者不希望设置文件在文件系统中复制512次,那么请将该参数设置为较低的数值。另一个相关的参数是dfs.namenode.replication.min,它控制在分块写入完毕时,某个特定分块最小的复制次数。该变量的默认设置为1,这表示至少有一个DataNode存储了分块并且写入操作返回成功。这种默认的情况表示某些文件的副本将会少于dfs.replication设定的要求值。当集群中发生网络故障或者有部分DataNode不可能访问时会发生这种情况。

Hadoop会定期扫描文件系统搜寻正在复制中的分块并且根据系统的默认设定对它们进行复制。dfs.namenode.replication.min参数的默认值1是一个比较合理的设定,因此我们不会对其进行修改,但是读者也可能会设定该参数,尤其是在对数据弹性有着严格要求时。

我们在DataNode配置中需要指定的下一个参数是dfs.du.reserve。该变量的名称含义并不清晰,但是它的作用是Hadoop可以为DataNode预留部分的磁盘空间。这么要求的原因是MapReduce框架需要本地分卷来存储临时数据。作业的map和reduce步骤都会产生临时文件,因此在MapReduce临时目录下留有足够的空间非常重要。常见的作法是使用与分布式文件系统相同的本地磁盘,用来在不同的磁盘上分割输入输出负载,但是这就表示需要预留部分的空间以避免分布式文件系统使用了所有的磁盘空间,导致MapReduce作业由于无法传输临时数据而启动失败。除非读者计划在每台服务器上为MapReduce临时目录指定专门的硬盘,否则我们建议在每块磁盘上预留总容量的10%。要在每块磁盘上预留10GB的空间,我们将进行下列设定:

hadoop配置 主机名 hadoop配置namenode_操作系统_48

在开启DataNode后台服务前,我们有必要再次检查JVM堆设定。默认情况下DataNode初始拥有1GB的堆内存。在大部分情况下该设定都能满足要求,由于DataNode主要工作是大规模的顺序读取和写入,如果读者需要对此进行调整,请设置/etc/default/hadoop-hdfs-datanode文件中的HADOOP_DATANODE_OPTS变量,这种做法与设置NameNode堆大小类似:

hadoop配置 主机名 hadoop配置namenode_java_49

现在我们使用service命令开启DataNode后台服务:

hadoop配置 主机名 hadoop配置namenode_高可用_50

请经常检查后台服务的日志文件,特别是在对配置文件进行修改之后。如果DataNode成功启动并且能够与活动以及备份NameNode进行通信,读者应该查看日志文件中显示DataNode向NameNode发送分块分配信息的提示。

为了验证DataNode工作是否正常,我们将进行两个简单的测试。虽然只配置了一个DataNode,但现在我们仍会使用分布式文件系统。请回想dfs.namenode.replication.min参数的设定,它的默认值为1,这表示如果创建一份文件分块的副本,分布式文件系统将使用它存储文件。因此在花费时间将设定传输到所有的DataNode前,我们可以在单个DataNode上对其进行验证。

首先我们在分布式文件系统中创建一个临时目录并且向其上传一个示例文件。Hadoop中的临时目录与Linux下的/tmp目录作用类似。我们在随后章节中构建的某些生态系统项目要求/tmp目录包含在分布式文件系统中。我们使用hdfs命令在分布式文件系统中创建新目录:

hadoop配置 主机名 hadoop配置namenode_运维_51

hdfs命令行客户端工具用于在分布式文件系统中执行各种操作。它接受分布式文件系统命令作为参数并且尝试完成同标准Linux命令相同的任务,比如mkdir、ls、rm等等。请注意我们是以hdfs用户的身份执行该条命令,因为我们需要在文件系统中创建一个root权限的目录,而hdfs等同于本地文件系统中的root用户。如果读者尝试以root用户的身份执行该条命令,那么将会产生拒绝权限错误。

现在我们需要设置分布式文件系统中/tmp目录的权限,方法与在本地文件系统相类似:任何人都可以在该目录中读写文件,但是用户只能删除或者重命名自己的文件(防删除位)。在分布式文件系统中有一条chmod命令,它类似于下面的Linux命令:

hadoop配置 主机名 hadoop配置namenode_java_52

现在我们创建一个示例文本文件test.txt并且将它上传到分布式文件系统中,假设文件位于/root中,那么读者可以使用下列命令进行上传:

hadoop配置 主机名 hadoop配置namenode_操作系统_53

为了验证文件已经正确地进行了上传,我们可以通过hdfs的身份运行-ls和-cat命令。读者同样可以使用hdfs fsck命令确认文件系统的健康状态。

此时读者应该继续对集群中剩余的DataNode进行配置。显然在处理大量服务器时使用自动化工具来传输配置文件以及并行执行命令更为便捷。

TaskTracker配置

TaskTracker是我们在Hadoop核心中需要配置的最后一个部分。TaskTracker在MapReduce框架中的作用相当于分布式文件系统中的DataNode。TaskTracker负责启动和执行JobTracker提交的单个作业。TaskTracker后台服务运行在与DataNode相同的服务器上。在map过程中这就要求最大化的本地数据访问。JobTracker能够指出单个任务所需要的DataNode以及文件分块的位置并且将这些任务提交到运行在同一服务器上的TaskTracker中。

首先我们需要安装所需的包:

hadoop配置 主机名 hadoop配置namenode_操作系统_54

同JobTracker类似,hadoop-0.20-mapreduce将会作为依赖项进行安装。

TaskTracker后台服务采用和JobTracker相同的mapred-site.xml配置文件。这可能并不是最佳的方案,因为对于TaskTracker和JobTracker来说某些设定值可能会有所区别。在下面的示例中,我们假设读者维护了两个不同版本的mapred-site.xml,它们分别适用于JobTracker和TaskTracker。

我们首先需要设定JobTracker后台服务的地址和端口:

hadoop配置 主机名 hadoop配置namenode_操作系统_55

对于JobTracker我们也配置了相同的值。

在JobTracker服务器上我们同样配置了mapred.local.dir,但是在TaskTracker上它有着不同的功能。虽然它指定了存储临时数据的本地分卷,但是在TaskTracker上对于本地存储的要求更为严格。MapReduce作业使用本地存储来存放临时数据(map任务输出数据),随后它们将会传递到reduce阶段中。根据读者运行的作业以及作业的并行机制,数据的大小以及输入输出的密度会变得非常庞大。常见的解决方法是在DataNode使用的磁盘上为作业数据分配独立的目录。这样就要求有足够的磁盘空间并且使用多块硬盘来提升输入输出吞吐量。之前我们已经在DataNode后台服务中配置了dfs.du.reserve变量,它避免了分布式文件系统占据了所有的磁盘使得作业无法对临时空间进行写入导致任务失败。同样我们在JobTracker上也配置了相同的变量,但是对于磁盘的要求相对较低。下面是在TaskTracker上配置该参数的方法:

hadoop配置 主机名 hadoop配置namenode_高可用_56

假设分布式文件系统分卷挂接在/dfs/data*上。请确保MapReduce操作系统用户可以访问MapReduce目录。

我们在TaskTracker对Hadoop集群能力进行配置。从MapReduce的角度来看,集群的能力由可用的map空位以及reduce空位组成。每个TaskTracker能够分配的空位数是由服务器的硬件配置所决定的(尤其是可用的CPU以及内存)。在单个工作节点上创建过多的空位并没有太大的意义,因为作业进程会争夺系统资源,由此会导致性能大幅的下降。正如之前所讨论的,我们假设构建的小型高端集群中每个节点上配有16核CPU以及64GB的内存。根据经验可用的空位数和CPU数量两者之间应该大致匹配。在更为高速的服务器上可以略微增加一些CPU的负载,对于16核的机器我们可以分配总共24个任务空位(16×1.5=24)。请牢记这是所有用于map以及reduce的空位,由于map任务会对数据处理进行初始化并且针对每个输入分片(input split)都会生成一个map任务,因此相对于map空位,reduce空位的需求会更高一些。reduce步骤将执行map任务所生成的数据,所处理的数据也远小于map任务中生成的数据量。可用的map以及reduce空位比例取决于实际的工作负载,但是我们建议读者在最初为map任务分配三分之二的总服务器空位,剩余的三分之一则预留给reduce任务。在16核的机器上,我们拥有16个map空位以及8个reduce空位:

hadoop配置 主机名 hadoop配置namenode_操作系统_57

TaskTracker会为每个map和reduce任务创建单独的Java进程,因此除了本身的堆内存设定外,它还需要向子进程提供这些设定。和我们之前所配置的Hadoop后台服务类似,TaskTracker的堆大小可以在/etc/default/hadoop-0.20-mapreduce文件中的HADOOP_TASKTRACKER_OPTS变量中设定:

hadoop配置 主机名 hadoop配置namenode_运维_58

TaskTracker堆内存的大小默认为1GB,它能够符合大部分安装的需求。但是该设定与可分配给map以及reduce进程的内存无关,我们通过mapred-site.xml文件中的mapred.java.child.opts变量对此进行设定。实际上它可以用来向map和reduce进程提供不同的参数,但是最常见的用法是设定堆内存的上限以及下限。读者分配给单个任务的内存量取决于配置的空位总数以及服务器的内存量。在本例中单个服务器拥有64GB的内存以及总共24个任务空位,因此我们应该为每个任务分配2GB的内存:

hadoop配置 主机名 hadoop配置namenode_java_59

mapred.java.child.opts变量只是一串传递给任务进程的选项字符串,因此可以在此包含额外的参数,比如通过-Xms选项指定初始分配给进程的内存量。

现在我们已经完成了基本的TaskTracker设置,请使用下列命令对其进行启动:

hadoop配置 主机名 hadoop配置namenode_高可用_60

请检查TaskTracker的日志文件确保没有发生任何错误。在初始化设置中典型的错误通常都是不正确的本地目录权限、JobTracker地址拼写错误等等所造成的。可以运行下列命令列出所有JobTracker成功注册的TaskTracker:

hadoop配置 主机名 hadoop配置namenode_运维_61

在将该设置发送到所有TaskTracker之前,我们将运行一个实际的MapReduce作业,进行最终的可行性测试。这是一个基本的WordCount项目,它通常被认为是MapReduce中的“Hello,World”项目。同样它也包含在CDH包的示例中。

  1. 首先创建一个文件,在其中写入任意的文本并且将它保存在本地目录中。假设我们在jt1服务器上以root用户权限完成了这些操作。要执行MapReduce作业,需要在分布式文件系统中创建/user/root 目录。它同样也会作为作业提交目录。请确保将它的所属权设置为root:
  2. 请注意我们是以hdfs的身份执行这些操作的,它是分布式文件系统中的超级用户,在分布式文件系统中root用户只是一个普通用户。下面我们在/user/root中创建作业输入目录:
  3. 使用下列命令向分布式文件系统中上传文件:
  4. word cout示例以及其他示例作业都位于/usr/lib/hadoop-0.20-mapreduce/hadoop-examples.jar内。请使用hadoop jar命令来提交MapReduce作业:
  5. hadoop jar命令包含了多个参数:. jar文件的位置、运行作业的类名、用于查找输入文件的目录以及写入最终结果的目录。对于每个运行的作业都会创建一个输出目录,因此请确保在开启作业时该目录并不存在。在执行该命令后如果一切都配置正常,那么读者将看到作业的执行流程以及一些额外的信息,其中包括了map和reduce步骤所花费的时间、处理的行数,等等。
  6. 在输出目录中读者应该看到下列文件:
  7. _SUCCESS是一个标记文件,它表示作业已经完成并且没有产生任何错误。_logs目录包含了作业执行日志,part-r-00000是结果文件,其中包含了文字以及根据输入文件所产生的计数。读者可以运行下列命令检查其中的内容:

如果一切运行正常,那么表示MapReduce和分布式文件系统的配置没有任何问题,因此读者可以将它们传输到集群中的所有节点上。

高级Hadoop设置

在之前的部分中我们讲解了构建和设置核心Hadoop组件的步骤。在对实际工作负载以及执行的作业类型有了更深层次的理解后,读者可能希望调整某些额外的配置设定来更好地提升或者平衡工作负载。Hadoop提供了更多超过我们之前讨论范围的配置选项。读者可能不会对其中的大部分进行更改,但是在此我们还是要讲解一些与性能相关的变量。

hdfs-site.xml

NameNode需要对分布式文件系统的客户端的各种请求进行响应,其中包括了DataNode以及外部程序。为了更高效地处理这些请求,NameNode创建了多个线程来处理这些负载并且所创建的线程数可以通过dfs.namenode.handler.count变量进行配置。在默认情况下线程的数量为10,但是如果在构建大型集群时读者可能希望增加它的数量。该数量的计算有各种不同的选项,但是通常情况下将该值设置过高并不会带来极大的性能提升。如果集群中的节点数超过200的话请将该值设置为100,在其他情况下请将它设置为50:

hadoop配置 主机名 hadoop配置namenode_java_62

在集群中加入新的DataNode用来提升性能或者替换故障节点是Hadoop管理员的日常任务。虽然新节点会为新创建的文件以及副本接收分块,但是现存的数据并不会自动进行平衡,也就是说新节点无法完全得到使用。为了强制Hadoop将现存数据分块移动到性能较强的服务器上,读者需要运行hdfs balancer命令,但是在网络中移动大量的数据会干扰到普通的作业。为了防止这种情况,Hadoop定义了dfs.datanode.balance.bandwidthPerSec变量(单位是字节/秒)用来平衡数据的移动。默认的设置为1MB/秒,具体的数值根据集群中的网络带宽而定。我们使用下列设定将它增加为10MB/秒:

hadoop配置 主机名 hadoop配置namenode_运维_63

mapred-site.xml

和NameNode类似,JobTracker也会对多种客户端请求进行响应。为了确保JobTracker能够分配足够的线程来完成任务,读者需要对mapred.job.tracker.handler.countmapred.job.tracker.handler.count变量进行设置。配置的原则和NameNode线程数相同:

hadoop配置 主机名 hadoop配置namenode_高可用_64

MapReduce作业的性能很大程度受到排序阶段的影响,单个map任务的输出必须按照键进行排序,然后归并到多个大型文件中发送到reduce器。该阶段通常会产生大量的网络流量并且产生巨大的本地输入输出。在map任务对结果进行排序时,它会使用内部的内存,在该内存用完后,它会将数据传输到本地磁盘上。为了节省这种传输的流量,读者可以增加io.sort.mb的大小。默认情况下它的设置为100MB,对于大部分工作负载来说都是一个理想的内存大小。如果读者在排序阶段观察到了大量的本地输入输出,那么请增加该变量的数值。我们在mapred-site.xml文件中加入下列代码将排序内存增加到200MB:

hadoop配置 主机名 hadoop配置namenode_运维_65

请注意该内存是作为任务堆内存(通过mapred.java.child.opts变量指定)中的一部分进行分配的。

与此相关的一个选项是io.sort.factor,它指定了一次批量归并的文件数。同样对于该参数没有严格的规定,但是默认的数值10并不能满足要求。读者可以将它设置为32,该数值可能并不精确,因此请读者根据集群的性能自行调节:

hadoop配置 主机名 hadoop配置namenode_高可用_66

在作业map的reduce阶段中,某个键值范围内的输出将会复制到特定的reduce器中。在集群中会有许多这样的输出,因此reduce器使用多个并行进程来加速复制过程。默认情况下会并行创建五个复制进程。在大型的集群中或者运行包含多个map任务的作业时,读者可能需要增加该数值。对于小型或者中型的集群(20到100个节点)中请设置12到16个并行进程:

hadoop配置 主机名 hadoop配置namenode_hadoop配置 主机名_67

core-site.xml

大型的Hadoop集群在数据中心中会分布在多个机架上,同样小型集群也会占据两到三个机架。这样对于小型集群来说,在单个机架故障时能够提供额外的冗余性。Hadoop本身就实现了机架感知(rack-aware),同时能够根据服务器所属的机架进行一定的优化。其中的一个示例是Hadoop使用的分块副本分布策略。它会尝试在不同的机架上存储至少一个副本,以此来增加数据弹性。在请求数据分块时(例如在MapReduce作业中),Hadoop会选择相同机架上的服务器,从而避免了跨越机架的网络访问。

为了使用该特性,Hadoop需要了解机架上所架设的服务器。因此Hadoop管理员需要提供一个返回机架标识以及服务器IP或者主机名的可执行文件。该文件的实现方法由管理员决定。最常见的做法是创建一个由逗号分隔的文本文件,其中包含服务器所对应的机架,同时编写一个命令行、Python或者Perl脚本,它将IP或者主机名作为参数并且会返回机架标识。机架标识可以为任意的字符串。如何编写这种功能的脚本超出了本书的讲解范围,但是在网上有多种版本的示例。读者需要在net.topology.script.file.name变量中指定脚本的路径来开启机架感知功能:

hadoop配置 主机名 hadoop配置namenode_java_68

如果没有提供脚本,Hadoop会认为所有的服务器都位于一个机架上。