本篇主要从 hdfs 的 namenode 和 resourcemanager 的高可用进行安装和原理的阐述.
一, HA 安装
1, 基本环境准备
1.1.1,centos7 虚拟机安装, 详情见 VMware 安装 Centos7 虚拟机
1.1.2, 关闭防火墙
- systemctl stop firewalld.service
- systemctl disable firewalld.service
1.1.3, 修改 selinux
VIM /etc/selinux/config
将 SELINUX=enforcing 改为 SELINUX=disabled
- [hadoop@lgh2 ~]$ cat /etc/selinux/config
- # This file controls the state of SELinux on the system.
- # SELINUX= can take one of these three values:
- # enforcing - SELinux security policy is enforced.
- # permissive - SELinux prints warnings instead of enforcing.
- # disabled - No SELinux policy is loaded.
- SELINUX=disabled
- # SELINUXTYPE= can take one of three two values:
- # targeted - Targeted processes are protected,
- # minimum - Modification of targeted policy. Only selected processes are protected.
- # mls - Multi Level Security protection.
- SELINUXTYPE=targeted
1.1.4, 安装 java
java 安装
- tar -zxvf jdk-8u201-Linux-x64.tar.gz -C /usr/local/
- VIM /etc/profile
- export JAVA_HOME=/usr/local/jdk1.8.0_201
- export JRE_HOME=/usr/local/jdk1.8.0_201/jre
- export CLASS_PATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib
- export PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
- source /etc/profile
1.1.5, 添加用户 hadoop
- groupadd hadoop
- useradd -g hadoop -d /home/hadoop
- echo 'hadoop' | passwd hadoop --stdin
1.1.6, 修改 / etc/hosts
- cat /etc/hosts
- 192.168.88.131 lgh1
- 192.168.88.132 lgh2
- 192.168.88.133 lgh3
如上环境我们准备三台机器, 如上 1.1.6 所见:
1.1.7, 配置免密登录
- SSH-keygen -t rsa #这个操作需要连续三次按 enter 键,
- SSH-copy-id lgh3
- SSH-copy-id lgh2
- SSH-copy-id lgh1
1.1.8, 配置时间同步(这个很重要, 在生产环境必定要有, 不过自己玩也可以不用配置)
首先我们选定 192.168.88.131(lgh1)这台为时间标准的节点, 其他两台机器同这个节点进行同步
设置 192.168.88.131 这个节点:
- yum install -y ntp #如果没有安装就安装
- [root@lgh1 ~]# rpm -qa | grep ntp #查看安装结果
- ntp-4.2.6p5-29.el7.CentOS.x86_64 #用来提供时间同步服务
- ntpdate-4.2.6p5-29.el7.CentOS.x86_64 #和某台服务器进行同步
修改 / etc/ntp.conf 文件
- egrep -v "^$|#" /etc/ntp.conf
- [root@lgh1 ~]# egrep -v "^$|#" /etc/ntp.conf
- driftfile /var/lib/ntp/drift
- restrict default nomodify notrap nopeer noquery
- restrict 192.168.88.0 mask 255.255.255.0 nomodify notrap
- restrict 127.0.0.1
- restrict ::1
- #server 0.CentOS.pool.ntp.org iburst
- #server 1.CentOS.pool.ntp.org iburst
- #server 2.CentOS.pool.ntp.org iburst
- #server 3.CentOS.pool.ntp.org iburst
- server 127.127.1.0
- fudge 127.127.1.0 stratum 10
- includefile /etc/ntp/crypto/pw
- keys /etc/ntp/keys
- disable monitor
- systemctl enable ntpd #启动
其他两个节点: lhg2 和 lgh3 设置如下:
首先要安装 ntpd:yum install -y ntp #如果没有安装则要安装
新增 crontab -e
*/5 * * * */usr/sbin/ntpdate -u 192.168.88.131 #表示每五分钟和 131 时间同步一次
测试:(可以通过如下命令修改 131 的时间, 看其他两个节点是否能同步成功, 亲测成功)
- date "+%Y-%m-%d %H:%M:%S"
- date -s '2018-09-20 10:02:02'
2,hadoop 高可用安装
1.2.1, 安装规划 -- 目录
- mkdir -p /opt/hadoop #存放 hadoop 文件, 安装目录
- chown -R hadoop:hadoop /opt/hadoop
- mkdir -p /opt/data/hadoop/hdfs #存放 namenode 和 datanode 的数据
- mkdir -p /opt/data/hadoop/tmp #存放临时文件
- chown -R hadoop:hadoop /opt/data/hadoop/hdfs
- chown -R hadoop:hadoop /opt/data/hadoop/tmp
1.2.2, 角色规划
解压 1.2.3,zookeeper 安装
- cd /opt/hadoop
- tar -zxvf zookeeper-3.4.8.tar.gz
- ln -s zookeeper-3.4.8 zookeeper
配置环境变量
- VIM /etc/profile
- export ZOOKEEPER_HOME=/opt/hadoop/zookeeper
- export PATH=$ZOOKEEPER_HOME/bin:$ZOOKEEPER_HOME/conf:$PATH
- source /etc/profile
修改配置 zoo.cfg
- cd /opt/hadoop/zookeeper/conf
- cp zoo_sample.cfg zoo.cfg
- VIM zoo.cfg
- tickTime=2000 #服务器与客户端之间交互的基本时间单元(ms)
- initLimit=10 # 此配置表示允许 follower 连接并同步到 leader 的初始化时间, 它以 tickTime 的倍数来表示. 当超过设置倍数的 tickTime 时间, 则连接失败
- syncLimit=5 # Leader 服务器与 follower 服务器之间信息同步允许的最大时间间隔, 如果超过次间隔, 默认 follower 服务器与 leader 服务器之间断开链接
- dataDir=/opt/hadoop/zookeeper/data #保存 zookeeper 数据路径
- dataLogDir=/opt/hadoop/zookeeper/dataLog #保存 zookeeper 日志路径, 当此配置不存在时默认路径与 dataDir 一致
- clientPort=2181 #客户端访问 zookeeper 时经过服务器端时的端口号
- server.1=lgh1:2888:3888 #表示了不同的 zookeeper 服务器的自身标识, 作为集群的一部分, 每一台服务器应该知道其他服务器的信息
- server.2=lgh2:2888:3888
- server.3=lgh3:2888:3888
- maxClientCnxns=60 #限制连接到 zookeeper 服务器客户端的数量
修改 myid 文件
- cd /opt/hadoop/zookeeper
- mkdir data dataLog
- cd /opt/hadoop/zookeeper/data
- touch myid && echo 1> myid
分发并修改 myid 文件
- scp -r /opt/hadoop/zookeeper hadoop@lgh2:/opt/hadoop/
- scp -r /opt/hadoop/zookeeper hadoop@lgh3:/opt/hadoop/
- VIM /opt/hadoop/zookeeper/data/myid #lgh2 修改为 2
- VIM /opt/hadoop/zookeeper/data/myid #lgh3 修改为 3
启动并查看状态
- zkServer.sh start
- zkServer.sh status
一台为 leader 状态, 其他两个为 follower 状态
1.2.4, 解压 hadoop
- cd /opt/hadoop
- tar -zxvf hadoop-2.7.7.tar.gz
- ln -s hadoop-2.7.7 hadoop
1.2.5, 配置环境变量
- export HADOOP_HOME="/opt/hadoop/hadoop-2.7.7"
- export PATH=$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$PATH
1.2.6, 修改 hadoop-env.sh,mapred-env.sh,yarn-env.sh
export JAVA_HOME=/usr/local/jdk1.8.0_201
1.2.7, 修改 hdfs-site.xml 文件
- <configuration>
- <property>
- <!-- 为 namenode 集群定义一个 services name -->
- <name>dfs.nameservices</name>
- <value>mycluster</value>
- </property>
- <property>
- <!-- nameservice 包含哪些 namenode, 为各个 namenode 起名 -->
- <name>dfs.ha.namenodes.mycluster</name>
- <value>nn1,nn2</value>
- </property>
- <property>
- <!-- 名为 nn1 的 namenode 的 rpc 地址和端口号, rpc 用来和 datanode 通讯 -->
- <name>dfs.namenode.rpc-address.mycluster.nn1</name>
- <value>lgh1:8020</value>
- </property>
- <property>
- <!-- 名为 nn2 的 namenode 的 rpc 地址和端口号, rpc 用来和 datanode 通讯 -->
- <name>dfs.namenode.rpc-address.mycluster.nn2</name>
- <value>lgh2:8020</value>
- </property>
- <property>
- <!-- 名为 nn1 的 namenode 的 http 地址和端口号, web 客户端 -->
- <name>dfs.namenode.http-address.mycluster.nn1</name>
- <value>lgh1:50070</value>
- </property>
- <property>
- <!-- 名为 nn2 的 namenode 的 http 地址和端口号, web 客户端 -->
- <name>dfs.namenode.http-address.mycluster.nn2</name>
- <value>lgh2:50070</value>
- </property>
- <property>
- <!-- namenode 间用于共享编辑日志的 journal 节点列表 -->
- <!-- 指定 NameNode 的 edits 元数据的共享存储位置. 也就是 JournalNode 列表
- 该 url 的配置格式: qjournal://host1:port1;host2:port2;host3:port3/journalId
- journalId 推荐使用 nameservice, 默认端口号是: 8485 -->
- <name>dfs.namenode.shared.edits.dir</name>
- <value>qjournal://lgh1:8485;lgh2:8485;lgh3:8485/mycluster</value>
- </property>
- <property>
- <!-- journalnode 上用于存放 edits 日志的目录 -->
- <name>dfs.journalnode.edits.dir</name>
- <value>/opt/hadoop/hadoop/tmp/data/dfs/jn</value>
- </property>
- <property>
- <!-- 客户端连接可用状态的 NameNode 所用的代理类 -->
- <name>dfs.client.failover.proxy.provider.mycluster</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>
- <!-- journalnode 集群之间通信的超时时间 -->
- <property>
- <name>dfs.qjournal.start-segment.timeout.ms</name>
- <value>60000</value>
- </property>
- <!-- 指定副本数 -->
- <property>
- <name>dfs.replication</name>
- <value>2</value>
- </property>
- <!--namenode 路径 -->
- <property>
- <name>dfs.namenode.name.dir</name>
- <value>/opt/data/hadoop/hdfs/nn</value>
- </property>
- <!--datanode 路径 -->
- <property>
- <name>dfs.datanode.data.dir</name>
- <value>/opt/data/hadoop/hdfs/dn</value>
- </property>
- <!-- 开启 NameNode 失败自动切换 -->
- <property>
- <name>dfs.ha.automatic-failover.enabled</name>
- <value>true</value>
- </property>
- <!-- 启用 webhdfs -->
- <property>
- <name>dfs.webhdfs.enabled</name>
- <value>true</value>
- </property>
- <!-- 配置 sshfence 隔离机制超时时间 -->
- <property>
- <name>dfs.ha.fencing.SSH.connect-timeout</name>
- <value>30000</value>
- </property>
- <property>
- <name>ha.failover-controller.cli-check.rpc-timeout.ms</name>
- <value>60000</value>
- </property>
- </configuration>
1.2.8, 修改 core-site.xml
- <configuration>
- <property>
- <!-- hdfs 地址, ha 中是连接到 nameservice -->
- <name>fs.defaultFS</name>
- <value>hdfs://mycluster</value>
- </property>
- <property>
- <!-- -->
- <name>hadoop.tmp.dir</name>
- <value>/opt/data/hadoop/tmp</value>
- </property>
- <!-- 指定 zookeeper 地址 -->
- <property>
- <name>ha.zookeeper.quorum</name>
- <value>lgh1:2181,lgh2:2181,lgh3:2181</value>
- </property>
- <!-- hadoop 链接 zookeeper 的超时时长设置 -->
- <property>
- <name>ha.zookeeper.session-timeout.ms</name>
- <value>30000</value>
- <description>ms</description>
- </property>
- <property>
- <name>fs.trash.interval</name>
- <value>1440</value>
- </property>
- <property>
- <name>hadoop.proxyuser.hdfs.groups</name>
- <value>*</value>
- </property>
- <property>
- <name>hadoop.proxyuser.hdfs.hosts</name>
- <value>*</value>
- </property>
- <property>
- <name>hadoop.proxyuser.hive.groups</name>
- <value>*</value>
- </property>
- <property>
- <name>hadoop.proxyuser.hive.hosts</name>
- <value>*</value>
- </property>
- </configuration>
1.2.9, 修改 yarn-site.xml
- <configuration>
- <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>106800</value>
- </property>
- <property>
- <!-- 启用 resourcemanager 的 ha 功能 -->
- <name>yarn.resourcemanager.ha.enabled</name>
- <value>true</value>
- </property>
- <property>
- <!-- 为 resourcemanage ha 集群起个 id -->
- <name>yarn.resourcemanager.cluster-id</name>
- <value>yarn-cluster</value>
- </property>
- <property>
- <!-- 指定 resourcemanger ha 有哪些节点名 -->
- <name>yarn.resourcemanager.ha.rm-ids</name>
- <value>rm1,rm2</value>
- </property>
- <property>
- <!-- 指定第一个节点的所在机器 -->
- <name>yarn.resourcemanager.hostname.rm1</name>
- <value>lgh2</value>
- </property>
- <property>
- <!-- 指定第二个节点所在机器 -->
- <name>yarn.resourcemanager.hostname.rm2</name>
- <value>lgh3</value>
- </property>
- <property>
- <!-- 指定 resourcemanger ha 所用的 zookeeper 节点 -->
- <name>yarn.resourcemanager.zk-address</name>
- <value>lgh1:2181,lgh2:2181,lgh3:2181</value>
- </property>
- <property>
- <!-- -->
- <name>yarn.resourcemanager.recovery.enabled</name>
- <value>true</value>
- </property>
- <!-- 制定 resourcemanager 的状态信息存储在 zookeeper 集群上 -->
- <property>
- <name>yarn.resourcemanager.store.class</name>
- <value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value>
- </property>
- <property>
- <name>yarn.log.server.url</name>
- <value>http://lgh2:19888/jobhistory/logs/</value>
- </property>
- </configuration>
1.2.10, 修改 slaves
lgh1 lgh2 lgh3
1.2.11, 分发到其他两个节点
- scp /opt/hadoop/hadoop-2.7.7 hadoop@lgh2:/opt/hadoop/
- scp /opt/hadoop/hadoop-2.7.7 hadoop@lgh3:/opt/hadoop/
1.2.12, 格式化 nomenode 和 zookeeper
- [hadoop@lgh1 ~]$ hdfs namenode -format
- [hadoop@lgh2 ~]$ hdfs namenode -bootstrapStandby
- [hadoop@lgh1 ~]$ hdfs zkfc -formatZK #格式化 zookeeper
1.2.13, 启动
- stop-dfs.sh #关闭所有 journalnode
- start-dfs.sh #启动 namenode,datanode,journalnode 等组件
- start-yarn.sh #启动 yarn
- [hadoop@lgh2 ~]$ /opt/hadoop/hadoop/sbin/yarn-daemon.sh start resourcemanager #这里一定要注意是 yarn-daemon.sh, 启动 resourcemanager
- [hadoop@lgh3 ~]$ /opt/hadoop/hadoop/sbin/yarn-daemon.sh start resourcemanager
1.2.14, 查看进程
jps (图片不协调...)
1.2.15, 访问页面(namenode)
- 192.168.88.131:50070
- 192.168.88.132:50070
1.2.16, 测试 namenode 故障转移
在节点 192.168.88.132 上执行:
[hadoop@lgh2 ~]$ /opt/hadoop/hadoop/sbin/hadoop-daemon.sh stop namenode
然后我们恢复 192.168.88.132 的 namenode
[hadoop@lgh2 ~]$ /opt/hadoop/hadoop/sbin/hadoop-daemon.sh start namenode
该节点变成了 standby 节点. 说明故障转移成功
1.2.17, 查看 yarn 页面访问
resourcemanager 的故障测试:
[hadoop@lgh3 ~]$ /opt/hadoop/hadoop/sbin/yarn-daemon.sh stop resourcemanager #停掉 lgh3 节点上的 resourcemanager
这里不截图了, 很成功
到这里 hadoop 的高可用就安装完毕了(不过笔者这个中踩了不少坑, 遇到一些奇葩问题, 但是没有记录, 总之, 删除掉生成的东西, 多格式化几次试试)
删除的目录有:
- rm -rf /opt/data/hadoop/hdfs/*
- rm -rf /opt/data/hadoop/tmp/*
- rm -rf /opt/hadoop/hadoop/logs/*
二, 基本原理
1,namenode 高可用
我们知道 namenode 是整个 hdfs 的核心, 如果 namenode 挂了, 那么整个 hdfs 文件系统也不能提供服务, 所以 hadoop 对 hdfs 提供了高可用的方案, 即 Hadoop HA,hdfs 的高可用提供了两种方案, 一种是基于 QJM(Quorum Journal Manager)的, 一种是基于 NFS 的, 我们用的一般都是基于 QJM 的, 所以这里也是讲基于 QJM 的高可用, 高可用用来解决 NameNode 单点故障的问题. 解决的方法是在 HDFS 集群中设置多个 NameNode 节点. 那么提供多个 namenode 必定存在新的问题:
1, 如何保证 NameNode 内存中元数据数据一致, 并保证编辑日志文件的安全性.
2, 多个 NameNode 如何协作
3, 客户端如何能正确地访问到可用的那个 NameNode.
4, 怎么保证任意时刻只能有一个 NameNode 处于对外服务状态
针对如上问题, hadoop 提供了如下解决方案:
对于保证 NameNode 元数据的一致性和编辑日志的安全性, 采用 Zookeeper 来存储编辑日志文件.
两个 NameNode 一个是 Active 状态的, 一个是 Standby 状态的, 一个时间点只能有一个 Active 状态的 .
NameNode 提供服务, 两个 NameNode 上存储的元数据是实时同步的, 当 Active 的 NameNode 出现问题时, 通过 Zookeeper 实时切换到 Standby 的 NameNode 上, 并将 Standby 改为 Active 状态.
客户端通过连接一个 Zookeeper 的代理来确定当时哪个 NameNode 处于服务状态.
我们看一下 hdfs 高可用的架构图: 如下图所示:
HDFS HA 架构中有两台 NameNode 节点, 一台是处于活动状态 (Active) 为客户端提供服务, 另外一台处于热备份状态(Standby).
DataNode 会将心跳信息和 Block 汇报信息同时发给两台 NameNode,DataNode 只接受 Active NameNode 发来的文件读写操作指令. 为了使备用节点保持其状态与 Active 节点同步, 两个节点都与一组称为 "JournalNodes"(JN)的单独守护进程通信. 当 Active 节点执行任何名称空间修改时, 它会将修改记录持久地记录到大多数这些 JN 中. 待机节点能够从 JN 读取编辑, 并且不断观察它们对编辑日志的更改. 当备用节点看到编辑时, 它会将它们应用到自己的命名空间. 如果发生故障转移, Standby 将确保在将自身升级为 Active 状态之前已从 JournalNodes 读取所有编辑内容. 这可确保在发生故障转移之前完全同步命名空间状态. 注意: 必须至少有 3 个 JournalNode 守护进程, 因为编辑日志修改必须写入大多数 JN. 这将允许系统容忍单个机器的故障. 您也可以运行 3 个以上的 JournalNodes, 但为了实际增加系统可以容忍的失败次数, 您应该运行奇数个 JN(即 3,5,7 等). 请注意: 当使用 N JournalNodes 运行时, 系统最多可以容忍(N-1)/ 2 个故障并继续正常运行.
Zookeeper 来保证在 Active NameNode 失效时及时将 Standby NameNode 修改为 Active 状态.
故障检测 - 集群中的每个 NameNode 计算机都在 ZooKeeper 中维护一个持久会话. 如果计算机崩溃, ZooKeeper 会话将过期, 通知其他 NameNode 应该触发故障转移. Active NameNode 选举 - ZooKeeper 提供了一种简单的机制, 可以将节点专门选为活动节点. 如果当前活动的 NameNode 崩溃, 则另一个节点可能在 ZooKeeper 中采用特殊的独占锁, 指示它应该成为下一个活动的.
ZKFailoverController(ZKFC)是一个新组件, 它是一个 ZooKeeper 客户端, 它还监视和管理 NameNode 的状态. 运行 NameNode 的每台机器也运行 ZKFC,ZKFC 负责:
1, 运行状况监视 : ZKFC 定期使用运行状况检查命令对其本地 NameNode 进行 ping 操作. 只要 NameNode 及时响应健康状态, ZKFC 就认为该节点是健康的. 如果节点已崩溃, 冻结或以其他方式进入不健康状态, 则运行状况监视器会将其标记为运行状况不佳.
2,ZooKeeper 会话管理 : 当本地 NameNode 运行正常时, ZKFC 在 ZooKeeper 中保持会话打开. 如果本地 NameNode 处于活动状态, 它还拥有一个特殊的 "锁定"znode. 此锁使用 ZooKeeper 对 "短暂" 节点的支持; 如果会话过期, 将自动删除锁定节点
3, 基于 ZooKeeper 的选举 : 如果本地 NameNode 是健康的, 并且 ZKFC 发现没有其他节点当前持有锁 znode, 它将自己尝试获取锁. 如果成功, 那么它 "赢得了选举", 并负责运行故障转移以使其本地 NameNode 处于活动状态. 故障转移过程类似于上述手动故障转移: 首先, 必要时对先前的活动进行隔离, 然后本地 NameNode 转换为活动状态.
元数据文件有两个文件: fsimage 和 edits, 备份元数据就是备份这两个文件. JournalNode 用来实时从 Active NameNode 上拷贝 edits 文件, JournalNode 有三台也是为了实现高可用.
Standby NameNode 不对外提供元数据的访问, 它从 Active NameNode 上拷贝 fsimage 文件, 从 JournalNode 上拷贝 edits 文件, 然后负责合并 fsimage 和 edits 文件, 相当于 SecondaryNameNode 的作用. 最终目的是保证 Standby NameNode 上的元数据信息和 Active NameNode 上的元数据信息一致, 以实现热备份.
2,resourcemanager 高可用
首先我们来看一下官方提供的架构图: 如图所示:
ResourceManager HA 通过主动 / 备用架构实现 - 在任何时间点, 其中一个 RM 处于活动状态, 并且一个或多个 RM 处于待机模式, 等待活动 RM 出现故障或者宕机时机. 转换为活动的触发器来自管理员 (通过 CLI) 或启用自动故障转移时的集成故障转移控制器.
RM 可以选择嵌入基于 Zookeeper 的 ActiveStandbyElector 来决定哪个 RM 应该是 Active. 当 Active 关闭或无响应时, 另一个 RM 自动被选为 Active, 然后接管. 请注意, 不需要像 HDFS 那样运行单独的 ZKFC 守护程序, 因为嵌入在 RM 中的 ActiveStandbyElector 充当故障检测器和领导者选择器而不是单独的 ZKFC 守护程序.
当存在多个 RM 时, 客户端和节点使用的配置 (yarn-site.xml) 应该列出所有 RM. 客户端, 应用程序管理器 ApplicationMaster(AM)和节点管理器 NodeManager(NM)尝试以循环方式连接到 RM, 直到它们到达活动 RM. 如果活动停止, 他们将恢复循环轮询, 直到他们连接到新的 RM
来源: https://www.cnblogs.com/zsql/p/11560372.html