一、namenode高可用:

namenode存储了数据和地址的映射(fsimage),当节点发生故障的时候,
备份节点应该和故障节点具有相同的数据,因此有两种方式实现高可用。
1、使用NFS:将数据放在一个共享的目录下。
2、使用QJM:准备两台namenode,一个用于备份,
datanode向namenode回复数据与地址的映射时,
不仅向namenode回复,也要向备份的namenode回复。
两个namenode节点,一个处于活跃状态(active)用于处理请求,(active仅有一个)
另外一个namenode节点处于备份状态(standby)仅备份数据。
active节点是通过zookeeper选举出来的。

fsedits数据变更日志的备份(同步):active向JNS(JournalNodes)中写数据,standby从JNS中读数据。

二、yarn高可用:(resourcemanager)

原理和namenode高可用相同。
也要使用zookeeper集群

三、高可用配置:

1、主机准备:
	192.168.1.60  nn01		角色:namenode、resourcemanager
	192.168.1.66  nn02		角色:namenode、resourcemanager
	192.168.1.61  node1     角色:datanode、zookeeper、journalnode
	192.168.1.62  node2     角色:datanode、zookeeper、journalnode
	192.168.1.63  node3     角色:datanode、zookeeper、journalnode
	# 保证nn01连接所有主机都不需要密码(包括本机)
	# 保证nn02连接node1、node2、node3、nn02不需要密码
	# 修改/etc/hosts,同步到所有主机


2、修改配置文件(在nn01上执行,然后同步到所有主机):
	①、core-site.xml
	vim /usr/local/hadoop/etc/hadoop/core-site.xml
	<configuration>
		<!-- 核心配置文件 -->
		<!-- http://hadoop.apache.org/docs/r2.7.7/hadoop-project-dist/hadoop-common/core-default.xml 找对应参数 -->	
		<property>
			<name>fs.defaultFS</name>
			<value>hdfs://namenodeGroup</value> 
			<!-- 
			由于由两个namenode,active(活动节点)是被选举出来的,
			需要把两个namenode定义成一个组,这里写namenode组的名字 
			-->
			<!-- <description> 使用什么样的存储,file:///表示本地存储,配置伪分布式;hdfs://nameNode的ip </description>  -->
		</property>
	
		<property>
			<name>hadoop.tmp.dir</name>
			<value>/var/hadoop</value>
			<!-- <description> hadoop核心数据存储目录,一般是单独的磁盘所挂载的目录 </description>  -->
		</property>
	
		<property>
			<!-- zookeeper集群的地址,配3个,自动连接第一个,如果出现问题自动连接下一个 -->
			<name>ha.zookeeper.quorum</name>
			<value>node1:2181,node2:2181:node3:2181</value>
		</property>
	
		<property>
			<!-- nfs代理用户的组,nfsuser是设置的代理用户 -->
			<name>hadoop.proxyiser.nfsuser.groups</name>
			<value>*</value>
		</property>
	
		<property>
			<!-- nfs代理用户的主机,nfsuser是设置的代理用户 -->
			<name>hadoop.proxyiser.nfsuser.hosts</name>
			<value>*</value>
		</property>
	</configuration>


	②、hdfs-site.xml
	vim /usr/local/hadoop/etc/hadoop/hdfs-site.xml
	<configuration>
		<!-- HDFS配置文件 -->
	
		<!-- http://hadoop.apache.org/docs/r2.7.7/hadoop-project-dist/hadoop-hdfs/hdfs-default.xml 找对应参数 -->	
		
		<property>
			<!-- 定义,namenode组的名称,core-site.xml中使用就在这里定义 -->
			<name>dfs.nameservices</name>
			<value>namenodeGroup</value>
		</property>
	
		<property>
			<!-- 定义namenodeGroup组中的角色,相当于为主机起的名字 -->
			<name>dfs.ha.namenodes.namenodeGroup</name>
			<value>nn1,nn2</value> <!-- 角色名,自定义 -->
		</property>
	
		<property>
			<!-- 定义角色对应的主机  角色nn1对应nn01主机 -->
			<name>dfs.namenode.rpc-address.namenodeGroup.nn1</name>
			<value>nn01:8020</value> <!-- 角色对应的主机以及端口 -->
		</property>
	
		<property>
			<!-- 定义角色对应的主机  角色nn2对应nn02主机 -->
			<name>dfs.namenode.rpc-address.namenodeGroup.nn2</name>
			<value>nn02:8020</value> <!-- 角色对应的主机以及端口 -->
		</property>
	
		<property>
			<!-- 定义namenode,nn1对应的主机的namenode是nn01的50070 -->
			<name>dfs.namenode.http-address.namenodeGroup.nn1</name>
			<value>nn01:50070</value>
		</property>
	
		<property>
			<!-- 定义namenode,nn2对应的主机的namenode是nn02的50070 -->
			<name>dfs.namenode.http-address.namenodeGroup.nn2</name>
			<value>nn02:50070</value>
		</property>
	
		<property>
			<!-- JNS,用于同步fsedits数据变更日志 -->
			<name>dfs.namenode.shared.edits.dir</name>
			<value>qjournal://node1:8485;node2:8485;node3:8485/fsedits_log</value>
		</property>
	
		<property>
			<!-- 保存数据变更日志的目录 -->
			<name>dfs.journalnode.edits.dir</name>
			<value>/var/hadoop/journal</value>
		</property>
	
		<property>
			<!-- 高可用软件,zookeeperFailoverController -->
			<name>dfs.client.failover.proxy.provider.namenodeGroup</name>
			<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
		</property>
	
		<property>
			<!-- 管理standby备份主机的方法,ssh -->
			<name>dfs.ha.fencing.methods</name>
			<value>sshfence</value>
		</property>
	
		<property>
			<!-- 秘钥存放位置 -->
			<name>dfs.ha.fencing.ssh.private-key-files</name>
			<value>/root/.ssh/id_rsa</value>
		</property>
	
		<property>
			<!-- 故障时,是否自主切换主从 -->
			<name>dfs.ha.automatic-failover.enabled</name>
			<value>true</value>
		</property>
	
		<property>
			<name>dfs.replication</name>
			<value>3</value>
			<!-- <description> 副本策略,数据存几份,3份中有2份备份数据 </description>  -->
		</property>
	
		<property>
			<!-- 为了删除datanode节点, 写在这个文件中的主机在删除前会自动迁移数据-->
			<name>dfs.hosts.exclude</name>
			<value>/usr/local/hadoop/etc/hadoop/exclude</value>
		</property>
	</configuration>


	③、yarn-site.xml
	vim /usr/local/hadoop/etc/hadoop/yarn-site.xml
	<configuration>
		<!-- Map-Reduce配置文件 -->
	
		<!-- http://hadoop.apache.org/docs/r2.7.7/hadoop-yarn/hadoop-yarn-common/yarn-default.xml 找对应参数 -->	
		
		<property>
			<!-- 开启resourcemanager高可用 -->
			<name>yarn.resourcemanager.ha.enabled</name>
			<value>true</value>
		</property>
	
		<property>
			<!-- 定义两个角色,代表不同的resourcemanager主机 -->
			<name>yarn.resourcemanager.ha.rm-ids</name>
			<value>rm1,rm2</value>
		</property>
	
		<property>
			<!-- resourcemanager故障时自动切换 -->
			<name>yarn.resourcemanager.recovery.enabled</name>
			<value>true</value>
		</property>
	
		<property>
			<!-- resourcemanager使用管理软件 -->
			<name>yarn.resourcemanager.store.class</name>
			<value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value>
		</property>
	
		<property>
			<!-- 指定zookeeper集群 -->
			<name>yarn.resourcemanager.zk-address</name>
			<value>node1:2181,node2:2181,node3:2181</value>
		</property>
	
		<property>
			<!-- resourcemanager集群的id -->
			<name>yarn.resourcemanager.cluster-id</name>
			<value>yarn-ha</value>
		</property>
	
		<property>
			<!-- 定义角色对应的主机 -->
			<name>yarn.resourcemanager.hostname.rm1</name>
			<value>nn01</value>
		</property>
	
		<property>
			<!-- 定义角色对应的主机 -->
			<name>yarn.resourcemanager.hostname.rm2</name>
			<value>nn02</value>
		</property>
	
		<property>
			<name>yarn.nodemanager.aux-services</name>
			<value>mapreduce_shuffle</value> 	<!-- 官方提供的框架 -->
			<!-- <description> nodemanager使用什么计算框架,计算框架的名称,问开发人员所使用的框架是什么 </description>  -->
		</property>
	</configuration>

# 同步到nn02、node1、node2、node3上
for i in {61..63} 66; do rsync -aSH --delete /usr/local/hadoop/ 192.168.1.$i:/usr/local/hadoop  -e 'ssh' & done


3、验证

# 启动zookeeper集群(node1、node2、node3都要进行操作)
/usr/local/zookeeper/bin/zkServer.sh start

# 初始化zookeeper集群(在nn01上操作)
/usr/local/hadoop/bin/hdfs zkfc -formatZK	# 出现Successfully即为成功

# 启动journalnode服务(在node1、node2、node3上操作)
/usr/local/hadoop/sbin/hadoop-daemon.sh start journalnode

# 格式化journalnode(在nn01上执行,先启动才可以初始化)
/usr/local/hadoop//bin/hdfs  namenode  -format		# 出现Successfully即为成功

# 为了保证nn01和nn02的数据完全一致,需要将nn01的数据同步到nn02(我这里是在nn02上进行的操作)
rsync -aSH  nn01:/var/hadoop/  /var/hadoop/

# 初始化JNS(nn01上操作)
/usr/local/hadoop/bin/hdfs namenode -initializeSharedEdits	# 出现Successfully即为成功

# 停止 journalnode 服务(node1、node2、node3)
/usr/local/hadoop/sbin/hadoop-daemon.sh stop journalnode

# 启动hadoop集群(在nn01上操作)
/usr/local/hadoop/sbin/start-all.sh

# 启动resourcemanager热备(nn02上操作)
/usr/local/hadoop/sbin/yarn-daemon.sh start resourcemanager

# 查看集群状态(nn01上执行)
# namenode、resourcemanager的active和standby都是选举产生的
/usr/local/hadoop/bin/hdfs haadmin -getServiceState nn1		# namenode
/usr/local/hadoop/bin/hdfs haadmin -getServiceState nn2

/usr/local/hadoop/bin/yarn rmadmin -getServiceState rm1		# resourcemanager
/usr/local/hadoop/bin/yarn rmadmin -getServiceState rm2

# 查看节点是否加入
/usr/local/hadoop/bin/hdfs dfsadmin -report
/usr/local/hadoop/bin/yarn  node  -list


这里假设nn01是namenode和resourcemanager的active节点
关闭nn01上对应的服务服务(模拟故障),则nn02会变成active
如果nn01故障恢复,则nn01则变为standby