2.QJM HA简述
2.1为什么要做HDFS HA?
2.2 HDFS HA的方式
2.2 HSFS HA的结构
2.3 机器要求
3.部署HDFS HA
3.1 详细配置
3.2 部署HDFS HA
4. HDFS HA的管理
5.自动切换
5.1 使用zookeeper实现HA原理
5. 部署hdfs自动切换
5.1 关闭集群
5.2 添加HA配置
5.3 在zookeeper中初始化HA状态
5.4 开启集群
5.5 使用zookeeper时的安全机制
6.FAQ
7.做了HA后HDFS的升级、回滚
7.1 升级
7.2 finalize
7.3 回滚
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方式:
- NFS
namenode和standby namenode共享一个NFS磁盘,所以namenode的元数据变更立即同步到standby中。缺点是如果namenode或者standby namenode与NFS磁盘之间的网络出了问题,HA即失效,即把namenode单独故障转移到了NFS上,NFS同样存在单点故障问题。 - 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 机器要求
- 两个配置完全一样的namenode节点
- 2n+1个 journal节点,journal节点不需要很好的配置,可以与集群中的其它角色一起。
3.部署HDFS HA
3.1 详细配置
HDFS HA中用,nameserivce ID来标识一个HDFS服务,为了标识每个NN,还要加上namenode id。
在hdfs-site.xml中:
1.设置集群的标识dfs.nameservice
<property>
<name>dfs.nameservices</name>
<value>mycluster</value>
</property>
这里修改为dockercluster
2.设置namenode名称 dfs.ha.namenodes.[nameservice ID]
<property>
<name>dfs.ha.namenodes.mycluster</name>
<value>nn1,nn2</value>
</property>
nn1 nn2为namenode的标识。
注意:当前只支持两个namenode的HA
3.设置namenode对外提供服务的RPC地址 dfs.namenode.rpc-address.[nameservice ID].[name node ID]
<property>
<name>dfs.namenode.rpc-address.mycluster.nn1</name>
<value>machine1.example.com:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn2</name>
<value>machine2.example.com:8020</value>
</property>
这个RPC地址实际就是 dfs.defaultFS地址
4.设置HDFS web页面地址 dfs.namenode.http-address.[nameservice ID].[name node ID]
<property>
<name>dfs.namenode.http-address.mycluster.nn1</name>
<value>machine1.example.com:50070</value>
</property>
<property>
<name>dfs.namenode.http-address.mycluster.nn2</name>
<value>machine2.example.com:50070</value>
</property>
如果启用的hdfs的安全机制,要设置 https-address
5.设置journal上edit log共享目录 dfs.namenode.shared.edits.dir
格式是:qjournal://host1:port1;host2:port2;host3:port3/journalId 所有节点上路径要保持一致
<property>
<name>dfs.namenode.shared.edits.dir</name><value>qjournal://node1.example.com:8485;node2.example.com:8485;node3.example.com:8485/mycluster</value>
</property>
这里我们改成: qjournal://hadoop4:8485;hadoop5:8485;hadoop6:8485/dockercluster
6.设置实现集群HA的类 dfs.client.failover.proxy.provider.[nameservice ID]
<property>
<name>dfs.client.failover.proxy.provider.mycluster</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</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
<property>
<name>dfs.ha.fencing.methods</name>
<value>sshfence</value>
</property>
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/home/hdfs/.ssh/id_rsa</value>
</property>
也可以用其它用户登录,同样可以配置超时参数:
<property>
<name>dfs.ha.fencing.methods</name>
<value>sshfence([[username][:port]])</value>
</property>
<property>
<name>dfs.ha.fencing.ssh.connect-timeout</name>
<value>30000</value>
</property>
7.2.shell
自定义一个shell脚本业杀死NAMENODE
<property>
<name>dfs.ha.fencing.methods</name>
<value>shell(/path/to/my/script.sh arg1 arg2 ...)</value>
</property>
shell脚本可以读取到当前已经配置的HDFS变量,将"."替换为"_" 即可。对于某些共用的条目,如dfs_namenode_rpc-address可以自动的指向特定节点如dfs.namenode.rpc-address.ns1.nn1。以下变量也可以使用:
$target_host |
$target_port |
$target_address |
$target_namenodeid |
示例:
<property>
<name>dfs.ha.fencing.methods</name>
<value>shell(/path/to/my/script.sh --nameservice=$target_nameserviceid $target_host:$target_port)</value>
</property>
如果shell返回0,表示执行成功。如果不为0,则继续执行其它的fencing.method.shell方式没有timeout.
这时里,我们也用ssh方式,比较简单,只需要生成key就行了.在NN1 NN2上执行:
[hdfs@hadoop1 ~]$ ssh-keygen -t rsa
Generatingpublic/private rsa key pair.
Enter file in which to save the key (/home/hdfs/.ssh/id_rsa):
Enter passphrase (empty forno passphrase):
Enter same passphrase again:
Your identification has been saved in/home/hdfs/.ssh/id_rsa.
Yourpublic key has been saved in/home/hdfs/.ssh/id_rsa.pub.
The key fingerprint is:
6b:de:13:b7:55:ba:43:1c:28:ef:2e:b8:b7:0a:e0:15 hdfs@hadoop1
The key's randomart image is:
+--[ RSA 2048]----+
| |
| |
| E . |
8.在core-site.xml中设置hdfs 服务 fs.defaultFS
一旦使用了HDFS HA,那么fs.defaultFS就不能写成host:port文件,而要写成服务方式,写上nameservice id:
<property>
<name>fs.defaultFS</name>
<value>hdfs://mycluster</value>
</property>
这里改成hdfs://dockercluster
9.journal节点守护进程自己的数据目录 dfs.journalnode.edits.dir
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/path/to/journal/node/local/data</value>
</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命令实现:
[hdfs@hadoop1 ~]$ hdfs haadmin
Usage: haadmin
[-transitionToActive [--forceactive]<serviceId>]
[-transitionToStandby <serviceId>]
[-failover [--forcefence][--forceactive]<serviceId><serviceId>]
[-getServiceState <serviceId>]
[-checkHealth <serviceId>]
[-help <command>]
Generic options supported are
-conf <configuration file> specify an application configuration file
-D <property=value>use value for given property
-fs <local|namenode:port> specify a namenode
-jt <local|resourcemanager:port> specify a ResourceManager
-files <comma separated list of files> specify comma separated files to be copied to the map reduce cluster
-libjars <comma separated list of jars> specify comma separated jar files to include in the classpath.
-archives <comma separated list of archives> specify comma separated archives to be unarchived on the compute machines.
The general command line syntax is
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
添加:
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
2.修改core-site.xml
添加zookeer的server列表:
<property>
<name>ha.zookeeper.quorum</name>
<value>zk1.example.com:2181,zk2.example.com:2181,zk3.example.com:2181</value>
</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
命令来同步状态