这是我参与更文挑战的第11天,活动详情查看:更文挑战
高可用HA
概念
一、hadoop1.0的局限
- namenode的问题
- 单点故障:只有一个namenode
- 单点瓶颈:一个namenode,可能内存不足以管理所有datanode
二、高可用(high availability)
- 用于解决单点故障
- hadoop2.0只支持2个节点的HA,3.0可以一主多从
- 如果主节点(master)出现故障,就转到备用节点(stand by)
- HA的架构
- HDFS的高可靠性(HA)主要体现在利用zookeeper实现主备NameNode,以解决单点NameNode故障问题。
- ZooKeeper主要用来存储HA下的状态文件,主备信息。 ZK个数建议3个及以上且为奇数
个
- 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集群
- 把多个journalnode节点部署在不同的服务器上,其实每个节点都是接收相同信息,多个节点就是为了防止单点故障
- 主NN把数据往journalnode节点里写,备份NN从journalnode里读数据
- 过半机制(弱一致性):允许一小半的journalnode节点失效
- 主NN写数据不一定要所有journalnode都确定写入完成,允许有一小半失效
- 一般会配置奇数个journalnode节点
- 比如3个允许1个失效,5个允许两个失效
- 既然静态数据信息都由NN自己处理完成,那么有两个NN,要怎么同步这两个NN的信息呢?
- 两个NN必须同步数据信息
- 元数据持久化
- 主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
三、联邦(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高可用搭建
一、各服务节点安装位置
- ZK位置任意,必须先启动(它要确定主NN)
- ZKFC必须在NN上
- JNN位置任意
二、准备
- 实现node1和node2之间免密登录
- 由于node1、node2都为NN,因此它们故障时需要切换,所以这两个node之间要配置SSH免密
三、配置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
- 通过这个配置映射到真正的namenode地址
<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
- 故障转移的时候使用的java代理类是什么
<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>
复制代码
四、配置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>
复制代码
五、启动前准备
- 把修改好的core-site.xml和hdfs-site.xml分发到其他节点
六、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配置文件,添加了路径
- 配置zookeeper环境变量
七、执行
- 启动zookeeper
- 启动命令
zkServer.sh start
- 作用在node2,node3,node4
- 启动后,状态如下
[root@node4 hadoop]# jps 7590 QuorumPeerMain 7607 Jps 复制代码
- 可以通过命令查看每个节点的状态
[root@node4 conf]# zkServer.sh status 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]# jps 7912 Jps 7866 JournalNode 复制代码
- 启动命令:
- 格式化hdfs(第一次启动集群时执行,以后不用执行)
- 随机选择一个NN执行
hdfs namenode -format
- 只需在一个节点上执行一遍格式化命令,多次执行的话,集群id就不一致了
- 那么我们有两个NN,怎么让它们两个都格式化呢?
- 先启动格式化好的那个NN
hadoop-daemon.sh start namenode
//该NN现有进程 [root@node1 ~]# jps 6673 Jps 6603 NameNode 6462 JournalNode 复制代码
- 在另一个NN上执行
hdfs namenode -bootstrapStandby
把启动的那个NN的数据复制到这台NN所在服务器上
- 先启动格式化好的那个NN
- 随机选择一个NN执行
- hdfs在zookeeper上注册(第一次启动集群时执行,以后不用执行)
- hdfs在zookeeper上创建自己的节点
- 使用命令
hdfs zkfc -formatZK
- zookeeper可以同时维护多个集群的信息,所以这个命令的意思就是把这个集群的信息格式化到zookeeper上
- zookeeper会创建一个
/hadoop-ha/mycluster
目录在保存这个集群的所有信息
- 启动集群
start-dfs.sh
- 要说明的是zkfc进程不需要手动启动,它会随集群自己启动
//node1 [root@node1 ~]# jps 7185 Jps 6603 NameNode 7116 DFSZKFailoverController 6462 JournalNode //node2 [root@node2 ~]# jps 6945 Jps 6770 DataNode 6899 DFSZKFailoverController 6700 NameNode 6445 QuorumPeerMain 6494 JournalNode //node3 [root@node3 ~]# jps 6629 DataNode 6492 JournalNode 6718 Jps 6447 QuorumPeerMain //node4 [root@node4 ~]# jps 6454 QuorumPeerMain 6598 DataNode 6667 Jps 复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END