写点什么

完全解析大数据的高可用集群部署

  • 2022-11-25
    北京
  • 本文字数:6765 字

    阅读完需:约 22 分钟

HA 介绍

什么是 HA


HA: High Availability,高可用集群,指的是集群 7*24 小时不间断服务。


为什么需要 HA


在 HDFS 中,有 NameNode、DataNode 和 SecondaryNameNode 角色的分布,客户端所有的操作都是要与 NameNode 交互的,同时整个集群的命名空间信息也都保存在 NameNode 节点。但是,现在的集群配置中只有一个 NameNode,于是就有一个问题: 单点故障


那么,什么是单点故障呢?现在集群中只有一个 NameNode,那么假如这个 NameNode 意外宕机、升级硬件等,导致 NameNode 不可用了,整个集群是不是也就不可用了?这就是单点故障的问题。


为了解决这样的问题,就需要高可用集群了。


高可用的备份方式


  • 主从模式(冷备)


准备两台服务器, 准备相同的程序。 一台服务器对外提供服务, 称为主节点(Active 节点); 另外一台服务器平时不对外提供服务, 主要负责和 Active 节点之间进行数据的同步, 称为备份节点(Standby 节点). 当主节点出现故障, Standby 节点可以自动提升为 Active 节点, 对外提供服务。


 ZooKeeper 实现的集群高可用, 采用的就是这种模式。


我作为一个班级的讲师,在班级负责授课的工作。如果我有一天生病请假了,是不是咱们班级就得自习一天了?为了解决这样的问题,教学部安排另外一个讲师,每天跟着我。我上课讲课,他就在旁边听着;我上课提问问题,他就在旁边看着;我去吃饭,他也在旁边跟着;我去上个厕所,他也在跟着!做为我的一个影子存在着。由于这个同时每天都会跟着我,因此我的一言一行,讲了什么内容,留了什么作业,吃了什么饭,抽了几根烟,他都知道!那么,如果有一天我生病请假了,他是不是就可以直接替代我为班级上课呢?


  • 双主互备(热备)(了解)


准备两台服务器, 准备相同的程序. 同时对外提供服务(此时, 这两台服务器彼此为对方的备份), 这样, 当一台节点宕机的时候, 另外一台节点还可以继续提供服务.


小明到肯德基吃饭,找服务员点餐,这是正常的流程。但是,如果服务员只有一个,并且恰好生病了,那么小明是不是将没有办法正常点餐了。为了解决这个问题,肯德基雇了两个服务员,同时提供服务,这样一个服务员出问题了,另外一个服务员依然可以提供服务。


  • 集群多备(了解)


基本上等同于双主互备, 区别就在于同时对外提供服务的节点数量更多, 备份数量更多  肯德基觉得两个服务员也不保险,有两个同时生病的可能性,于是又多雇了几个服务员。


高可用的实现


我们在这里采用的是主从模式的备份方式,也就是准备两个 NameNode,一个对外提供服务,称为 Active 节点;另外一个不对外提供服务,只是实时的同步 Active 节点的数据,称为 Standby 的节点。


为了提供快速的故障转移,Standby 节点还必须具有集群中块位置的最新信息。为了实现这一点,DataNodes 被配置了两个 NameNodes 的位置,并向两者发送块位置信息和心跳信号。也就是说,DataNode 同时向两个 NameNode 心跳反馈。

高可用架构图


JournalNode

  • JournalNode 的功能


Hadoop2.x 版本之后, Clouera 提出了 QJM/QuromJournal Manager, 这是一个基于 Paxos 算法实现的 HA 的实现方案


 1. 基本的原理就是使用 2N+1 台 JN 存储 EditLog, 每次写入数据的时候, 有半数以上的 JN 返回成功的信息, 就表示本次的操作已经同步到了 JN


 2. 在 HA 中, SecondaryNameNode 这个角色已经不存在了, 保证 Standby 节点的元数据信息与 Active 节点的元数据信息一致, 需要通过若干个 JN


 3. 当有任何的操作发生在 Active 节点上的时候, JN 会记录这些操作到半数以上的节点中. Standby 节点检测 JN 中的 log 日志文件发生了变化, 会读取 JN 中的数据到自己的内存中, 维护最新的目录树结构与元数据信息


 4. 当发生故障的时候, Active 节点挂掉, 此时 Standby 节点在成为新的 Active 节点之前, 会将读取到的 EditLog 文件在自己的内存中进行推演, 得到最新的目录树结构. 此时再升为 Active 节点, 可以无缝的继续对外提供服务.


  • 防止脑裂的发生


对于 HA 群集的正确操作至关重要,一次只能有一个 NameNode 处于 Active 状态。否则,名称空间状态将在两者之间迅速分散,从而有数据丢失或其他不正确结果的风险。为了确保该属性并防止所谓的“裂脑情况”,JournalNode 将一次仅允许单个 NameNode 成为作者。在故障转移期间,变为活动状态的 NameNode 将仅承担写入 JournalNodes 的角色,这将有效地防止另一个 NameNode 继续处于活动状态,从而使新的 Active 可以安全地进行故障转移。


 - 怎么理解脑裂?


  就是 Active 节点处于网络震荡状态,假死状态,Standby 就转为 Active。等网络震荡过后,就有两个 Active 了,这就是脑裂。


  • JournalNode 集群正常工作的条件


- 至少 3 个 Journalnode 节点


 - 运行个数建议奇数个(3,5,7 等)


 - 满足(n+1)/2 个以上,才能正常服务。即能容忍(n-1)/2 个故障。


  • JournalNode 的缺点


在这种模式下,即使活动节点发生故障,系统也不会自动触发从活动 NameNode 到备用 NameNode 的故障转移,必须需要人为的操作才行。要是有一个能监视 Active 节点的服务功能就好了。


这个时候,我们就可以使用 zookeeper 集群服务,来帮助我们进行自动容灾了。

自动容灾原理

如果想进行 HA 的自动故障转移,那么需要为 HDFS 部署两个新组件:ZooKeeper quorum 和 ZKFailoverController 进程(缩写为 ZKFC)


Zookeeper quorum


Apache ZooKeeper 是一项高可用性服务,用于维护少量的协调数据,将数据中的更改通知客户端并监视客户端的故障。HDFS 自动故障转移的实现依赖 ZooKeeper 进行以下操作:


- 故障检测


  集群中的每个 NameNode 计算机都在 ZooKeeper 中维护一个持久性会话。如果计算机崩溃,则 ZooKeeper 会话将终止,通知另一个 NameNode 应触发故障转移。


 - 活动的 NameNode 选举(HA 的第一次启动)


  ZooKeeper 提供了一种简单的机制来专门选举一个节点为活动的节点。如果当前活动的 NameNode 崩溃,则另一个节点可能会在 ZooKeeper 中采取特殊的排他锁,指示它应成为下一个活动的 NameNode。


ZKFC


ZKFailoverController(ZKFC)是一个新组件,它是一个 ZooKeeper 客户端,它监视和管理 namenode 的状态。运行 namenode 的每台机器都会运行一个 ZKFC,该 ZKFC 负责以下内容:


- 运行状况监视


  ZKFC 使用运行状况检查命令定期 ping 其本地 NameNode。只要 NameNode 以健康状态及时响应,ZKFC 就会认为该节点是健康的。如果节点崩溃,冻结或以其他方式进入不正常状态,则运行状况监视器将其标记为不正常。


 - ZooKeeper 会话管理


  当本地 NameNode 运行状况良好时,ZKFC 会在 ZooKeeper 中保持打开的会话。如果本地 NameNode 处于活动状态,则它还将持有一个特殊的“锁定” znode。该锁使用 ZooKeeper 对“临时”节点的支持。如果会话到期,则锁定节点将被自动删除。


 - 基于 ZooKeeper 的选举


  如果本地 NameNode 运行状况良好,并且 ZKFC 看到当前没有其他节点持有锁 znode,则它本身将尝试获取该锁。如果成功,则它“赢得了选举”,并负责运行故障转移以使其本地 NameNode 处于活动状态。故障转移过程类似于上述的手动故障转移:首先,如有必要,将先前的活动节点隔离,然后将本地 NameNode 转换为活动状态。


自动容灾的过程描述


ZKFC(是一个进程,和 NN 在同一个物理节点上)有两只手,分别拽着 NN 和 Zookeeper。(监控 NameNode 健康状态,并向 Zookeeper 注册 NameNode);集群一启动,2 个 NN 谁是 Active?谁又是 Standby 呢?


  2 个 ZKFC 先判断自己的 NN 是否健康,如果健康,2 个 ZKFC 会向 zoopkeeper 集群抢着创建一个节点,结果就是只有 1 个会最终创建成功,从而决定 active 地位和 standby 位置。如果 ZKFC1 抢到了节点,ZKFC2 没有抢到,ZKFC2 也会监控 watch 这个节点。如果 ZKFC1 的 Active NN 异常退出,ZKFC1 最先知道,就访问 ZK,ZK 就会把曾经创建的节点删掉。删除节点就是一个事件,谁监控这个节点,就会调用 callback 回调,ZKFC2 就会把自己的地位上升到 active,但在此之前要先确认 ZKFC1 的节点是否真的挂掉?这就引入了第三只手的概念。


  ZKFC2 通过 ssh 远程连接 NN1 尝试对方降级,判断对方是否挂了。确认真的不健康,才会真的 上升地位之 active。所以 ZKFC2 的步骤是:


  1.创建新节点。


  2.第三只手把对方降级。


  3.把自己升级


  那如果 NN 都没毛病,ZKFC 挂掉了呢?Zoopkeeper 有一个客户端 session 机制,集群启动之后,2 个 ZKFC 除了监控自己的 NN,还要和 Zoopkeeper 建立一个 tcp 长连接,并各自获取自己的 session。只要一方的 session 失效,Zoopkeeper 就会删除该方创建的节点,同时另一方创建节点,上升地位。

HA 的配置

守护进程布局


qianfeng01: NameNode、DataNode、JournalNode、QuorumPeerMain、ZKFC


qianfeng02: NameNode、DataNode、JournalNode、QuorumPeerMain、ZKFC


qianfeng03: DataNode、JournalNode、QuorumPeerMain


现在,先停止 HDFS 的进程,修改如下的配置文件吧!


hdfs-site.xml


<!-- 注意: 高可用的集群,没有SecondaryNameNode的存在,因此在这个文件中之前存在的SecondaryNameNode的配置需要删除 --> <configuration>     <!-- 配置NameNode的逻辑名称 -->     <!-- 注意: 后面的很多参数配置都是需要使用到这个名称的 -->     <property>         <name>dfs.nameservices</name>         <value>supercluster</value>     </property>      <!-- 配置两个NameNode的唯一标识符 -->     <property>         <name>dfs.ha.namenodes.supercluster</name>         <value>nn1,nn2</value>     </property>      <!-- 针对每一个NameNode,配置自己的RPC通信地址和端口 -->     <property>         <name>dfs.namenode.rpc-address.supercluster.nn1</name>         <value>qianfeng01:9820</value>     </property>     <property>         <name>dfs.namenode.rpc-address.supercluster.nn2</name>         <value>qianfeng02:9820</value>     </property>      <!-- 针对每一个NameNode,配置WebUI的地址和端口 -->     <property>         <name>dfs.namenode.http-address.supercluster.nn1</name>         <value>qianfeng01:9870</value>     </property>     <property>         <name>dfs.namenode.http-address.supercluster.nn2</name>         <value>qianfeng02:9870</value>     </property>          <!-- 定义journalnode进程的数据存储的父路径, 目录在上面已经定义好了的:journalData -->     <property>         <name>dfs.journalnode.edits.dir</name>         <value>/usr/local/hadoop-3.3.1/tmp</value>     </property>      <!-- 配置journalnode的服务器地址和存储目录(数目为奇数个) -->     <!-- 服务器地址使用分号“;”作为分隔符-->     <property>         <name>dfs.namenode.shared.edits.dir</name>         <value>qjournal://qianfeng01:8485;qianfeng02:8485;qianfeng03:8485/journalData</value>     </property>      <!-- 指定客户端连接Active的namenode节点的java类型 -->     <property>         <name>dfs.client.failover.proxy.provider.supercluster</name>         <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>     </property>      <!--为了保证系统的正确性,在任何时间只有一个NameNode处于Active状态,需要配置一个防护机制 -->     <property>         <name>dfs.ha.fencing.methods</name>         <value>sshfence</value>     </property>     <!--为了使该防护选项起作用,它必须能够在不提供密码的情况下SSH到目标节点。因此,还必须配置以下属性-->     <property>         <name>dfs.ha.fencing.ssh.private-key-files</name>         <value>/root/.ssh/id_rsa</value>     </property>     <!-- 免密登陆超时时间,超过此时间未连接上,则登陆失败,此配置可选-->     <property>          <name>dfs.ha.fencing.ssh.connect-timeout</name>          <value>30000</value>      </property>      <!-- 支持自动容灾属性 -->     <property>         <name>dfs.ha.automatic-failover.enabled</name>         <value>true</value>     </property>          <!-- 块的副本数量 -->     <property>         <name>dfs.replication</name>         <value>3</value>     </property> </configuration>
复制代码


core-site.xml


<configuration>     <!--注意:使用到的是在hdfs-site.xml中配置的逻辑名称 -->     <property>         <name>fs.defaultFS</name>         <value>hdfs://supercluster</value>     </property>          <!-- hdfs的数据保存的路径,被其他属性所依赖的一个基础路径 -->     <property>         <name>hadoop.tmp.dir</name>         <value>/usr/local/hadoop-3.3.1/tmp</value>     </property>      <!-- ZooKeeper服务的地址 -->     <property>         <name>ha.zookeeper.quorum</name>         <value>qianfeng01:2181,qianfeng02:2181,qianfeng03:2181</value>     </property> </configuration>
复制代码


hadoop-env.sh


# 添加两行export HDFS_JOURNALNODE_USER=rootexport HDFS_ZKFC_USER=root
复制代码


分发配置文件到其他节点


 [root@qianfeng01 ~]# cd $HADOOP_HOME/etc [root@qianfeng01 hadoop]# scp -r hadoop qianfeng02:$PWD [root@qianfeng01 hadoop]# scp -r hadoop qianfeng03:$PWD
复制代码


启动集群


现在,集群已经搭建成为了高可用的集群了。在启动集群之前,我们需要先明确一件事情: 集群现在的状态有两种:


  • 这个集群我之前使用过,NameNode 已经存储有数据了(fsimage 和 edits 已生成)

  • 这个集群是我新搭建的,我直接搭建集群的时候就搭建的高可用的集群,之前从来没有启动过


如果你是第一种情况,请跳转到 普通集群转 HA


如果你是第二种情况,请跳转到 直接搭建 HA


启动: 普通集群转 HA


# 1. 启动集群的JournalNode服务。#    注意事项: 如果之前集群还在运行,需要先将其停止!使用命令 stop-dfs.sh[root@qianfeng01 ~]# hdfs --daemon start journalnode[root@qianfeng02 ~]# hdfs --daemon start journalnode[root@qianfeng03 ~]# hdfs --daemon start journalnode
# 2. 启动以前节点上的namenode进程[root@qianfeng01 ~]# hdfs --daemon start namenode
# 3. 在新的namenode节点上拉取镜像文件[root@qianfeng02 ~]# hdfs namenode -bootstrapStandby
# 4. 同步日志到journalnode集群上,再启动集群# 先关namenode[root@qianfeng01 ~]# hdfs --daemon stop namenode# 再同步日志[root@qianfeng01 ~]# hdfs namenode -initializeSharedEdits
# 5. 格式化zkfc# 5.1. 前提QuorumPeerMain服务必须处于开启状态,客户端zkfc才能格式化成功[root@qianfeng01 ~]# zkServer.sh start[root@qianfeng02 ~]# zkServer.sh start[root@qianfeng03 ~]# zkServer.sh start# 5.2. 选择其中一个namenode节点进行格式化zkfc[root@qianfeng01 ~]# hdfs zkfc -formatZK
# 6. 你就可以快乐的开启HA集群进行测试了[root@qianfeng01 ~]# start-all.sh
# 查看NameNode的状态[root@qianfeng01 ~]# hdfs haadmin -getServiceState nn1
# 注意: 以后开HA集群时,要先开zookeeper服务,再开HDFS。
复制代码


启动: 直接搭建 HA


# 1. 启动三个节点上的journalnode服务[root@qianfeng01 ~]# hdfs --daemon start journalnode[root@qianfeng02 ~]# hdfs --daemon start journalnode[root@qianfeng03 ~]# hdfs --daemon start journalnode
# 2. 格式化namenode# - 先删除所有节点的${hadoop.tmp.dir}/tmp/的数据(可选,这一步表示弃用fsimage.)# - 选择其中一个namenode进行格式化[root@qianfeng01 ~]# hdfs namenode -format# - 并启动namenode进程[root@qianfeng01 ~]# hdfs --daemon start namenode
# 3. 在另一台namenode上拉取已格式化的那台机器的镜像文件(数据的一致性)[root@qianfeng02 ~]# hdfs namenode -bootstrapStandby
# 4. 然后关闭已经启动的namenode[root@qianfeng01 ~]# hdfs --daemon stop namenode
# 5. 格式化zkfc# 5.1. 前提QuorumPeerMain服务必须处于开启状态,客户端zkfc才能格式化成功[root@qianfeng01 ~]# zkServer.sh start[root@qianfeng02 ~]# zkServer.sh start[root@qianfeng03 ~]# zkServer.sh start# 5.2. 选择其中一个namenode节点进行格式化zkfc[root@qianfeng01 ~]# hdfs zkfc -formatZK
# 6. 你就可以快乐的开启HA集群进行测试了[root@qianfeng01 ~]# start-all.sh
# 注意:以后开HA集群时,要先开zookeeper服务,再开HDFS。
复制代码


自动容灾测试


由于 CentOS7 的 minimal 版本缺少容灾切换 ActiveNameNode 节点时所需要的组件,因此需要手动安装一下:


yum install -y psmisc


1. 首先查看当前活跃的 Active 节点是谁


 2. Kill 掉活跃节点上的 NameNode 进程,模拟宕机


 3. 观察另外一个节点,是否已经变成 Active 的状态




帮助到你的话就点个关注吧~


用户头像

还未添加个人签名 2022-10-21 加入

还未添加个人简介

评论

发布
暂无评论
完全解析大数据的高可用集群部署_大数据_好程序员IT教育_InfoQ写作社区