通过Journal Node实现NameNode集群启动时,可以通过动手方式来实现NameNodeHA也可以通过自动方式实现NameNodeHA.
NameNode HA实现可以同时启动2个NameNode,这些NameNode只有一个是active的,另一个属于standby状态。active状态意味着提供服务,standby状态意味着处于休眠状态,只进行数据同步,进行数据合并工作,时刻准备着提供服务。
手动实现NameNode原理如下图所示:
实现NameNode高可用大体步骤如下:
以上手动方式需要我们手动将Standby NamNode切换成Active NameNode,对于高可用场景时效性较低。那么可以通过zookeeper进行协调自动实现NameNode HA,实现代码通过Zookeeper来检测Activate NameNode节点是否挂点,如果挂掉立即将Standby NameNode切换成Active NameNode,原理如下:
ZooKeeper Failover Controller:监控NameNode健康状态,并向Zookeeper注册NameNode。NameNode挂掉后,ZKFC为NameNode竞争锁,获得ZKFC 锁的NameNode变为active。
手动切换NameNode场景一般用于HDFS升级场合,绝大多数我们都是基于Zookeeper来实现自动NameNode HA切换。
环境中要关闭防火墙,防止后续查看web页面访问受阻。
systemctl stop firewalld #临时关闭
systemctl disable firewalld #禁止开机启动
systemctl status firewalld #查看防火墙是否关闭
输入下面命令进入配置文件
vi etc/sysconfig/network-scripts/ifcfg-ens33
修改配置文件
TYPE=Ethernet
PROXY_METHOD=none
BROWSER_ONLY=no
# 将动态IP设置为static(静态)
BOOTPROTO=static
DEFROUTE=yes
IPV4_FAILURE_FATAL=no
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
IPV6_ADDR_GEN_MODE=stable-privacy
NAME=ens33
UUID=dea19265-ddfe-4de3-ba50-c627093fd7c0
DEVICE=ens33
#系统启动时是否激活网卡 这里改为yes
ONBOOT=yes
#IP地址可以自定义,必须和VMnet8的子网在同一网段
IPADDR=192.168.81.10
#网关,这个值与我们在NAT设置的网关一样
GATEWAY=192.168.81.2
#子网掩码
NETMASK=255.255.255.0
#DNS的值也跟设置的的网关一样
DNS1=192.168.81.2
PREFIX=24
#表示该接口将通过该配置文件进行设置,而不是通过网络管理器进行管理
NM_CONTROLLED=no
DNS=8.8.8.8
DNS2=114.114.114.114
配置主机名和主机映射
进入后删除原配置文件输入要更改的主机名
vim /etc/hostname
删除原配置文件,输入命令后进入文件
vim /etc/hosts
修改为静态ip地址和对应主机名,如下
192.168.81.142 hadoop3
192.168.81.141 hadoop2
192.168.81.140 hadoop1
重启网络
systemctl start network.service
注意:配置完成后其他节点也要按照如上所述进行配置,但是ip地址不能相同
此时能ping通百度和其他节点即代表静态配置完成
ping www.baidu.com
ping 其他节点映射或IP地址
在Hadoop集群中,需要各个节点之间是有通信的,这里需要设置节点之间免密通信,为了后期操作方便,三台服务器之间需互相均可以免密登录。
ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa
[root@hadoop1.ssh] ssh-copy-id hadoop1
[root@hadoop2 .ssh] ssh-copy-id hadoop2
[root@hadoop3 .ssh] ssh-copy-id hadoop3
[root@hadoop1 .ssh]scp ~/.ssh/authorized_keys hadoop2:`pwd`
[root@hadoop1 .ssh]scp ~/.ssh/authorized_keys hadoop3:`pwd`
经过以上步骤,可以测试两两节点已将完成免密配置。
HDFS 安装需要jdk,这里在hadoop1-hadoop3每台节点需要安装jdk8。
hadoop1-hadoop3节点上执行如下命令,创建目录:
mkdir -p /opt/app
将jdk-8u181-linux-x64.rpm上传到hadoop1 /opt/app目录下
将/opt/app/下的jdk*.rpm scp到hadoop2、hadoop3的对应目录中
scp jdk-8u181-linux-x64.rpm hadoop2:/opt/app
scp jdk-8u181-linux-x64.rpm hadoop3:/opt/app
在hadoop1、hadoop2、hadoop3上安装jdk并配置profile文件
rpm -ivh jdk-8u181-linux-x64.rpm
hadoop1上修改环境变量
java
vim /etc/profile
export JAVA_HOME=/opt/app/java/jdk1.8.0_181-amd64
export PATH=$PATH:$JAVA_HOME/bin
初始化使修改的环境变量生效
source /etc/profile
将hadoop1的/etc/profile拷贝到hadoop2、hadoop3上并执行 source /etc/profile,完成JDK安装。
scp /etc/profile hadoop[23]:`pwd`
从上图中,我们可以很明显地看出现有的HDFS数据管理,数据存储2层分层的结构。也就是说,所有关于存储数据的信息和管理是放在NameNode这边,而真实数据的存储则是在各个DataNode下。而这些隶属于同一个NameNode,所管理的数据都是在同一个命名空间下的“NS”,以上结构是一个NameNode管理集群中所有元数据信息。
举个例子,一般1GB内存放1,000,000 block元数据。200个节点的集群中每个节点有24TB存储空间,block大小为128MB,能存储大概4千万个block(或更多):200241024*1024M/128 约为4千万。100万需要1G内存存储元数据,4千万大概需要40G内存存储元数据,假设节点数如果更多、存储数据更多的情况下,需要的内存也就越多。
通过以上例子可以看出,单NameNode的架构使得 HDFS 在集群扩展性和性能上都有潜在的问题,当集群大到一定程度后,NameNode进程使用的内存可能会达到上百G,NameNode 成为了性能的瓶颈。这时该怎么办?元数据空间依然还是在不断增大,一味调高NameNode的JVM大小绝对不是一个持久的办法,这时候就诞生了 HDFS Federation 的机制。
HDFS Federation是解决namenode内存瓶颈问题的水平横向扩展方案。Federation中文意思为联邦、联盟,HDFS Federation是NameNode的Federation,也就是会有多个NameNode。这些 namenode之间是联合的,他们之间相互独立且不需要互相协调,各自分工,管理自己的区域。分布式的datanode被用作通用的数据块存储存储设备。每个datanode要向集群中所有的namenode注册,且周期性地向所有 namenode 发送心跳和块报告,并执行来自所有 namenode的命令。
HBase主要用ZooKeeper来实现HA选举与主备集群主节点的切换、系统容错、RootRegion管理、Region状态管理和分布式SplitWAL任务管理,所以我们必须要配置ZoopKeeper集群。
1.1.3.1 集群配置准备工作
我们这里使用3.4.10,选择与hadoop相对应的zookeeper版本,下载网址:https://archive.apache.org/dist/zookeeper/zookeeper-3.4.10/
在hadoop1、hadoop2和hadoop3三个节点上部署Zookeeper。
# 解压Zookeeper安装包到/opt/app/目录下
tar -zxvf zookeeper-3.4.10.tar.gz -C /opt/app/
# 在/opt/app/zookeeper-3.4.10/这个目录下创建zkData
mkdir -p zkData
1.1.3.2配置文件
配置zoo.cfg文件
重命名/opt/app/zookeeper-3.4.10/conf这个目录下的zoo_sample.cfg为zoo.cfg
mv zoo_sample.cfg zoo.cfg
# The number of milliseconds of each tick
# 通信心跳数,服务器心跳时间,单位毫秒
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
# initLimit:LF初始通信时限
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
# 同步通信时限
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
#安装数据目录,最好不要用默认值
dataDir=/opt/app/zookeeper/zkData
# the port at which the clients will connect
#默认客户端端口号
clientPort=2181
#######################集群配置##########################
server.1=hadoop1:2888:3888
server.2=hadoop2:2888:3888
server.3=hadoop3:2888:3888
参数解读
Server.A=B:C:D。A:是一个数字,表示这个是第几号服务器;B:是这个服务器的IP地址;C:是这个服务器与集群中的Leader服务器交换信息的端口;D:是万一集群中的Leader服务器挂了,需要一个端口来重新进行选举,选出一个新的Leader,而这个端口就是用来执行选举时服务器相互通信的端口。 集群模式下配置一个文件myid,这个文件在dataDir目录下,这个文件里面有一个数据就是A的值,Zookeeper启动时读取此文件,拿到里面的数据与zoo.cfg里面的配置信息比较从而判断到底是哪个server。
配置myid
在/opt/app/zookeeper-3.4.10/zkData目录下创建一个myid的文件,在文件中添加与server对应的编号:如1
echo "1" > myid
1.1.3.1 拷贝和启动
scp -r zookeeper-3.4.10/ root@hadoop2:/opt/app/
scp -r zookeeper-3.4.10/ root@hadoop3:/opt/app/
# 并分别修改myid文件中内容为2、3
[root@hadoop1 zookeeper-3.4.10]# bin/zkServer.sh start
[root@hadoop2 zookeeper-3.4.10]# bin/zkServer.sh start
[root@hadoop3 zookeeper-3.4.10]# bin/zkServer.sh start
使用命令后,只要所有结果里面出现 一个leader多个follower就表示集群基本成功
bin/zkServer.sh status
scp -r zookeeper-3.4.10/ hadoop@hadoop3:/opt/app/
在前面课程中,我们知道Hadoop集群中有Namenode,SecondaryNameNode,DataNode各个角色,这里我们需要搭建Hadoop集群,在我们现有Linux集群中节点对应角色划分如下:
节点 | NN | DN | ZK | ZKFC | JN |
---|---|---|---|---|---|
mynode1 | ★ | ★ | ★ | ★ | ★ |
mynode2 | ★ | ★ | ★ | ★ | ★ |
mynode3 | ★ | ★ | ★ |
找到这个路径下C:\Windows\System32\drivers\etc的hosts,打开,添加如
下映射:
192.168.179.13 hadoop1
192.168.179.14 hadoop2
192.168.179.15 hadoop3
添加的目的是为了以后要在浏览器中查看HDFS中的数据信息,需要通过IP地址加上端口进行访问,添加完成之后我们可以直接通过节点名称和端口进行访问。(这一步不配,就直接使用ip地址)
快照名称为zookeeper完成。为什么要拍摄快照,因为以后我们搭建HDFS HA的时候要使用快照,在关键位置快照,可以省下很多问题
我们安装Hadoop2.7.2,此版本目前是比较稳定的版本,搭建HDFS集群前,首先需要在官网下载安装包,地址如下:https://archive.apache.org/dist/hadoop/common/hadoop-2.7.2/,进入到网站之后,选择二进制的下载。
下载完成安装包后,上传到hadoop1节点的/opt/app目录下
将下载好的安装包上传到/opt/app目录下,并解压
cd /opt/app
tar -zxvf ./hadoop-2.7.2.tar.gz
解压完成之后,配置Hadoop的环境变量,方便后期操作HDFS。
[root@hadoop1 app]# vim /etc/profile
export HADOOP_HOME=/opt/app/hadoop-2.7.2
export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin:
使配置生效
source /etc/profile
#完成之后输入hd 然后按一下tab,如下图说明配置成功
由于通过SSH远程启动进程的时候默认不会加载/etc/profile设置,JAVA_HOME变量就加载不到,而Hadoop启动需要读取到JAVA_HOME信息,所有这里需要手动指定。在对应的$HADOOP_HOME/etc/hadoop路径中,找到hadoop-env.sh文件加入以下配置(大概在54行有默认注释配置的JAVA_HOME):
export JAVA_HOME=/opt/app/java/jdk1.8.0_181-amd64/
3.5 配置
进入 $HADOOP_HOME/etc/hadoop路径下,修改slaves配置文件,(3.0之后的hadoop此文件改名为wroks)删掉localhost并加入以下内容:
hadoop1
hadoop2
hadoop3
进入 $HADOOP_HOME/etc/hadoop路径下,修改hdfs-site.xml文件,指定NN1,NN2的位置:
<configuration>
<property>
<name>dfs.nameservicesname>
<value>myclustervalue>
property>
<property>
<name>dfs.ha.namenodes.myclustername>
<value>nn1,nn2value>
property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn1name>
<value>hadoop1:9000value>
property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn2name>
<value>hadoop2:9000value>
property>
<property>
<name>dfs.namenode.http-address.mycluster.nn1name>
<value>hadoop1:50070value>
property>
<property>
<name>dfs.namenode.http-address.mycluster.nn2name>
<value>hadoop2:50070value>
property>
<property>
<name>dfs.namenode.shared.edits.dirname>
<value>qjournal://hadoop1:8485;hadoop2:8485;hadoop3:8485/myclustervalue>
property>
<property>
<name>dfs.ha.fencing.methodsname>
<value>sshfencevalue>
property>
<property>
<name>dfs.ha.fencing.ssh.private-key-filesname>
<value>/root/.ssh/id_rsavalue>
property>
<property>
<name>dfs.journalnode.edits.dirname>
<value>/opt/app/ha/hadoop/data/jnvalue>
property>
<property>
<name>dfs.permissions.enablename>
<value>falsevalue>
property>
<property>
<name>dfs.client.failover.proxy.provider.myclustername>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvidervalue>
property>
<property>
<name>dfs.ha.automatic-failover.enabledname>
<value>truevalue>
property>
configuration>
进入 $HADOOP_HOME/etc/hadoop路径下,修改core-site.xml文件
<configuration>
<property>
<name>fs.defaultFSname>
<value>hdfs://myclustervalue>
property>
<property>
<name>hadoop.tmp.dirname>
<value>/opt/app/ha/hadoop272/data/tmpvalue>
property>
<property>
<name>ha.zookeeper.quorumname>
<value>hadoop1:2181,hadoop2:2181,hadoop3:2181value>
property>
configuration>
注意:Hadoop框架自身集成了很多第三方的JAR包库。Hadoop框架自身启动或者在运行用户的MapReduce等应用程序时,会优先查找Hadoop预置的JAR包。这样的话,当用户的应用程序使用的第三方库已经存在于Hadoop框架的预置目录,但是两者的版本不同时,Hadoop会优先为应用程序加载Hadoop自身预置的JAR包,这种情况的结果是往往会导致应用程序无法正常运行,使用下面的命令,获取jar包路径,添加到配置文件中
hadoop classpath
<configuration>
<!-- Site specific YARN configuration properties -->
<!-- 设置该属性通知NodeManager需要实现名为mapreduce.shuffle的辅助服务-->
<property>
<name>yarn.resourcemanager.hostname</name>
<value>hadoop2</value>
</property>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.log-aggregation-enable</name>
<value>true</value>
</property>
<property>
<name>yarn.log-aggregation.retain-seconds</name>
<value>604800</value>
</property>
<!-- 配置日志聚集属性-->
<property>
<name>yarn.log-aggregation-enable</name>
<value>true</value>
</property>
<!-- 配置日志聚集的时间 -->
<property>
<name>yarn.log-aggregation.retain-seconds</name>
<value>604800</value>
</property>
<!-- 指定jar路径 -->
<property>
<name>yarn.application.classpath</name>
<value>/opt/app/hadoop272/etc/hadoop:/opt/app/hadoop272/share/hadoop/common/lib/*:/opt/app/hadoop272/share/hadoop/common/*:/opt/app/hadoop272/share/hadoop/hdfs:/opt/app/hadoop272/share/hadoop/hdfs/lib/*:/opt/app/hadoop272/share/hadoop/hdfs/*:/opt/app/hadoop272/share/hadoop/yarn/lib/*:/opt/app/hadoop272/share/hadoop/yarn/*:/opt/app/hadoop272/share/hadoop/mapreduce/lib/*:/opt/app/hadoop272/share/hadoop/mapreduce/*:/opt/app/hadoop272/contrib/capacity-scheduler/*.jar
进入 $HADOOP_HOME/etc/hadoop路径下cp一份mapred-site.xml.template为mapred-site.xml
cp mapred-site.xml.template mapred-site.xml
<configuration>
<!-- 配置MapReduce的计算框架,可以是local,classic,yarn,如果不配置,默认是local -->
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
<!-- 配置历史服务器的地址 -->
<property>
<name>mapreduce.jobhistory.address</name>
<value>192.168.81.140:10020</value>
</property>
</configuration>
进入到/opt/app/hadoop-2.7.2/sbin/文件夹下,有一个start-all.sh文件,可以启动所有节点,实际上调用了start-dfs.sh。下面是配置操作各个不同节点角色的用户。
vim /opt/app/hadoop-2.7.2/sbin/start-dfs.sh
vim /opt/app/hadoop-2.7.2/sbin/stop-dfs.sh
HDFS_DATANODE_USER=root
HDFS_DATANODE_SECURE_USER=hdfs
HDFS_NAMENODE_USER=root
HDFS_SECONDARYNAMENODE_USER=root
直接使用命令发送到其他节点
scp -r ./hadoop-2.7.2 hadoop2:/opt/app
scp -r ./hadoop-2.7.2 hadoop3:/opt/app
将安装包发送到hadoop2-hadoop3每台节点上,这里由于Hadoop安装包文件比较多,如果直接发送时间较长,这里可以先将之打成压缩包:
[root@hadoop1 app]# tar -zcvf hadoop-2.7.2-config.tar.gz hadoop-2.7.2/
将/opt/app/hadoop-2.7.2-config.tar.gz 使用以下命令发送到hadoop2、hadoop3的对应目录中:
scp ./hadoop-2.7.2-config.tar.gz hadoop2:`pwd`
scp ./hadoop-2.7.2-config.tar.gz hadoop3:`pwd`
hadoop2、hadoop3分别解压,并分别在各个节点上配置Hadoop环境变量,直接复制粘贴hadoop1中的hadoop配置即可。
tar -zxvf hadoop-2.7.2-config.tar.gz
注意:如果是安装的mini版本的centos,里面会缺一个fuser的命令,错误可以在logs/hadoop-root-zkfc-s1.log发现下面的错误:PATH=$PATH:/sbin:/usr/sbin fuser -v -k -n tcp 9000 via ssh: bash: fuser: command not found
在三台机上面要安装这个fuser命令即可,如下
yum install -y psmisc
注意:如果是二次格式化,要删除hadoop2.7.2文件下的data和logs文件,防止脏数据导致namenode和datanode id不匹配。如果为第一次格式化,那么则不需要做此步操作
rm -r data logs
在各个JournalNode节点上,输入以下命令启动journalnode服务
sbin/hadoop-daemon.sh start journalnode
格式化,可以在格式化的时候创建集群号,很多配置的路径会自动创建,在hadoop1上执行如下命令:
hdfs namenode -format
在hadoop1节点上执行如下命令启动namenode:
sbin/hadoop-daemon.sh start namenode
在[nn2]上,同步nn1的元数据信息
bin/hdfs namenode -bootstrapStandby
启动[nn2]
sbin/hadoop-daemon.sh start namenode
启动所有datanode
sbin/hadoop-daemons.sh start datanode
关闭所有HDFS服务:
sbin/stop-dfs.sh
分别启动Zookeeper集群:
bin/zkServer.sh start
初始化HA在Zookeeper中状态:
bin/hdfs zkfc -formatZK
启动HDFS服务:
sbin/start-dfs.sh
启动yarn服务:
sbin/start-yarn.sh
测试HDFS HA 可以直接将对应的active NameNode节点的NameNode进程杀掉,观察Standby NameNode节点状态会自动切换成Active状态,说明NameNode HA 没有问题,否则就需要查看各个NameNode节点$HADOOP_HOME/logs目录下对应的进行日志解决问题。
1,查看NN1和NN2那个为Active
bin/hdfs haadmin -getServiceState nn1
bin/hdfs haadmin -getServiceState nn2
2,将Active NameNode进程kill
kill -9 namenode的进程id
然后就会看到standby的状态的namenode状态变为Active
每次启动HDFS集群需要首先去各个zookeeper节点上启动zookeeper,然后再去namenode节点上启动HDFS集群,关闭集群时也是一样,先在namenode节点上停止HDFS集群,然后去zookeeper每台节点上关闭zookeeper。为了操作方便我们可以编写HDFS启动脚本和HDFS关闭脚本来方便以上操作。
打印节点环境变量:
echo $PATH
在hadoop1节点/root下创建bin目录,在此目录下编写启动和关闭HDFS集群脚本。
mkdir -p /root/bin
HDFS 集群启动脚本如下:
#!/bin/bash
for zknode in hadoop1 hadoop2 hadoop3
do
ssh $zknode "source /etc/profile;zkServer.sh start"
done
sleep 1
start-dfs.sh
sleep 1
echo "=====hadoop1 jps====="
jps
for other_node in hadoop2 hadoop3
do
echo "=====$other_node jps====="
ssh $other_node "source /etc/profile;jps"
done
HDFS集群关闭脚本如下:
#!/bin/bash
stop-dfs.sh
sleep 1
for zknode in hadoop1 hadoop2 hadoop3
do
ssh $zknode "source /etc/profile;zkServer.sh stop"
done
echo "=====hadoop1 jps====="
jps
for other_node in hadoop1 hadoop3
do
echo "=====$other_node jps====="
ssh $other_node "source /etc/profile;jps"
done
建议初学者按照原始方式来启动关闭集群,可以加深HDFS原理的理解。