Hadoop学习03——高可用HA搭建

这是我参与更文挑战的第11天,活动详情查看:更文挑战html

高可用HA

概念

1、hadoop1.0的局限

  1. namenode的问题
    • 单点故障:只有一个namenode
    • 单点瓶颈:一个namenode,可能内存不足以管理全部datanode

2、高可用(high availability)

  • 用于解决单点故障
  • hadoop2.0只支持2个节点的HA,3.0能够一主多从
  • 若是主节点(master)出现故障,就转到备用节点(stand by)
  1. HA的架构

01.jpg

  • 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部署在一块儿,二者个数相同。
  • 元数据同步
  1. 两个NN的数据同步:两个namenode并非同时在工做,同时间只有一个NN在工做
    1. 两个NN必须同步数据信息
      • 块位置信息(block imformation),它是由datanode处理的,而且要向NN汇报————动态数据信息
      • 偏移量,大小,id,这些都是由NN本身来处理完成————静态信息
    2. 动态信息的同步
      • 由DN向NN汇报
      • 由原来的DN向单一NN汇报变成向多个NN汇报
    3. 静态信息的同步
      • 既然静态数据信息都由NN本身处理完成,那么有两个NN,要怎么同步这两个NN的信息呢?
        • 使用journalnode集群
      • 把多个journalnode节点部署在不一样的服务器上,其实每一个节点都是接收相同信息,多个节点就是为了防止单点故障
      • 主NN把数据往journalnode节点里写,备份NN从journalnode里读数据
      • 过半机制(弱一致性):容许一小半的journalnode节点失效
        • 主NN写数据不必定要全部journalnode都肯定写入完成,容许有一小半失效
        • 通常会配置奇数个journalnode节点
        • 好比3个容许1个失效,5个容许两个失效
  2. 元数据持久化
    • 主NameNode对外提供服务。生成的Editlog同时写入本地和JN,同时更新主NameNode内存中的元数据。
    • 备NameNode监控到JN上Editlog变化时,加载Editlog进内存,生成新的与主NameNode同样的元数据。元数据同步完成。
    • 主备的FSImage仍保存在各自的磁盘中,不发生交互。 FSImage是内存中元数据定时写到本地磁盘的副本,也叫元数据镜像

02.png

  • 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。
  1. zookeeper集群
    • 主NN发生故障时,用于自动切换NN
    • zookeeper会把zkfc进程部署在NN上,进行选举和健康检查,一旦发现NN挂掉了,就会通知stand by NN(注意,zookeeper只会监控状态,切换主从都是NN本身决定的)
    • 一旦主NN挂掉,它当即切换为stand by,而另外一个NN自动切换为active

3、联邦(federation)

  • 解决单点瓶颈
  1. 架构

03.png

  • 产生缘由:单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、各服务节点安装位置

04.png

  • ZK位置任意,必须先启动(它要肯定主NN)
  • ZKFC必须在NN上
  • JNN位置任意

2、准备

  1. 实现node1和node2之间免密登陆
    • 因为node一、node2都为NN,所以它们故障时须要切换,因此这两个node之间要配置SSH免密

3、配置hdfs-site.xml

  1. 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>
复制代码
  1. 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>
复制代码
  1. 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>
复制代码
  1. 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>
复制代码
  1. 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>
复制代码
  1. 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>
复制代码
  1. 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>
复制代码
  1. 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>
复制代码
  1. 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

  1. 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>
复制代码
  1. 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、启动前准备

  1. 把修改好的core-site.xml和hdfs-site.xml分发到其余节点

6、zookeeper配置文件修改

  1. 打开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
复制代码
  1. 添加几个文件
    • 上面修改了zookeeper配置文件,添加了路径/var/hadoop/zk
    • 在每个要配置zookeeper服务的节点上都要在这个目录的下面建立文件myid
    //三台服务器上
    echo 1 >> /var/hadoop/zk/myid
    echo 2 >> /var/hadoop/zk/myid
    echo 3 >> /var/hadoop/zk/myid
    复制代码
  2. 配置zookeeper环境变量

7、执行

  1. 启动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
    复制代码
  2. 启动journalnode(第一次启动集群时执行,之后不用执行)
    • 启动命令:hadoop-daemon.sh start journalnode
    • 做用在node1,node2,node2
    • 产生了一个新的进程
    [root@node1 hadoop]# jps
    7912 Jps
    7866 JournalNode
    复制代码
  3. 格式化hdfs(第一次启动集群时执行,之后不用执行)
    • 随机选择一个NN执行hdfs namenode -format
    • 只需在一个节点上执行一遍格式化命令,屡次执行的话,集群id就不一致了
    • 那么咱们有两个NN,怎么让它们两个都格式化呢?
      • 先启动格式化好的那个NNhadoop-daemon.sh start namenode
      //该NN现有进程
      [root@node1 ~]# jps
      6673 Jps
      6603 NameNode
      6462 JournalNode
      复制代码
      • 在另外一个NN上执行hdfs namenode -bootstrapStandby把启动的那个NN的数据复制到这台NN所在服务器上
  4. hdfs在zookeeper上注册(第一次启动集群时执行,之后不用执行)
    • hdfs在zookeeper上建立本身的节点
    • 使用命令hdfs zkfc -formatZK
    • zookeeper能够同时维护多个集群的信息,因此这个命令的意思就是把这个集群的信息格式化到zookeeper上
    • zookeeper会建立一个/hadoop-ha/mycluster目录在保存这个集群的全部信息
  5. 启动集群
    • 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
    复制代码