转:http://blog.csdn.net/everl_1/article/details/52303011
非HA弊端
HDFS集群的分布式存储是靠namenode节点(namenode负责响应客户端请求)来实现。在非HA集群中一旦namenode宕机,虽然元数据不会丢失,但整个集群将无法对外提供服务,导致HDFS服务的可靠性不高,这在实际应用场景中显然是不可行的。HA机制
已知导致服务可靠性不高的原因是namenode节点宕机,那么怎么才能避免这个namenode节点宕机呢?一个容易想到的解决方案是部署两台namenode节点,形成主备模式(active/standby模式),这样一旦active节点宕机,standby节点立即切换到active模式。事实上HA机制就是采取的这种方案。要想实现该机制,需要解决以下问题:
一个显然的前提是,两台namenode节点需要保存一致的元数据。
我们知道namenode节点是用来管理这些元数据的,响应客户端请求时(上传)需要增加元数据信息,如果使用主主模式,那么两个节点都将对元数据进行写操作,怎么同步是个很困难的问题。因此,只能有一台机器响应请求,也即处在active状态的节点(可称为主节点),而另一台namenode在主节点正常工作情况下仅用来同步active节点的元数据信息,这个namenode称为备用节点(处在standby状态),可见,要解决的问题主要是怎么同步active节点的元数据信息。
2.怎么同步两个namenode节点的元数据
响应客户端请求的是active节点,因此只有active节点保存了最新的元数据。元数据分为两部分,一部分是刚写入新的元数据(edits),另一部分是合并后的较旧的(fsimage)。HA机制解决同步问题的方法是将active节点新写入的edits元数据放在zookeeper集群上(zookeeper集群主要功能是实现少量数据的分布式同步管理),standby节点在active节点正常情况下只需要将zookeeper集群上edits文件同步到自己的fsimage中就可以。
Hadoop框架为这个集群专门写了个分布式应用qjournal(依赖zookeeper实现),实现qjournal的节点称为journalnode。
3.怎么感知active节点是否宕机,并将standby节点快速切换到active状态?
解决方案是专门在namenode节点上启动一个监控进程,时刻监控namenode的状态。对于处在active状态的namenode,如果发现不正常就向zookeeper集群中写入一些数据。对于处在standby状态的namenode,监控进程从zookeeper集群中读数据,从而感知到active节点是否正常。如果发现异常,监控进程负责将standby状态切换到active状态。这个监控进程在hadoop中叫做zkfc(依赖zookeeper实现)。
4.如何在状态切换时避免brain split(脑裂)?
脑裂:active namenode工作不正常后,zkfc在zookeeper中写入一些数据,表明异常,这时standby namenode中的zkfc读到异常信息,并将standby节点置为active。但是,如果之前的active namenode并没有真的死掉,出现了假死(死了一会儿后又正常了,哈哈,是不是很搞笑),这样,就有两台namenode同时工作了。这种现象称为脑裂。
解决方案:standby namenode感知到主用节点出现异常后并不会立即切换状态,zkfc会首先通过ssh远程杀死active节点的 namenode进程(kill -9 进程号)。但是(这样还不行,惊讶),如果kill指令没有执行成功咋办??如果在一段时间内没有收到执行成功的回执,standby节点会执行一个自定义脚本,尽量保证不会出现脑裂问题!这个机制在hadoop中称为fencing(包括ssh发送kill指令,执行自定义脚本两道保障)
解决上诉问题以后,基本上就实现了hadoop HA 。
HA实现
1.HA集群规划
机名 软件 进程
hadoop01 jdk,hadoop,zookeeper QuorumPeerMain(zookeeper),journalnode,datanode,nodemanager
hadoop02 jdk,hadoop,zookeeper QuorumPeerMain(zookeeper),journalnode,datanode,nodemanager
hadoop03 jdk,hadoop,zookeeper QuorumPeerMain(zookeeper),journalnode,datanode,nodemanager
hadoop04 jdk,hadoop namenode,zkfc(active)
hadoop05 jdk,hadoop namenode,zkfc
hadoop06 jdk,hadoop resourcemanager
hadoop07 jdk,hadoop resourcemanager
(注:datanode,nodemanager一般放到一起。journalnode依赖zookeeper来实现,因此QuorumPeerMain(zookeeper),journalnode必须放一起!)
2.集群安装前的环境检查
时间同步:
在命令行中做如下操作,来安装ntpdate
yum install -y ntp
继续在命令行中操作,进行同步时间
ntpdate 210.72.145.44 #中国国家授时中心
关闭防火墙:
systemctl stop firewalld.service #停止firewall
systemctl disable firewalld.service #禁止firewall开机启动
设置主机名映射(root用户)
机器之间的主机名和IP建立映射关系
192.168.169.129 hadoop01
192.168.169.130 hadoop02
192.168.169.131 hadoop03
192.168.169.132 hadoop04
192.168.169.133 hadoop05
192.168.169.134 hadoop06
192.168.169.135 hadoop07
创建专有的用户(root用户)
一般是建专有的hadoop用户,不在root用户上面搭建
创建组和用户
这里每台虚拟主机都应该有hadoop用户
#先创建组cloud
groupadd cloud
#创建用户并加入组cloud
useradd -g cloud hadoop
#修改用户hadoop的密码
passwd hadoop
将hadoop用户加到sodu列表
1、查看/etc/sudoers的权限
ls -l /etc/sudoers
可以看的是只读权限,如果我们要修改就必须先改变该文件的权限
2、修改权限
chmod 777 /etc/sudoers
3、将hadoop添加root权限
vim /etc/sudoers
在root下加入下面hadoop用户
chmod 440 /etc/sudoers
拷贝/etc/sudoers到其它主机
scp /etc/sudoers hadoop02:/etc/
scp /etc/sudoers hadoop03:/etc/
scp /etc/sudoers hadoop04:/etc/
scp /etc/sudoers hadoop05:/etc/
scp /etc/sudoers hadoop06:/etc/
scp /etc/sudoers hadoop07:/etc/
配置免密码登录(hadoop用户)
切换hadoop用户
su hadoop
进入到当前用户的根目录
cd ~
查看所有文件
ls –la
进入.ssh目录
cd .ssh
生产公钥和私钥(四个回车)
ssh-keygen -t rsa
执行完这个命令后,会生成两个文件id_rsa(私钥)、id_rsa.pub(公钥)
将公钥拷贝到要免登陆的机器上
ssh-copy-id hadoop01
ssh-copy-id hadoop02
ssh-copy-id hadoop03
ssh-copy-id hadoop04
ssh-copy-id hadoop05
ssh-copy-id hadoop06
ssh-copy-id hadoop07
这时会在hadoop02
主机的.ssh/下产生一个名为authorized_keys的文件,这时通过 ssh hadoop02时可以直接免登陆进入主机
如下:
准备软件
在/home/hadoop/下创建cloud文件夹,用来安装相关软件,同时所用安装包放在cloud下的soft-install文件夹下,如:
cd /home/hadoop
mkdir cloud
mkdir soft-install
安装jdk
解压
tar -zxvf jdk-8u91-linux-x64.tar.gz -C /home/hadoop/cloud/
配置环境变量
# 修改配置文件
sudo vi /etc/profile
# 在最后下添加
export JAVA_HOME=/home/hadoop/cloud/jdk1.8.0_91
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
# 刷新配置文件
source /etc/profile
将jdk和环境变量分别拷贝到其他主机上
可以直接将cloud文件夹复制过去
scp -r cloud/ hadoop02:/home/hadoop/
scp -r cloud/ hadoop03:/home/hadoop/
scp -r cloud/ hadoop04:/home/hadoop/
scp -r cloud/ hadoop05:/home/hadoop/
scp -r cloud/ hadoop06:/home/hadoop/
scp -r cloud/ hadoop07:/home/hadoop/
将环境变量拷贝到其他主机下
sudo scp /etc/profile hadoop02:/etc/
sudo scp /etc/profile hadoop03:/etc/
sudo scp /etc/profile hadoop04:/etc/
sudo scp /etc/profile hadoop05:/etc/
sudo scp /etc/profile hadoop06:/etc/
sudo scp /etc/profile hadoop07:/etc/
刷新环境变量
source /etc/profile
安装zookeeper
如果不懂Zookeeper请参考:https://www.ibm.com/developerworks/cn/opensource/os-cn-zookeeper/
下载地址:http://mirrors.hust.edu.cn/apache/zookeeper/
安装
前面我们已经安装的jdk,现在我们在hadoop01、hadoop02、hadoop03上安装Zookeeper
1、解压
tar -zxvf zookeeper-3.4.9.tar.gz -C /home/hadoop/cloud/
2、修改Zookeeper的默认配置 conf/zoo_sample.cfg
mv zoo_sample.cfg zoo.cfg
vi zoo.cfg
配置如下:
#修改dataDir指向我们数据
dataDir=/home/hadoop/cloud/zookeeper-3.4.9/data
#并在最后添加
server.1=hadoop01:2888:3888
server.2=hadoop02:2888:3888
server.3=hadoop03:2888:3888
3、在/home/hadoop/cloud/zookeeper-3.4.9/目录下创建data文件夹
mkdir data
4、在data文件夹下创建myid文件指明本机id
vi myid
id 分别对应为hadoop01为1,hadoop02为2,hadoop03为3 后面我们再统一拷贝
5、复制zookeeper-3.4.8到hadoop02、hadoop03机器上并修改相应的myid
scp -r zookeeper-3.4.9/ hadoop02:/home/hadoop/cloud/zookeeper-3.4.9/
scp -r zookeeper-3.4.9/ hadoop03:/home/hadoop/cloud/zookeeper-3.4.9/
启动Zookeeper
分别在hadoop01、hadoop02、hadoop03上启动Zookeeper
#执行/home/hadoop/cloud/zookeeper-3.4.9/bin目录下的脚本启动
./zkServer.sh start
查看zookeeper的状态
./zkServer.sh status
其实我们可以找到leader 然后stop,会发现Zookeeper会立即切换Leader
安装hadoop
安装(现在hadoop01安装,然后复制其他机器)
解压
tar -zxvf hadoop-2.7.3.tar.gz -C /home/hadoop/cloud/
# 修改配置文件
sudo vi /etc/profile
# 在最后下添加
export HADOOP_HOME=/home/hadoop/cloud/hadoop-2.7.3
export PATH=$PATH:$HADOOP_HOME/bin
# 刷新配置文件
source /etc/profile
测试:
which hadoop
修改配置文件(6个)
#hadoop2.x的配置文件全部在$HADOOP_HOME/etc/hadoop下
cd /home/hadoop/cloud/hadoop-2.7.3/etc/hadoop
hadoop-env.sh
# The java implementation to use.
export JAVA_HOME=/home/hadoop/cloud/jdk1.8.0_91
core-site.xml
<configuration>
<!-- 指定hadoop运行时产生文件的存储路径 -->
<property>
<name>hadoop.tmp.dir</name>
<value>/home/hadoop/cloud/hadoop-2.7.3/tmp</value>
</property>
<!-- 指定hdfs的nameservice为ns1 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://ns1</value>
</property>
<!-- 指定zookeeper地址,多个用,分割 -->
<property>
<name>ha.zookeeper.quorum</name>
<value>hadoop01:2181,hadoop02:2181,hadoop03:2181</value>
</property>
</configuration>
hdfs-site.xml
<configuration>
<!-- dfs.nameservices 命名空间的逻辑名称,多个用,分割 -->
<property>
<name>dfs.nameservices</name>
<value>ns1</value>
</property>
<!-- 指定ns1下有两个namenode,分别是nn1,nn2 -->
<property>
<name>dfs.ha.namenodes.ns1</name>
<value>nn1,nn2</value>
</property>
<!-- 指定nn1的RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.ns1.nn1</name>
<value>hadoop04:8020</value>
</property>
<!-- 指定nn1的HTTP通信地址 -->
<property>
<name>dfs.namenode.http-address.ns1.nn1</name>
<value>hadoop04:50070</value>
</property>
<!-- 指定nn2的RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.ns1.nn2</name>
<value>hadoop05:8020</value>
</property>
<!-- 指定nn2的HTTP通信地址 -->
<property>
<name>dfs.namenode.http-address.ns1.nn2</name>
<value>hadoop05:50070</value>
</property>
<!-- 指定namenode的元数据存放的Journal Node的地址,必须基数,至少三个 -->
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://hadoop01:8485;hadoop02:8485;hadoop03:8485/ns1</value>
</property>
<!--这是JournalNode进程保持逻辑状态的路径。这是在linux服务器文件的绝对路径-->
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/home/hadoop/cloud/hadoop-2.7.3/journal/</value>
</property>
<!-- 开启namenode失败后自动切换 -->
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
<!-- 配置失败自动切换实现方式 -->
<property>
<name>dfs.client.failover.proxy.provider.ns1</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
<!-- 配置隔离机制方法,多个机制用换行分割 -->
<property>
<name>dfs.ha.fencing.methods</name>
<value>
sshfence
shell(/bin/true)
</value>
</property>
<!-- 使用sshfence隔离机制时需要ssh免登陆 -->
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/home/hadoop/.ssh/id_rsa</value>
</property>
<!-- 配置sshfence隔离机制超时时间30秒 -->
<property>
<name>dfs.ha.fencing.ssh.connect-timeout</name>
<value>30000</value>
</property>
</configuration>
mapred-site.xml.template
需要重命名: mv mapred-site.xml.template mapred-site.xml
<configuration>
<!-- 通知框架MR使用YARN -->
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>
yarn-site.xml
<configuration>
<!-- 开启RM高可用 -->
<property>
<name>yarn.resourcemanager.ha.enabled</name>
<value>true</value>
</property>
<!-- 指定RM的cluster id -->
<property>
<name>yarn.resourcemanager.cluster-id</name>
<value>yrc</value>
</property>
<!-- 指定RM的名字 -->
<property>
<name>yarn.resourcemanager.ha.rm-ids</name>
<value>rm1,rm2</value>
</property>
<!-- 分别指定RM的地址 -->
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>hadoop06</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm2</name>
<value>hadoop07</value>
</property>
<!-- 指定zk集群地址 -->
<property>
<name>yarn.resourcemanager.zk-address</name>
<value>hadoop01:2181,hadoop02:2181,hadoop03:2181</value>
</property>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
</configuration>
修改/home/hadoop/cloud/hadoop-2.7.3/etc/hadoop/slaves文件
要在hadoop4上启动hdfs,按照集群配置,需要指定datanode在hadoop01,hadoop02,hadoop3上
要在hadoop6上启动yarn,按照集群配置,需要指定nodemanager在hadoop01,hadoop02,hadoop3上。
#子节点的位置
hadoop01
hadoop02
hadoop03
并在 hadoop-2.7.3文件下 创建tmp文件:
mkdir tmp
scp -r hadoop-2.7.3/ hadoop02:/home/hadoop/cloud/hadoop-2.7.3/
scp -r hadoop-2.7.3/ hadoop03:/home/hadoop/cloud/hadoop-2.7.3/
scp -r hadoop-2.7.3/ hadoop04:/home/hadoop/cloud/hadoop-2.7.3/
scp -r hadoop-2.7.3/ hadoop05:/home/hadoop/cloud/hadoop-2.7.3/
scp -r hadoop-2.7.3/ hadoop06:/home/hadoop/cloud/hadoop-2.7.3/
scp -r hadoop-2.7.3/ hadoop07:/home/hadoop/cloud/hadoop-2.7.3/
将环境变量拷贝到其他主机下
sudo scp /etc/profile hadoop02:/etc/
sudo scp /etc/profile hadoop03:/etc/
sudo scp /etc/profile hadoop04:/etc/
sudo scp /etc/profile hadoop05:/etc/
sudo scp /etc/profile hadoop06:/etc/
sudo scp /etc/profile hadoop07:/etc/
刷新环境变量
source /etc/profile
启动
启动的时候注意启动顺序
1、启动zookeeper(在hadoop01、02、03)
./zkServer.sh start
查看zookeeper状态:./zkServer.sh status, 正确的状态是一个leader,两个follower。
2、启动journal node(在hadoop01、02、03)
#hadoop-2.7.3/sbin下
./sbin/hadoop-daemon.sh start journalnode
启动成功后会多出一个JournalNode进程。
3.格式化HDFS
在hadoop04上执行格式化指令:./bin/hadoop namenode -format
并把/home/hadoop/cloud/hadoop-2.7.3/tmp 文件夹拷贝到另一台namenode的目录下
scp -r /home/hadoop/cloud/hadoop-2.7.3/tmp hadoop05:/home/hadoop/cloud/hadoop-2.7.3/
4.格式化zkfc
在hadoop4上执行格式化指令:./bin/hdfs zkfc -formatZK
格式化成功后会在zookeeper集群建立新的文件路径(该路径下存放zkfc监控namenode节点的信息)
5、启动zkfc来监控NN状态(在hadoop04、05)
./sbin/hadoop-daemon.sh start zkfc
6、启动HDFS(namenode)(在hadoop04即可)
#hadoop-2.7.3/sbin下
./sbin/start-dfs.sh
7、启动YARN
在hadoop06上执行./sbin/start-yarn.sh
在hadoop07上执行./sbin/yarn-daemon.sh start resourcemanager
通过浏览器测试如下:
http://192.168.169.132:50070/
http://192.168.169.133:50070/
可以看出hadoop04的namenode是处于一种standby状态,那么hadoop05应该是处于active状态
hdfs haadmin -getServiceState nn1
hdfs haadmin -getServiceState nn2
把hadoop05(192.168.169.133)的namenode 进程kill掉
hdfs haadmin -getServiceState nn1
hdfs haadmin -getServiceState nn2
可以看出hadoop04的namenode是处于一种active状态,hadoop05不能访问
重新启动hadoop05的namenode
./sbin/hadoop-daemon.sh start namenode
hadoop05会变成standby状态
查看YARN的状态
http://192.168.169.134:8088/
输入:http://192.168.169.135:8088/ 会跳转到 http://hadoop06:8088/