Hadoop HA 高可用原理及部署

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Hadoop HA 高可用原理及部署相关的知识,希望对你有一定的参考价值。

参考技术A 在Hadoop 2.0之前,只有namenode一个节点,存在单点问题,namenode单点故障,难以应用与在线场景,也不利于生产上维护集群。namenode压力过大,且内存受损,影响系统延展性。0

HA:高可用集群(High Availability Cluster),是指以减少服务中断时间为目的的服务器集群技术。它通过保护用户的业务程序对外不间断提供的服务,把因软件、硬件、人为造成的故障对业务的影响降到最小。

在hadoop2.0引入了HA机制。hadoop2.0的HA机制官方介绍了有2种方式,一种是NFS(Network File System)方式,另外一种是QJM(QuorumJournal Manager)方式。

NFS(Network File System)
在QJM出现之前,为保障集群的HA,设计的是一种基于NAS的共享存储机制,即主备NameNode间通过NAS进行元数据的同步。该方案有什么缺点呢,主要有以下几点:
1. 定制化硬件设备:必须是支持NAS的设备才能满足需求
2. 复杂化部署过程:在部署好NameNode后,还必须额外配置NFS挂载、定制隔离脚本,部署易出错
3. 简陋化NFS客户端:Bug多,部署配置易出错,导致HA不可用
所以对于替代方案而言,也必须解决NAS相关缺陷才能让HA更好服务。即设备无须定制化,普通设备即可配置HA,部署简单,相关配置集成到系统本身,无需自己定制,同时元数据的同步也必须保证完全HA,不会因client问题而同步失败。所以引出了QJM方式。

QJM全称是Quorum Journal Manager, 由JournalNode(JN)组成,一般是奇数点结点组成。每个JournalNode对外有一个简易的RPC接口,以供NameNode读写EditLog到JN本地磁盘。当写EditLog时,NameNode会同时向所有JournalNode并行写文件,只要有N/2+1结点写成功则认为此次写操作成功,遵循Paxos协议。

HADOOP docker:HDFS 高可用原理

 

1.环境简述

上从在docker上装完hadoop集群后,发现有很多问题,又重新建了一个,如下:

主机名IP角色
hadoop1 172.18.0.11 NN1 ZK RM
hadoop2 172.18.0.12 NN2 ZK RM JOBHISTORY
hadoop3 172.18.0.13 DN ZK ND
hadoop4 172.18.0.14 DN QJM1 ND
hadoop5 172.18.0.15 DN QJM2 ND
hadoop6 172.18.0.16 DN QJM3 ND

目前已经安装了hdfs yarn zookeeper

2.QJM HA简述

2.1为什么要做HDFS HA?

在hadoop2.0之前,集群中只能有一个namenode,如果这个namenode宕机或者需要对namenode进行升级,那么整个集群的服务将不可用。因此要做HA。

2.2 HDFS HA的方式

目前支持两种HA方式:

  1. NFS
    namenode和standby namenode共享一个NFS磁盘,所以namenode的元数据变更立即同步到standby中。缺点是如果namenode或者standby namenode与NFS磁盘之间的网络出了问题,HA即失效,即把namenode单独故障转移到了NFS上,NFS同样存在单点故障问题。
  2. QJM
    namenode和standby namenode分别连接到一组Journal节点中,如果namenode出了故障,可以把standby namenode切换到activer状态,不影响集群使用。本方式配合zookeeper可以实现自动切换。

2.2 HSFS HA的结构

技术分享
以上是QJM HA的典型的结构图。集群中共有两个namenode(简称NN),其中只有一个是active状态,另一个是standby状态。active 的NN负责响应DN(datanode)的请求,为了最快的切换为active状态,standby状态的NN同样也连接到所有的datenode上获取最新的块信息(blockmap)。

active NN会把元数据的修改(edit log)发送到多数的journal节点上(2n+1个journal节点,至少写到n+1个上),standby NN从journal节点上读取edit log,并实时的合并到自己的namespace中。另外standby NN连接所有DN,实时的获取最新的blockmap。这样,一旦active的NN出现故障,standby NN可以立即切换为active NN.

注意:同一时刻只能有一个NAMENODE写edit log,否则将hdfs 元数据将会"脑裂"

2.3 机器要求

  1. 两个配置完全一样的namenode节点
  2. 2n+1个 journal节点,journal节点不需要很好的配置,可以与集群中的其它角色一起。

3.部署HDFS HA

3.1 详细配置

HDFS HA中用,nameserivce ID来标识一个HDFS服务,为了标识每个NN,还要加上namenode id。
hdfs-site.xml中:
1.设置集群的标识dfs.nameservice

  1. <property>
  2. <name>dfs.nameservices</name>
  3. <value>mycluster</value>
  4. </property>

这里修改为dockercluster

2.设置namenode名称 dfs.ha.namenodes.[nameservice ID]

  1. <property>
  2. <name>dfs.ha.namenodes.mycluster</name>
  3. <value>nn1,nn2</value>
  4. </property>

nn1 nn2为namenode的标识。
注意:当前只支持两个namenode的HA

3.设置namenode对外提供服务的RPC地址 dfs.namenode.rpc-address.[nameservice ID].[name node ID]

  1. <property>
  2. <name>dfs.namenode.rpc-address.mycluster.nn1</name>
  3. <value>machine1.example.com:8020</value>
  4. </property>
  5. <property>
  6. <name>dfs.namenode.rpc-address.mycluster.nn2</name>
  7. <value>machine2.example.com:8020</value>
  8. </property>

这个RPC地址实际就是 dfs.defaultFS地址

4.设置HDFS web页面地址 dfs.namenode.http-address.[nameservice ID].[name node ID]

  1. <property>
  2. <name>dfs.namenode.http-address.mycluster.nn1</name>
  3. <value>machine1.example.com:50070</value>
  4. </property>
  5. <property>
  6. <name>dfs.namenode.http-address.mycluster.nn2</name>
  7. <value>machine2.example.com:50070</value>
  8. </property>

如果启用的hdfs的安全机制,要设置 https-address

5.设置journal上edit log共享目录 dfs.namenode.shared.edits.dir
格式是:qjournal://host1:port1;host2:port2;host3:port3/journalId 所有节点上路径要保持一致

  1. <property>
  2. <name>dfs.namenode.shared.edits.dir</name><value>qjournal://node1.example.com:8485;node2.example.com:8485;node3.example.com:8485/mycluster</value>
  3. </property>

这里我们改成: qjournal://hadoop4:8485;hadoop5:8485;hadoop6:8485/dockercluster

6.设置实现集群HA的类 dfs.client.failover.proxy.provider.[nameservice ID]

  1. <property>
  2. <name>dfs.client.failover.proxy.provider.mycluster</name>
  3. <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
  4. </property>

当前仅支持这个类

7.设置切换时执行的程序 dfs.ha.fencing.methods
当namenode发生切换时,原来active的NN可能依然在写edit log,这时如果standby 也开始写edit log,元数据会"脑裂"。为了防止"脑裂",必须要切换之前杀掉原来active 的NN,这个脚本就是实现这个目的。当前支持两中fencing.method:shell 和 sshfence。另外,可能自定义org.apache.hadoop.ha.NodeFence来实现自己的保护程序。

7.1.sshfence(默认)
通过SSH登录到原来active的NN,并使用fuser命令KILL掉NN进程。要使用SSH,必须配置rsa-key参数:dfs.ha.fencing.ssh.private-key-files

  1. <property>
  2. <name>dfs.ha.fencing.methods</name>
  3. <value>sshfence</value>
  4. </property>
  5. <property>
  6. <name>dfs.ha.fencing.ssh.private-key-files</name>
  7. <value>/home/hdfs/.ssh/id_rsa</value>
  8. </property>

也可以用其它用户登录,同样可以配置超时参数:

  1. <property>
  2. <name>dfs.ha.fencing.methods</name>
  3. <value>sshfence([[username][:port]])</value>
  4. </property>
  5. <property>
  6. <name>dfs.ha.fencing.ssh.connect-timeout</name>
  7. <value>30000</value>
  8. </property>

7.2.shell
自定义一个shell脚本业杀死NAMENODE

  1. <property>
  2. <name>dfs.ha.fencing.methods</name>
  3. <value>shell(/path/to/my/script.sh arg1 arg2 ...)</value>
  4. </property>

shell脚本可以读取到当前已经配置的HDFS变量,将"."替换为"_" 即可。对于某些共用的条目,如dfs_namenode_rpc-address可以自动的指向特定节点如dfs.namenode.rpc-address.ns1.nn1。以下变量也可以使用:

 
$target_host
$target_port
$target_address
$target_namenodeid

示例:

  1. <property>
  2. <name>dfs.ha.fencing.methods</name>
  3. <value>shell(/path/to/my/script.sh --nameservice=$target_nameserviceid $target_host:$target_port)</value>
  4. </property>

如果shell返回0,表示执行成功。如果不为0,则继续执行其它的fencing.method.shell方式没有timeout.

这时里,我们也用ssh方式,比较简单,只需要生成key就行了.在NN1 NN2上执行:

  1. [[email protected] ~]$ ssh-keygen -t rsa
  2. Generatingpublic/private rsa key pair.
  3. Enter file in which to save the key (/home/hdfs/.ssh/id_rsa):
  4. Enter passphrase (empty forno passphrase):
  5. Enter same passphrase again:
  6. Your identification has been saved in/home/hdfs/.ssh/id_rsa.
  7. Yourpublic key has been saved in/home/hdfs/.ssh/id_rsa.pub.
  8. The key fingerprint is:
  9. 6b:de:13:b7:55:ba:43:1c:28:ef:2e:b8:b7:0a:e0:15 [email protected]
  10. The key‘s randomart image is:
  11. +--[ RSA 2048]----+
  12. | |
  13. | |
  14. | E . |

8.在core-site.xml中设置hdfs 服务 fs.defaultFS
一旦使用了HDFS HA,那么fs.defaultFS就不能写成host:port文件,而要写成服务方式,写上nameservice id:

  1. <property>
  2. <name>fs.defaultFS</name>
  3. <value>hdfs://mycluster</value>
  4. </property>

这里改成hdfs://dockercluster

9.journal节点守护进程自己的数据目录 dfs.journalnode.edits.dir

  1. <property>
  2. <name>dfs.journalnode.edits.dir</name>
  3. <value>/path/to/journal/node/local/data</value>
  4. </property>

3.2 部署HDFS HA

1.启动所有journal节点hadoop-daemon.sh start journalnode

2.如果是新建的集群,在其中一个NN上执行hdfs format命令hdfs namenode -format
3.如果从非HA集群升级为HA集群,或者是已经执行过hdfs format命令,把已经formatted的NN上的元数据拷贝到没有formatted的NN上,然后在没有formatted的NN上执行hdfs namenode -bootstrapStandby,该命令会让journal节点做好连接两个namenode的准备。
4.如果将非HA的NN切换为HA,执行hdfs namenode -initializeSharedEdits将本地的edit log初始化到journal中。
执行完以上后,像平时一样启动每个NN。
在每个NN的web页面中,将会显示NN的状态是active或者standby

————————————————-更改—————————————–
后续更新:
在做实验时发现,官网这个步骤有问题!
正确的步骤是:
1.启动所有journal节点hadoop-daemon.sh start journalnode
2.执行journal 节点初始化hdfs namenode -initializeSharedEdits
3.启动原来的namenode $HADOOP_HOME/sbin/hadoop-daemon.sh --config $HADOOP_CONF_DIR --script hdfs start namenode
4.初始化standby hdfs namenode -bootstrapStandby,
5.启动standby $HADOOP_HOME/sbin/hadoop-daemon.sh --config $HADOOP_CONF_DIR --script hdfs start namenode
————————————————-更改—————————————–

.

4. HDFS HA的管理

HDFS HA的管理主要靠hdfs haadmin命令实现:

  1. [[email protected] ~]$ hdfs haadmin
  2. Usage: haadmin
  3. [-transitionToActive [--forceactive]<serviceId>]
  4. [-transitionToStandby <serviceId>]
  5. [-failover [--forcefence][--forceactive]<serviceId><serviceId>]
  6. [-getServiceState <serviceId>]
  7. [-checkHealth <serviceId>]
  8. [-help <command>]
  9. Generic options supported are
  10. -conf <configuration file> specify an application configuration file
  11. -D <property=value>use value for given property
  12. -fs <local|namenode:port> specify a namenode
  13. -jt <local|resourcemanager:port> specify a ResourceManager
  14. -files <comma separated list of files> specify comma separated files to be copied to the map reduce cluster
  15. -libjars <comma separated list of jars> specify comma separated jar files to include in the classpath.
  16. -archives <comma separated list of archives> specify comma separated archives to be unarchived on the compute machines.
  17. The general command line syntax is
  18. bin/hadoop command [genericOptions][commandOptions]
  • transitionToActive 和 transitionToStandby
    切换为active或者standby。注意:不会使用任务fencing措施,因此一般不使用这两个命令,用hdfs haadmin -failover
  • failover
    对hdfs做一次主备切换。在切换前,如果原来active的NN现在是standby状态,那么会直接把原来standby的NN切换为active状态。如果原来active状态的NN还是acitve状态,则会先将该NN切换为standby状态,如果切换为standby失败,则会调用dfs.ha.fencing.methods里指定的fencing方式来确保原来的acitve NN被干掉。如果没有定义fencing方式,或者fencing执行失败,则会抛出异常,同时不会切换原来的standby 为acitve
  • getServiceState
    获取指定NN的状态是active还是standby
  • checkHealth
    检查指定NN的状态。NN会对自己的服务做检查,返回0表示正常,0之外的为异常。注意:当前这个功能还没有实现(形同虚设),只要不停机就会返回0

5.自动切换

以上讲了如何手动切换HA,现在来说说实在切换HA

5.1 使用zookeeper实现HA原理

自动切换的HA需要用到zookeeper中的两个组件ZooKeeper quorum和ZKFailoverController process (ZKFC)。
zoookeeper会做以下两件事:

  • Failure detection 失效检测
    每个namenode都会在zookeeper里保存一个持久会话,一旦某个namenode挂了,zookeeper中的会话就会过期,zookeeper检测机制会通知另外一个namenode需要做failover了
  • Active NameNode election 选择新的acitve namenode
    zookeeper可以通过简单的机制来选出唯一一个acitve的namdenode.当active的namenode挂了后,另外一个namenode会在zookeeper中保存一个独占锁来标明自己将会是下一个active的namenode.
    ZKFC是同namenode在同一台机器上的zookeeper客户端。ZKFC负责以下事情:
  • Health monitoring 健康检测
    ZKFC使用health-check命令定时去pingnamenode,如果在超时时间内得到了响应并且状态是健康的(当前不是只能返回0吗?),就认为namenode是健康的,如果超过时间没有响应,则认为namenode宕机。
  • ZooKeeper session management 会话管理
    当namenode是健康的时间,ZKFC会和zookeeper保持一个会话,对于acitve的namenode节点,还会在zookeeper上创建一个临时的znode(如/hdfs/active.lock),如果会话过期,则znode会被自动删除
  • ZooKeeper session management
    在active的节点上ZKFC会在zookeeper里创建一个临时的znode并创建文件(如果/hdfs/acitve.lock),这时其它的namenode节点就不能创建同样一个znode,那么其它节点就会监控这个znode,一旦原来active的namenode宕机,则znode被删除,原来standby的namenode上的ZKFC就可以创建znode并切换standby namenode为acitve

5. 部署hdfs自动切换

5.1 关闭集群

将手动的HA切换为自动的HA必须先关闭集群

5.2 添加HA配置

1.修改hdfs-site.xml
添加:

  1. <property>
  2. <name>dfs.ha.automatic-failover.enabled</name>
  3. <value>true</value>
  4. </property>

2.修改core-site.xml
添加zookeer的server列表:

  1. <property>
  2. <name>ha.zookeeper.quorum</name>
  3. <value>zk1.example.com:2181,zk2.example.com:2181,zk3.example.com:2181</value>
  4. </property>

这里我修改为 hadoop1 hadoop2 hadoop3

注意,如果使用了hdfs federation,需要加上nameservice-id,如dfs.ha.automatic-failover.enabled.my-nameservice-id.

5.3 在zookeeper中初始化HA状态

在其中一台namenode上执行:

[hdfs]HADOOP_PREFIX/bin/hdfs zkfc -formatZK

5.4 开启集群

  • 使用start-dfs.sh启动集群
    如果配置了SSH,使用start-dfs.sh启动集群,该脚本会自动启动ZKFC,然后ZKFC选择出一个active的namenode
  • 手动启动集群
    在每个namenode机器上执行:

    [hdfs]HADOOP_PREFIX/sbin/hadoop-daemon.sh - -script $HADOOP_PREFIX/bin/hdfs start zkfc

5.5 使用zookeeper时的安全机制

略,有兴趣的自己上官网看吧。

6.FAQ

1.ZKFC和NAMENODE有没有特定的启动顺序
2.需要对ZKFC进程做监控,某些时候自动切换失效是因为ZKFC挂了
3.如果zookeeper挂了,则自动failover失效,但不会到HDFS服务有影响。当zookeeper启动后,自动failover功能恢复正常
4.当前并不技能人为的设置某个namenode为primary或者preferred
5.在自动HA的情况下,可以人为的切换namenode,执行hdfs hadmin命令。

7.做了HA后HDFS的升级、回滚

注意**在升级、回滚、finalization中必须保持所有journal节点是开启的(至关重要!)

7.1 升级

1.停止所有的namenode,并安装新的软件
2.开启所有的journal节点,注意在升级、回滚、finalization中必须保持所有journal节点是开启的(至关重要!)
3.以-upgrade方式启动一台namenode
4.启动后,一般该namenode会直接进入active状态,然后执行本地元数据和JNs上edit log的升级
5.另外一台要namenode如果使用-upgrade启动会报错,正确方式是重新初始化-bootstrapStandby

7.2 finalize

注意:如果做回滚或者finalization,则以正常方式重启所有的namenode(不带其它参数)
在active的namenode上执行hdfs dfsadmin -finalizeUpgrade,这里active的NN将会定稿edit log并在本地上目录中删除旧版本的元数据

7.3 回滚

注意:如果做回滚或者finalization,则以正常方式重启所有的namenode(不带其它参数)
关闭所有的NN,在其中一台namenode上执行roll back命令,然后启动这个NN。在另外一个NN上执行-bootstrapStandby命令来同步状态
















































































以上是关于Hadoop HA 高可用原理及部署的主要内容,如果未能解决你的问题,请参考以下文章

搭建HA高可用hadoop-2.3(部署配置HBase)

大数据Hadoop的HA高可用架构集群部署

大数据Hadoop的HA高可用架构集群部署

技术交流大数据Hadoop的HA高可用架构集群部署

Hadoop高可用HA原理-全流程讲解

Hadoop高可用(HA)集群部署