代码改变世界

Hadoop学习(5)-- Hadoop2

2015-01-28 09:14  hduhans  阅读(1286)  评论(0编辑  收藏  举报

  在Hadoop1(版本<=0.22)中,由于NameNode和JobTracker存在单点中,这制约了hadoop的发展,当集群规模超过2000台时,NameNode和JobTracker已经不堪重负。于是,全新架构的hadoop2(版本>=0.23)诞生了,可以支持分布式NameNode、NameNode HA(NameNode High Available),实现了NameNode的横向扩展,使得集群规模最大可支持上万个节点。

一、Hadoop2介绍

1、Hadoop1局限性

   NameNode存储用户HDFS文件的元数据信息,集群关闭时这些信息存放在磁盘上,但是在集群运行时,这些信息是加载在内存中的。由于在Hadoop1的架构中只存在一个NameNode和一个JobTracker,由此带来了一系列的局限性:

   ▶ NameNode无法扩展。随着文件数目的增大,NameNode节点压力也相应增大,当NameNode无法在内存中加载所有元数据信息的时候,集群的寿命就到头了

   ▶ NameNode存在单点故障风险。所有的元数据信息存储在NameNode节点中,当此节点宕机或发生不可恢复的灾难时,集群的文件很难恢复

   ▶ 存在文件访问权限控制的问题。一个NameNode对应一个NameSpace,所有用户的文件都处于同一NameSpace下,很难隔离,不利于HDFS在公有云环境下的应用

   ▶ JobTracker存在单点故障风险。集群所有的任务都在JobTracker中执行,一旦此节点放生故障,所有执行的任务都会丢失。此外,JobTracker,也无法扩展,最多支持4000个并行任务

2、Hadoop2的新特性

   为了解决Hadoop1中存在的局限性,Hadoop2重新设计了框架架构,引入了许多新特性。

   1) HDFS Federation

   为了解决单点NameNode负载过重的问题,Hadoop2引入了HDFS联盟的概念。即多个HDFS同时存在,可支持更多的文件存储。每个HDFS存在一个激活的NameNode,每个NameNode对应一个NameSpace,配置人员可以选择合适的NameSpace划分方式,将所有的DataNode被全部的NameNode共享DataNode中存储的数据有不同NameNode的标识,因此不同NameNode存储的数据不会混淆,这就好比某个部门内的员工同时服从于部门主管和人事主管管理,部门主管和人事主管管理的内容是不一样的,理论上不会发生冲突。系统提供了一个公共的Block pools隔离了NameSpace与Block交互,如图1.1和1.2所示。

图1.1 HDFS 联盟架构

图1.2 HDFS联盟架构

   如果将一个城市中居住的市民比喻为HDFS中存储的文件,人才市场档案存储室的大小比喻为NameNode所在节点的内存大小,那么单点NameNode过重问题可以形象地比喻为:每一个市民都有档案保存在人才市场的房间中,当市民越来越多时,人才市场房间内的档案越来越多,一旦房间存满,那么即使整个城市还可以容纳更多的市民居住,也无法再添加更多的市民了,这时候整个城市容纳市民能力的瓶颈在于单个人才市场房间的存储能力。如果设置两个或多个人才市场来分担所有市民的档案,那么再也不用担心人才市场存放档案房间的大小了,当存放满时,可以再开一个新的人才市场用于存放档案,也即是说,此时整个城市容纳市民能力的瓶颈在于城市所有房间的居住能力和能最大化地利用所有资源

   在HDFS联盟中,所有NameNode可以共享所有的DataNode,处于不同NameSpace下的文件会被系统很好的隔离,很好地实现了文件的访问权限控制。

   2) Automatic High Available

   为了规避单点NameNode存在的故障风险,Hadoop2支持自动HA的配置。NameNode就是整个集群的心脏,在Hadoop1时代,只存在一个NameNode,一旦该NameNode数据丢失或者不能工作,可能会给整个集群带来巨大的灾难。在Hadoop2中,可以支持一个集群内2个NameNode同时启动(目前是2个,以后会增加),其中一个处于active工作状态,另一个处于standby休眠状态注意HA中的两个NameNode属于同一命名空间,这与HDFS联盟是不同的。两个NameNode为了数据同步,会通过一组称作JournalNodes的独立进程进行相互通信,其结果如图1.3所示。

图1.3 NameNode HA基本结构示意图

   要实现集群的自动HA,通常都要依赖Zookeeper集群和ZFKC进程。ZKFC进程在NameNode所在的节点上启动,用于监测Active的NameNode进程是否处于可用状态,一旦发现Active的NameNode进程挂掉,就立即通知Zookeeper集群,然后standby的NameNode节点上的ZFKC进程就会执行命令,将standby的NameNode切换为Active状态。其工作原理示意图如1.4所示。

图1.4 NameNode自动HA系统结构示意图

   需要注意的几点:

   ① 当active状态的NameNode宕机后,需要手动切换到standby状态的NameNode来继续提供服务。如果要实现自动切换,必须依赖Zookeeper

   ② JournalNode进程非常轻量,可以部署在其他的服务器上。JournalNode节点个数至少为3个,且为奇数个,如3、5、7等。当运行N个节点时,系统可以容忍至少(N-1)/2个节点失败而不影响正常运行;

   ③ 配置了NameNode HA后,客户端可以通过HA的逻辑名称去访问数据,而不用指定某一台NameNode,当某一台NameNode失效自动切换后,客户端不必更改hdfs的连接地址,仍可通过逻辑名称去访问,需要在conf中添加如下设置

conf.setStrings("dfs.nameservices", "cluster1,cluster2");
conf.setStrings("dfs.ha.namenodes.cluster1", "hadoop0,hadoop1");
conf.setStrings("dfs.namenode.rpc-address.cluster1.hadoop0", "hadoop0:9000");
conf.setStrings("dfs.namenode.rpc-address.cluster1.hadoop1", "hadoop1:9000");
//必须配置,可以通过该类获取当前处于active状态的namenode
conf.setStrings("dfs.client.failover.proxy.provider.cluster1", "org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider");
View Code

   3) Yarn架构

   在Hadoop1中,JobTracker扮演着资源分配任务调度的角色,当任务数达到一定级别后,JobTracker的负载就会很重,并且由于以单点形式存在,一旦出现故障,会造成作业信息的丢失,成为MapReduce中脆弱的一环。

   为了解决此问题,Hadoop2引入Yarn架构,将JobTracker的两个主要功能分离成单独的组件。全局资源分配由ResourceManager负责,任务调度和协调由每一个应用的ApplicationMaster负责,其架构如图1.5所示。

图1.5 Yarn架构图

   角色说明:

   ① ResourceManager(RM):负责全局资源(这里的资源指的是CPU和内存,暂不包括网络资源)的分配,主要由调度器应用程序管理器组成。调度器根据容量、队列等限制条件,将系统中的资源分配给各个正在运行的应用程序,而应用程序管理器负责管理整个系统中所有应用程序。Yarn提供了多种可直接调用的调度器,如Fair Scheduler和Capacity Scheduler等; 

   ② ApplicationMaster(AM):用户提交的每个应用程序均包含一个AM,主要用于与RM调度器协商以获取资源然后将得到的资源进一步分配给内部的任务AM还会与NM通信以自动/停止任务,监控所有任务运行状态,并在任务失败时重新为任务申请资源以重启任务。当前Yarn自带了两个AM实现,一个用于演示AM编写方法的实例程序distributedshell,另一个用于Mapreduce程序(MRAppMaste);

   ③ NodeManager(NM):NM是每个节点上的资源和任务管理器,主要用于接受并处理来自AM的Container启动/停止等各种要求,也会定时向RM汇报本节点上的资源使用情况和Container的运行状态

   ④ Container:是Yarn中的资源抽象,封装了某个节点上的多维度资源。YARN会为每个任务分配一个Container,且改任务只能使用该Container中描述的资源。Container不同于MRv1的slot,它是一个动态资源划分单位,是根据应用程序的需求动态产生的;

3、MR2通信协议及执行过程

   待完善....

二、搭建Hadoop2的伪分布模式环境

   本次实验搭建环境:CentOS-5.5(VMWare虚拟机),本地编译64位版hadoop-2.6.0(编译步骤见《编译本地64位版本的hadoop-2.6.0》)。

1、基本环境配置

   所有节点都需要配置基本环境,包括设置静态IP地址修改主机名关闭防火墙及防火墙的自动启动配置SSH免密码登陆安装JDK,配置过程参考《Hadoop学习(3)-- 安装1.x版本》。

2、安装hadoop2

   与hadoop1伪分布模式安装基本一致,区别是修改的配置文件不同,hadoop2需要修改配置如下配置文件:

   ① hadoop-env.sh

export JAVA_HOME=/usr/local/jdk1.7.0_75/
View Code

   ② core-site.xml

<property>
    <name>fs.defaultFS</name>
    <value>hdfs://hadoop0:9000</value>
</property>
<!--指定NameNode地-->
<property>
        <name>hadoop.tmp.dir</name>
        <value>/usr/local/hadoop-2.6.0/tmp</value>
</property>
<!--指定hadoop运行时产生文件的存储目录-->
View Code

   ③ hdfs-site.xml

<property>
        <name>dfs.replication</name>
        <value>1</value>
</property>    
View Code

   ④ mapred-site.xml(不存在则:mv mapred-site.xml.template mapred-site.xml)

<property>
    <name>mapreduce.framework.name</name>
    <value>yarn</value>
</property>
<!--指定mapreduce运行在yarn上-->
View Code

   ⑤ yarn-site.xml

<property>
    <name>yarn.resourcemanager.hostname</name>
    <value>hadoop0</value>
</property>
<!--指定YARN的ResourceManager地址-->
<property>
    <name>yarn.nodemanager.aux-services</name>
    <value>mapreduce_shuffle</value>
</property>
<!--指定reducer获取数据的方式-->
View Code

   格式化NameNode:hdfs namenode -formathadoop namenode -format

   启动hadoop:① 启动hdfs:sbin/start-dfs.sh;② 启动yarn:sbin/start-yarn.sh

   验证命令:jps,查看是否启动这些进程:NameNodeSecondaryNameNodeNodeManagerResourceManagerDataNode

   管理界面:① HDFS管理:http://localhost:50070;② MapReduce管理:http://localhost:8088

三、搭建Hadoop2的Automatic HA+HDFS Federation+Yarn环境

1、搭建说明

   本次实验环境:CentOS-5.5(VMWare虚拟机),编译后的64位版Hadoop-2.2.0(点击下载Hadoop-2.2.0-x64.zip,编译步骤参考《编译Apache Hadoop2.2.0源代码》)。

   实验使用了4台CentOS虚拟机,职责分别如下所示:

图2.1 实验环境节点说明

   其中JournalNode、Zookeeper和ZKFC用于实现自动HA功能,作用分别为:① JournalNode进程用于保存自动NameNode HA同步的文件元数据,数量为奇数个;② ZKFC(ZKFailover Controller)进程用于实现自动HA,它会监控Active的NameNode运行,并在其失效后立即将这一情况报告给Zookeeper,然后standby状态NameNode所在节点上的ZKFC就会接收来自Zookeeper的数据,并将standby的NameNode切换为Active,因此必须在自动HA两个NameNode所在的节点上分别启动ZKFC进程;③ Zookeeper进程用于在保存来自ZKFC的关于NameNode的状态数据,并被其他ZKFC进程获取,实现不同节点上ZKFC进程的数据共享,数量为奇数个

2、基本环境配置

   所有节点都需要配置基本环境,包括设置静态IP地址修改主机名关闭防火墙及防火墙的自动启动配置节点间SSH免密码登陆以及安装JDKZookeeper,参考《Hadoop学习(3)-- 安装1.x版本》中有关完全分布式的安装和《ZooKeeper -- 分布式开源协调服务》。

3、批量安装Hadoop2

   安装时根据机器是32位还是64位选择相应的Hadoop2版本进行安装,本实例所用版本Hadoop-2.2.0官方只提供了32位版本,可自行编译64位版本。

   1) 将编译后的64位版本的Hadoop-2.2.0项目上传到hadoop0节点的/usr/local目录下,重命名为hadoop;

   2) 修改配置文件hadoop/etc/hadoop/hadoop-env.sh,修改内容如下所示: 

export JAVA_HOME=/usr/local/jdk
View Code

   3) 修改配置文件hadoop/etc/hadoop/core-site.xml,修改内容如下所示:

<configuration>
    <property>
        <name>fs.defaultFS</name>
        <value>hdfs://cluster1</value>
    </property>
    <!--这里的值指的是默认的HDFS路径。当有多个HDFS集群同时工作时,用户如果不写集群名称,默认使用哪个在这里指定!该值来自于hdfs-site.xml中的配置。在节点hadoop0和hadoop1中使用cluster1,在节点hadoop2和hadoop3中使用cluster2-->
    <property>
        <name>hadoop.tmp.dir</name>
        <value>/usr/local/hadoop/tmp</value>
    </property>
    <!--这里的路径默认是NameNode、DataNode、JournalNode等存放数据的公共目录。用户也可以自己单独指定这三类节点的目录-->
    <property>
        <name>ha.zookeeper.quorum</name>
        <value>hadoop0:2181,hadoop1:2181,hadoop2:2181</value>
    </property>
    <!--这里是ZooKeeper集群的地址和端口。注意,数量一定是奇数,且不少于三个节点-->
</configuration>
View Code

   需要注意的是,fs.defaultFS配置在两个集群中不同节点hadoop0和hadoop1中配置为hdfs://cluster1节点hadoop2和hadoop3中配置为hdfs://cluster2

   4) 修改配置文件hadoop/etc/hadoop/hdfs-site.xml,修改内容如下所示:

<configuration>
    <property>
        <name>dfs.replication</name>
        <value>2</value>
    </property>
    <!--指定DataNode存储block的副本数量。默认值是3个,我们现在有4个DataNode,该值不大于4即可-->
    <property>
        <name>dfs.nameservices</name>
        <value>cluster1,cluster2</value>
    </property>
    <!--此实例HDFS联盟使用了2个HDFS集群,这里抽象给两个集群设置了别名-->
    <property>
        <name>dfs.ha.namenodes.cluster1</name>
        <value>hadoop0,hadoop1</value>
    </property>
    <!--指定NameService=cluster1时的namenode,值为逻辑名称-->
    <property>
        <name>dfs.namenode.rpc-address.cluster1.hadoop0</name>
        <value>hadoop0:9000</value>
    </property>
    <!--指定hadoop0的rpc地址,用户节点进程之间的沟通-->
    <property>
        <name>dfs.namenode.http-address.cluster1.hadoop0</name>
        <value>hadoop0:50070</value>
    </property>
    <!--指定hadoop0的http地址,可通过http://hadoop0:50070访问hadoop0的NameNode的数据信息-->
    <property>
        <name>dfs.namenode.rpc-address.cluster1.hadoop1</name>
        <value>hadoop1:9000</value>
    </property>
    <property>
        <name>dfs.namenode.http-address.cluster1.hadoop1</name>
        <value>hadoop1:50070</value>
    </property>
    <property>
        <name>dfs.ha.automatic-failover.enabled.cluster1</name>
        <value>true</value>
    </property>
    <!--设置cluster1是否启动自动故障恢复,即当NameNode出故障时,是否允许Zookeeper自动切换到另一台NameNode继续提供服务--->
    <property>
        <name>dfs.client.failover.proxy.provider.cluster1</name>
        <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
    </property>
    <!--设置cluster1出故障时,哪个实现类负责执行故障切换-->
    
    <property>
        <name>dfs.ha.namenodes.cluster2</name>
        <value>hadoop2,hadoop3</value>
    </property>
    <property>
        <name>dfs.namenode.rpc-address.cluster2.hadoop2</name>
        <value>hadoop2:9000</value>
    </property>
    <property>
        <name>dfs.namenode.http-address.cluster2.hadoop2</name>
        <value>hadoop2:50070</value>
    </property>
    <property>
        <name>dfs.namenode.rpc-address.cluster2.hadoop3</name>
        <value>hadoop3:9000</value>
    </property>
    <property>
        <name>dfs.namenode.http-address.cluster2.hadoop3</name>
        <value>hadoop3:50070</value>
    </property>
    <property>
        <name>dfs.ha.automatic-failover.enabled.cluster2</name>
        <value>true</value>
    </property>
    <property>
        <name>dfs.client.failover.proxy.provider.cluster2</name>
        <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
    </property>

    <property>
        <name>dfs.journalnode.edits.dir</name>
        <value>/usr/local/hadoop/tmp/journal</value>
    </property>
    <!--当JournalNode对NameNode的文件元数据进行共享时,指定共享文件在本地磁盘保存的路径--->
    <property>
        <name>dfs.ha.fencing.methods</name>
        <value>sshfence</value>
    </property>
    <!--当NameNode需要切换时,指定通过SSH方式进行操作-->
    <property>
        <name>dfs.ha.fencing.ssh.private-key-files</name>
        <value>/root/.ssh/id_rsa</value>
    </property>
    <!--如果配饰使用SSH进行NameNode故障切换,指定SSH通信时密钥存储的位置-->
    
    <property>
        <name>dfs.namenode.shared.edits.dir</name>
        <value>qjournal://hadoop0:8485;hadoop1:8485;hadoop2:8485/cluster1</value>
    </property>
    <!--此处两个集群需特殊配置,hadoop0和hadoop1值为cluster1,hadoop1和hadoop2值为cluster2。指定集群NameNode的元数据信息保存在哪些JournalNode节点上-->
</configuration>
View Code

   需要注意的是,上述最后一项配置dfs.namenode.shared.edits.dir在两个集群中值不同,hadoop0和hadoop1值为qjournal://hadoop0:8485;hadoop1:8485;hadoop2:8485/cluster1,hadoop2和hadoop3值为qjournal://hadoop0:8485;hadoop1:8485;hadoop2:8485/cluster2

   5) 修改配置文件hadopp/etc/hadoop/slaves,修改内容如下所示:

hadoop1
hadoop2
hadoop3
View Code

   该配置可以在hadoop0上通过命令:sbin/hadoop-daemons.sh start datanode启动所有的DataNode进程。

   6) 在环境变量/etc/profile中增加/usr/local/hadoop/bin和/usr/local/hadoop/sbin的配置,并执行命令:source /etc/profile使配置文件立即生效;

   7) 使用scp命令将hadoop0节点的上述配置内容复制到hadoop1、hadoop2和hadoop3节点上,并根据所在集群修改对应红字标出的特殊配置:①修改hadoop2、hadoop3上配置文件core-site.xml中fs.defaultFS的值为hdsf://cluster2;②修改hadoop2、hadoop3上配置文件hdfs-site.xml的dfs.namenode.shared.edits.dir值为qjournal://hadoop0:8485;hadoop1:8485;hadoop2:8485/cluster2

4、启动集群

   1) 启动Zookeeper,在hadoop0、hadoop1、hadoop2上执行命令:zkServer.sh start,并通过命令:zkServer.sh status验证Zookeeper集群是否成功启动; 

   2) 启动JournalNode,在hadoop0、hadoop1、hadoop2上执行命令:hadoop-daemon.sh start journalnode

   3) 格式化Zookeeper,在hadoop0、hadoop2上执行命令:hdfs zkfc -formatZK,该命令会分别在Zookeeper中创建记录hadoop-ha/{集群名},Zookeeper内的记录可通过zkCli.sh客户端执行ls命令查看;

   4) 格式化和启动hadoop0节点,在hadoop0上执行NameNode格式化命令:hdfs namenode -format,然后执行启动命令:hadoop-daemon.sh start namenode

   5) 格式化和启动hadoop1节点,在hadoop1上执行命令:hdfs namenode -bootstrapStandby(从节点执行此格式化命令后生成的VERSION文件中集群号等信息与主节点相同,相当于将hadoop0上的/tmp/name文件夹拷贝至从节点),然后执行启动命令:hadoop-daemon.sh start namenode

   6) 启动cluster1的zkfc,在hadoop0、hadoop1上启动命令:hadoop-daemon.sh start zkfc,然后hadoop0和hadoop1的其中一个NameNode会变成active状态;

   7) 同hadoop0和hadoop1,在hadoop2和hadoop3上执行相同操作启动cluster2;

   8) 启动集群的DataNode,在hadoop0上执行命令:hadoop-daemons.sh start datanode,会根据slaves配置内容启动hadoop1、hadoop2和hadoop3的DataNode进程; 

   注:

   ① 这里千万要区分hadoop-daemon.sh和hadoop-daemons.sh,前者命令只在本节点上执行,后者命令会在所有slaves节点上执行

   ② 若DataNode节点进程正常,但NameNode显示可用的DataNode为0,有可能是DataNode的集群号与NameNode不一致导致的,检查VERSION文件(测试启动集群时,发现某个datanode只能服务于某个集群,而不能被所有集群共享,这与官方介绍的datanode被所有集群共享不一致,应该是配置的问题,等日后再研究);

   ③ 上述启动命令中,格式化的命令是在集群部署后首次启动时执行的,常规启动不需要进行格式化操作;

   ④ 可以通过自定义的shell脚本来减少集群启动关闭时的手工操作,下述三个脚本供参考:

   首次格式化并启动集群脚本cluster-reformat-and-start.sh:

#!/bin/sh
i=0
cluster_count=4
zk_node_indexs=(0 1 2)  #the node indexs which run zookeeper progress 
journalnode_indexs=(0 1 2)  #the journalnode indexs
active_namenode_indexs=(0 2)  #the main namenode indexs in hdfs federation, these node will run command "hdfs zkfc -formatZK -force" and "hdfs namenode -format"
standby_namenode_indexs=(1 3)  #the standby namenode indexs in namenode HA, these node will run command "hdfs namenode -bootstrapStandby"

#delete tmp and log file
while(( $i<$cluster_count ))
do
    echo -e "------delete tmp file on hadoop$i-------"
        ssh root@hadoop$i "rm -rf /usr/local/hadoop/tmp"
    echo -e "------delete tmp logs on hadoop$i-------"
        ssh root@hadoop$i "rm -rf /usr/local/hadoop/logs"
        let "i++"
done

#start zk
for i in "${!zk_node_indexs[@]}";
do 
    zk_node_index=${zk_node_indexs[$i]}  #current zk node index
    echo -e "------start zk on hadoop$zk_node_index-------"
    ssh hadoop$zk_node_index "source /etc/profile;/usr/local/zk/bin/zkServer.sh start"
    ssh hadoop$zk_node_index "source /etc/profile;/usr/local/zk/bin/zkServer.sh status"
done

#start journalnode
for i in "${!journalnode_indexs[@]}";
do 
    journalnode_index=${journalnode_indexs[$i]}  #current journalnode index
    echo -e "------start journalnode on hadoop$journalnode_index-------"
    ssh hadoop$journalnode_index "source /usr/local/hadoop/sbin/hadoop-daemon.sh start journalnode"
done

#format zk, format and start active namenode
for i in "${!active_namenode_indexs[@]}";
do
    active_namenode_index=${active_namenode_indexs[$i]}  
    echo -e "------force formatzk on hadoop$active_namenode_index-------"
    ssh hadoop$active_namenode_index "/usr/local/hadoop/bin/hdfs zkfc -formatZK -force"
    echo -e "------force active format namenode on hadoop$active_namenode_index-------"
    ssh hadoop$active_namenode_index "/usr/local/hadoop/bin/hdfs namenode -format -force"
    echo -e "------start namenode on hadoop$active_namenode_index-------"
    ssh hadoop$active_namenode_index "/usr/local/hadoop/sbin/hadoop-daemon.sh start namenode"
done 

#format and start standby namenode
for i in "${!standby_namenode_indexs[@]}";
do
    standby_namenode_index=${standby_namenode_indexs[$i]}  
    echo -e "------force standby namenode on hadoop$standby_namenode_index-------"
    ssh hadoop$standby_namenode_index "/usr/local/hadoop/bin/hdfs namenode -bootstrapStandby -force"
    echo -e "------start namenode on hadoop$standby_namenode_index-------"
    ssh hadoop$standby_namenode_index "/usr/local/hadoop/sbin/hadoop-daemon.sh start namenode"
done 

#start zkfc in active namenodes, then standby namenodes
for i in "${!active_namenode_indexs[@]}";
do
    active_namenode_index=${active_namenode_indexs[$i]}  
    echo -e "------start zkfc on hadoop$active_namenode_index-------"
    ssh hadoop$active_namenode_index "/usr/local/hadoop/sbin/hadoop-daemon.sh start zkfc"
done
for i in "${!standby_namenode_indexs[@]}";
do
    standby_namenode_index=${standby_namenode_indexs[$i]}  
    echo -e "------start zkfc on hadoop$standby_namenode_index-------"
    ssh hadoop$standby_namenode_index "/usr/local/hadoop/sbin/hadoop-daemon.sh start zkfc"
done

#start datanodes
echo -e "------start datanode in all slaves-------"
ssh hadoop0 "/usr/local/hadoop/sbin/hadoop-daemons.sh start datanode"

#start yarn
echo -e "------start yarn in hadoop0-------"
ssh hadoop0 "/usr/local/hadoop/sbin/start-yarn.sh"
View Code

   常规启动集群脚本cluster-start.sh:

#!/bin/sh
i=0
cluster_count=4
zk_node_indexs=(0 1 2)  #the node indexs which run zookeeper progress 
journalnode_indexs=(0 1 2)  #the journalnode indexs
active_namenode_indexs=(0 2)  #the main namenode indexs in hdfs federation, these node will run command "hdfs zkfc -formatZK -force" and "hdfs namenode -format"
standby_namenode_indexs=(1 3)  #the standby namenode indexs in namenode HA, these node will run command "hdfs namenode -bootstrapStandby"

#start zk
for i in "${!zk_node_indexs[@]}";
do 
    zk_node_index=${zk_node_indexs[$i]}  #current zk node index
    echo -e "------start zk on hadoop$zk_node_index-------"
    ssh hadoop$zk_node_index "source /etc/profile;/usr/local/zk/bin/zkServer.sh start"
    ssh hadoop$zk_node_index "source /etc/profile;/usr/local/zk/bin/zkServer.sh status"
done

#start journalnode
for i in "${!journalnode_indexs[@]}";
do 
    journalnode_index=${journalnode_indexs[$i]}  #current journalnode index
    echo -e "------start journalnode on hadoop$journalnode_index-------"
    ssh hadoop$journalnode_index "source /usr/local/hadoop/sbin/hadoop-daemon.sh start journalnode"
done

#start active and standby namenodes
for i in "${!active_namenode_indexs[@]}";
do
    active_namenode_index=${active_namenode_indexs[$i]}  
    echo -e "------start namenode on hadoop$active_namenode_index-------"
    ssh hadoop$active_namenode_index "/usr/local/hadoop/sbin/hadoop-daemon.sh start namenode"
    echo -e "------start zkfc on hadoop$active_namenode_index-------"
    ssh hadoop$active_namenode_index "/usr/local/hadoop/sbin/hadoop-daemon.sh start zkfc"
done 
for i in "${!standby_namenode_indexs[@]}";
do
    standby_namenode_index=${standby_namenode_indexs[$i]}  
    echo -e "------start namenode on hadoop$standby_namenode_index-------"
    ssh hadoop$standby_namenode_index "/usr/local/hadoop/sbin/hadoop-daemon.sh start namenode"
    echo -e "------start zkfc on hadoop$standby_namenode_index-------"
    ssh hadoop$standby_namenode_index "/usr/local/hadoop/sbin/hadoop-daemon.sh start zkfc"
done 

#start datanodes
echo -e "------start datanode in all slaves-------"
ssh hadoop0 "/usr/local/hadoop/sbin/hadoop-daemons.sh start datanode"

#start yarn
echo -e "------start yarn in hadoop0-------"
ssh hadoop0 "/usr/local/hadoop/sbin/start-yarn.sh"
View Code

   关闭集群脚本cluster-stop.sh:

#!/bin/sh
i=0
cluster_count=4
zk_node_indexs=(0 1 2)  #the node indexs which run zookeeper progress 
journalnode_indexs=(0 1 2)  #the journalnode indexs
active_namenode_indexs=(0 2)  #the main namenode indexs in hdfs federation, these node will run command "hdfs zkfc -formatZK -force" and "hdfs namenode -format"
standby_namenode_indexs=(1 3)  #the standby namenode indexs in namenode HA, these node will run command "hdfs namenode -bootstrapStandby"

#stop zk
for i in "${!zk_node_indexs[@]}";
do 
    zk_node_index=${zk_node_indexs[$i]}  #current zk node index
    echo -e "------stop zk on hadoop$zk_node_index-------"
    ssh hadoop$zk_node_index "source /etc/profile;/usr/local/zk/bin/zkServer.sh stop"
done

#stop journalnode
for i in "${!journalnode_indexs[@]}";
do 
    journalnode_index=${journalnode_indexs[$i]}  #current journalnode index
    echo -e "------stop journalnode on hadoop$journalnode_index-------"
    ssh hadoop$journalnode_index "source /usr/local/hadoop/sbin/hadoop-daemon.sh stop journalnode"
done

#stop zkfc, namenode in active and standby namenodes
for i in "${!active_namenode_indexs[@]}";
do
    active_namenode_index=${active_namenode_indexs[$i]}  
    echo -e "------stop namenode on hadoop$active_namenode_index-------"
    ssh hadoop$active_namenode_index "/usr/local/hadoop/sbin/hadoop-daemon.sh stop namenode"
    echo -e "------stop zkfc on hadoop$active_namenode_index-------"
    ssh hadoop$active_namenode_index "/usr/local/hadoop/sbin/hadoop-daemon.sh stop zkfc"
done
for i in "${!standby_namenode_indexs[@]}";
do
    standby_namenode_index=${standby_namenode_indexs[$i]}  
    echo -e "------stop namenode on hadoop$standby_namenode_index-------"
    ssh hadoop$standby_namenode_index "/usr/local/hadoop/sbin/hadoop-daemon.sh stop namenode"
    echo -e "------stop zkfc on hadoop$standby_namenode_index-------"
    ssh hadoop$standby_namenode_index "/usr/local/hadoop/sbin/hadoop-daemon.sh stop zkfc"
done

#stop datanodes
echo -e "------stop datanode in all slaves-------"
ssh hadoop0 "/usr/local/hadoop/sbin/hadoop-daemons.sh stop datanode"

#stop yarn
echo -e "------stop yarn in hadoop0-------"
ssh hadoop0 "/usr/local/hadoop/sbin/stop-yarn.sh"
View Code 

5、批量配置Yarn

   1) 修改配置文件hadoop/etc/hadoop/mapred-site.xml,修改内容如下所示:

<property>
    <name>mapreduce.framework.name</name>
    <value>yarn</value>
</property> 
<!--指定框架名称为yarn-->
View Code

   2) 修改配置文件hadoop/etc/hadoop/yarn-site.xml,修改内容如下所示:

<property>
    <name>yarn.resourcemanager.hostname</name>
    <value>hadoop0</value>
</property>   
 <!--指定ResourceManager的地址,还是单点,这也是隐患-->
<property>
    <name>yarn.nodemanager.aux-services</name>
    <value>mapreduce_shuffle</value>
</property>
<!--指定reducer获取数据的方式-->
View Code

   3) 将上述配置文件复制到hadoop1、hadoop2和hadoop3节点上;

   4) 启动yarn,在hadoop0上执行命令:start-yarn.sh,会启动ResourceManager进程,可通过http://hadoop0:8088查看ResourceManager管理界面;

四、集群管理

1、添加新节点 

   1) 新节点配置安装jdk、hadoop软件;

   2) Name节点设置免密码登陆新节点;

   3) 在Name节点slaves文件中添加新节点;

   4) 在所有节点/etc/hosts添加新节点;

   5) 新节点启动datanode、nademanager进程,执行命令:① hadoop-daemon.sh start datanode;② yarn-daemon.sh start nodemanager

   6) 在主节点上执行 ./bin/start-balancer.sh均衡数据。

2、删除已有节点

   1) 在name节点的hdfs-site.xml文件中新增:

<property>
    <name>dfs.hosts.exclude</name>
    <value>/usr/local/hadoop/etc/hadoop/excludes</value>
</property>
View Code

   2) 在Name节点的mapred-site.xml文件中新增:

<property>
    <name>mapreduce.jobtracker.hosts.exclude.filename</name>
    <value>/usr/local/hadoop/etc/hadoop/excludes</value>
</property>
View Code

   3) 在/usr/local/hadoop/etc/hadoop下新建文件excludes,内容为要删除节点的hostname,多个换行;

   4) 在Name节点执行命令:① hdfs dfsadmin -refreshNodes;② yarn rmadmin -refreshNodes

   5) 验证,执行命令:hdfs dfsadmin -report,如果被删除节点处于Decommissioned状态,表示关闭成功。