这是我参与更文挑战的第11天,活动详情查看:更文挑战html
高可用HA
概念
1、hadoop1.0的局限
- namenode的问题
- 单点故障:只有一个namenode
- 单点瓶颈:一个namenode,可能内存不足以管理全部datanode
2、高可用(high availability)
- 用于解决单点故障
- hadoop2.0只支持2个节点的HA,3.0能够一主多从
- 若是主节点(master)出现故障,就转到备用节点(stand by)
- HA的架构

- HDFS的高可靠性(HA)主要体如今利用zookeeper实现主备NameNode,以解决单点NameNode故障问题。
- ZooKeeper主要用来存储HA下的状态文件,主备信息。 ZK个数建议3个及以上且为奇数
个java
- NameNode主备模式,主提供服务,备同步主元数据并做为主的热备。
- ZKFC(ZooKeeper Failover Controller)用于监控NameNode节点的主备状态。
- JN(JournalNode)用于存储Active NameNode生成的Editlog。 Standby NameNode加载JN上Editlog,同步元数据。
- ZKFC控制NameNode主备仲裁
- ZKFC做为一个精简的仲裁代理,其利用zookeeper的分布式锁功能,实现主备仲裁,再经过命令通道,控制NameNode的主备状态。 ZKFC与NN部署在一块儿,二者个数相同。
- 元数据同步
- 两个NN的数据同步:两个namenode并非同时在工做,同时间只有一个NN在工做
- 两个NN必须同步数据信息
- 块位置信息(block imformation),它是由datanode处理的,而且要向NN汇报————动态数据信息
- 偏移量,大小,id,这些都是由NN本身来处理完成————静态信息
- 动态信息的同步
- 由DN向NN汇报
- 由原来的DN向单一NN汇报变成向多个NN汇报
- 静态信息的同步
- 既然静态数据信息都由NN本身处理完成,那么有两个NN,要怎么同步这两个NN的信息呢?
- 把多个journalnode节点部署在不一样的服务器上,其实每一个节点都是接收相同信息,多个节点就是为了防止单点故障
- 主NN把数据往journalnode节点里写,备份NN从journalnode里读数据
- 过半机制(弱一致性):容许一小半的journalnode节点失效
- 主NN写数据不必定要全部journalnode都肯定写入完成,容许有一小半失效
- 通常会配置奇数个journalnode节点
- 好比3个容许1个失效,5个容许两个失效
- 元数据持久化
- 主NameNode对外提供服务。生成的Editlog同时写入本地和JN,同时更新主NameNode内存中的元数据。
- 备NameNode监控到JN上Editlog变化时,加载Editlog进内存,生成新的与主NameNode同样的元数据。元数据同步完成。
- 主备的FSImage仍保存在各自的磁盘中,不发生交互。 FSImage是内存中元数据定时写到本地磁盘的副本,也叫元数据镜像

- EditLog:记录用户的操做日志,用以在FSImage的基础上生成新的文件系统镜像。
- FSImage:用以阶段性保存文件镜像。
- FSImage.ckpt:在内存中对fsimage文件和EditLog文件合并(merge)后产生新的fsimage,写到磁盘上,这个过程叫checkpoint.。备用NameNode加载完fsimage和EditLog文件后,会将merge后的结果同时写到本地磁盘和NFS。此时磁盘上有一份原始的fsimage文件和一份新生成的checkpoint文件: fsimage.ckpt. 然后将fsimage.ckpt更名为fsimage(覆盖原有的fsimage)。
- EditLog.new: NameNode每隔1小时或Editlog满64MB就触发合并,合并时,将数据传到Standby NameNode时,因数据读写不能同步进行,此时NameNode产生一个新的日志文件Editlog.new用来存放这段时间的操做日志。 Standby NameNode合并成fsimage后回传给主NameNode替换掉原有fsimage,并将Editlog.new 命名为Editlog。
- zookeeper集群
- 主NN发生故障时,用于自动切换NN
- zookeeper会把zkfc进程部署在NN上,进行选举和健康检查,一旦发现NN挂掉了,就会通知stand by NN(注意,zookeeper只会监控状态,切换主从都是NN本身决定的)
- 一旦主NN挂掉,它当即切换为stand by,而另外一个NN自动切换为active
3、联邦(federation)
- 架构

- 产生缘由:单Active NN的架构使得HDFS在集群扩展性和性能上都有潜在的问题,当集群大到必定程度后, NN进程使用的内存可能会达到上百G, NN成为了性能的瓶颈。
- 应用场景:超大规模文件存储。如互联网公司存储用户行为数据、电信历史数据、语音数据等超大规模数据存储。此时NameNode的内存不足以支撑如此庞大的集群。
- 经常使用的估算公式为1G对应1百万个块,按缺省块大小计算的话,大概是128T (这个估算比例是有比较大的富裕的,其实,即便是每一个文件只有一个块,全部元数据信息也不会有1KB/block)。
- Federation简单理解:各NameNode负责本身所属的目录。与Linux挂载磁盘到目录相似,此时每一个NameNode只负责整个hdfs集群中部分目录。如NameNode1负责/database目录,那么在/database目录下的文件元数据都由NameNode1负责。各NameNode间元数据不共享,每一个NameNode都有对应的standby。
- 块池(block pool) :属于某一命名空间(NS)的一组文件块。
- 联邦环境下,每一个namenode维护一个命名空间卷(namespace volume),包括命名空间的元数据和在该空间下的文件的全部数据块的块池。
- namenode之间是相互独立的,两两之间并不互相通讯,一个失效也不会影响其余namenode。
- datanode向集群中全部namenode注册,为集群中的全部块池存储数据。
- ameSpace(NS):命名空间。 HDFS的命名空间包含目录、文件和块。能够理解为NameNode所属的逻辑目录。
HA高可用搭建
1、各服务节点安装位置

- ZK位置任意,必须先启动(它要肯定主NN)
- ZKFC必须在NN上
- JNN位置任意
2、准备
- 实现node1和node2之间免密登陆
- 因为node一、node2都为NN,所以它们故障时须要切换,因此这两个node之间要配置SSH免密
3、配置hdfs-site.xml
- dfs.nameservices - the logical name for this new nameservice
- 主节点服务id(这里配置的是mycluser)
- 提供了惟一的一个名称,指向须要作主从配置的两个namenode节点
- 至关与是一个入口
- 这个名字只是表明一队主从(hadoop2.0只能有两个NN),若是要作联邦,那么能够用逗号隔开不一样的id名
<property>
<name>dfs.nameservices</name>
<value>mycluster</value>
</property>
复制代码
- dfs.ha.namenodes.[nameservice ID] - unique identifiers for each NameNode in the nameservice
- 指定哪些NN是上面的id所属的服务
- 能够看出下面的nn1,nn2也是逻辑名
- 但能够指出上面配置的nameservices指向哪些NN
- dfs.ha.namenodes.mycluster最后一个词是上面的nameservices的id
<property>
<name>dfs.ha.namenodes.mycluster</name>
<value>nn1,nn2</value>
</property>
复制代码
- dfs.namenode.rpc-address.[nameservice ID].[name node ID] - the fully-qualified RPC(remote produce call) address for each NameNode to listen on
<property>
<name>dfs.namenode.rpc-address.mycluster.nn1</name>
//物理机的ip地址
<value>node1:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn2</name>
<value>node2:8020</value>
</property>
复制代码
- dfs.namenode.http-address.[nameservice ID].[name node ID] - the fully-qualified HTTP address for each NameNode to listen on
- 给浏览器提供服务,用浏览器访问hadoop集群
- 端口是50070
<property>
<name>dfs.namenode.http-address.mycluster.nn1</name>
<value>node1:50070</value>
</property>
<property>
<name>dfs.namenode.http-address.mycluster.nn2</name>
<value>node2:50070</value>
</property>
复制代码
- dfs.namenode.shared.edits.dir - the URI which identifies the group of JNs where the NameNodes will write/read edits
- journalnode部署在哪些服务器上,对外通信的地址是什么
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://node2:8485;node3:8485;node4:8485/mycluster</value>
</property>
复制代码
- dfs.client.failover.proxy.provider.[nameservice ID] - the Java class that HDFS clients use to contact the Active NameNode
<property>
<name>dfs.client.failover.proxy.provider.mycluster</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
复制代码
- dfs.ha.fencing.methods - a list of scripts or Java classes which will be used to fence the Active NameNode during a failover
- 当一个NN发生故障的时候要当即把它隔离,不然会形成脑裂;而另外一个会当即变为active
//采用ssh方式隔离
<property>
<name>dfs.ha.fencing.methods</name>
<value>sshfence</value>
</property>
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/root/.ssh/id_dsa</value>
</property>
复制代码
- fs.defaultFS - the default path prefix used by the Hadoop FS client when none is given
- 配置在core-site.xml文件中
- 配置客户端访问HA的hasoop的逻辑路径,使用以前的nameservice ID做为hdfs path
<property>
<name>fs.defaultFS</name>
#注意这里手打mycluster时千万不要打成mycluser
<value>hdfs://mycluster</value>
</property>
//以前是下面这样配置的,只有一个namenode,因此直接配置了哪一个NN的路径,这里使用服务id
<property>
<name>fs.defaultFS</name>
<value>hdfs://node1:9000</value>
</property>
//顺便再作一个修改
//把NN和DN存储数据位置的目录再改变一下
<property>
<name>hadoop.tmp.dir</name>
<value>/var/hadoop/ha</value>
</property>
复制代码
- dfs.journalnode.edits.dir - the path where the JournalNode daemon will store its local state
- journalnode产生的日志存在节点的哪一个目录下
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/var/hadoop/ha/journalnode</value>
</property>
复制代码
4、配置zookeeper
- The configuration of automatic failover requires the addition of two new parameters to your configuration. In your
hdfs-site.xml
file, add:
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
复制代码
- This specifies that the cluster should be set up for automatic failover. In your
core-site.xml
file, add:
<property>
<name>ha.zookeeper.quorum</name>
<value>node2:2181,node3:2181,node4:2181</value>
</property>
复制代码
5、启动前准备
- 把修改好的core-site.xml和hdfs-site.xml分发到其余节点
6、zookeeper配置文件修改
- 打开zookeeper软件的
/conf/zoo_sample.cfg
目录
#1. 更名
mv zoo_sample.cfg zoo.cfg
#2. 配置文件修改
#autopurge.purgeInterval=1
#autopurge.purgeInterval=1
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
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=/var/hadoop/zk
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1
//添加下面三行(有几台服务器参与,以继通讯端口)
server.1=node2:2888:3888
server.2=node3:2888:3888
server.3=node4:2888:3888
复制代码
- 添加几个文件
- 上面修改了zookeeper配置文件,添加了路径
/var/hadoop/zk
- 在每个要配置zookeeper服务的节点上都要在这个目录的下面建立文件myid
//三台服务器上
echo 1 >> /var/hadoop/zk/myid
echo 2 >> /var/hadoop/zk/myid
echo 3 >> /var/hadoop/zk/myid
复制代码
- 配置zookeeper环境变量
7、执行
- 启动zookeeper
- 启动命令
zkServer.sh start
- 做用在node2,node3,node4
- 启动后,状态以下
[root@node4 hadoop]
7590 QuorumPeerMain
7607 Jps
复制代码
[root@node4 conf]
JMX enabled by default
Using config: /opt/hadoop/zookeeper-3.4.6/bin/../conf/zoo.cfg
//说明这个节点是zookeeper集群主节点
Mode: leader
复制代码
- 启动journalnode(第一次启动集群时执行,之后不用执行)
- 启动命令:
hadoop-daemon.sh start journalnode
- 做用在node1,node2,node2
- 产生了一个新的进程
[root@node1 hadoop]
7912 Jps
7866 JournalNode
复制代码
- 格式化hdfs(第一次启动集群时执行,之后不用执行)
- hdfs在zookeeper上注册(第一次启动集群时执行,之后不用执行)
- hdfs在zookeeper上建立本身的节点
- 使用命令
hdfs zkfc -formatZK
- zookeeper能够同时维护多个集群的信息,因此这个命令的意思就是把这个集群的信息格式化到zookeeper上
- zookeeper会建立一个
/hadoop-ha/mycluster
目录在保存这个集群的全部信息
- 启动集群
start-dfs.sh
- 要说明的是zkfc进程不须要手动启动,它会随集群本身启动
//node1
[root@node1 ~]
7185 Jps
6603 NameNode
7116 DFSZKFailoverController
6462 JournalNode
//node2
[root@node2 ~]
6945 Jps
6770 DataNode
6899 DFSZKFailoverController
6700 NameNode
6445 QuorumPeerMain
6494 JournalNode
//node3
[root@node3 ~]
6629 DataNode
6492 JournalNode
6718 Jps
6447 QuorumPeerMain
//node4
[root@node4 ~]
6454 QuorumPeerMain
6598 DataNode
6667 Jps
复制代码