zoukankan      html  css  js  c++  java
  • 【Hadoop 】第五天 Hadoop-HA 搭建

    问题

    Hadoop 1.0存在的问题:单点故障和内存受限

    1. NameNode单点故障:NameNode只有一个,一旦宕机了,则数据就会丢失,虽然有配置SecondaryNameNode,但是SecondardyNameNode合并元数据和日志文件需要时间的,所有还是会有部分数据会丢失(edits)
    2. NameNode压力大:单节点只有一个NameNode,所有的请求都访问一个NameNode

    Hadoop 2.0解决方案:

    1. 单点故障:HA(通过主备NameNode解决,如果主NameNode发生故障,则切换到备NameNode上)
    2. 内存受限问题:F(HDFS Federation 联邦) NameService
      水平扩展,支持多个NameNode,每一个NameNode分管一部分目录,并且所有 NameNode 共享 DateNode 存储资源

    现在只讨论HA的实现:

    HA:客户端只有和一个NameNode(主)进行通信,而元数据部分是如何和NameNode(备)进行共享的?(首先dataNode 的信息是共享的,主NameNode和备NameNode这部分信息是一致的,而元数据不一样,不是实时的)

    1. 想法一:主Namenode和备Namenode之间建立一个socket通信(阻塞型通信),这样两个NameNode和DataNode的元数据就是一致的了(同时会引发一个问题,IO网络通信的问题,如果之间网络一旦出现问题,则客户端会认为主Namenode出现了问题,因为整个流程是这样的,客户端发送一个请求给主NameNode,然后主Namenode再发送给备Namenode,而此时网络发生波动的话,请求就会一直阻塞在那里直到备NameNode返回成功的状态,所以客户端会认为是主Namenode有问题),所以这个想法不可行。

    2. 想法二:主NameNode和备NameNode之间建立一个非阻塞的通信(就是客户端发送请求给主Namenode,然后主NameNode再发送给备NameNode,不需要等待备NameNode的返回状态,这样的话如果备NameNode发生问题,就会导致两个NameNode之间元数据不一致)所以这个想法也不可行。

    3. 想法三:当客户端发送请求给主NameNode时,元数据写到一个共享的磁盘中(两个Namenode都可以访问),这样元数据就可以保持一致了。这种技术就叫做NFS技术。但是NFS运维成本太高,所以Hadoop本身开发了一种技术,==JNN(JournalNode)==还是集群部署的,(保证了NameNode的高可用性)

    ZooKeeper:在HDFS-HA搭建的过程中起着分布式协调作用

    ZooKeeperFailOverController : Hadoop 配置ZKFC来实现自动故障转移,这两个都是在namenode上的JVM进程,用来监测主NameNode是否发生宕机的,如果发送宕机则向ZooKeeper汇报,ZooKeeper将原先注册的锁事件进行删除,然后ZooKeeper在锁事件删除后会回调备用NameNode发送的锁请求,将自动将备用NameNode变成主Namenode,并且备Namenode的状态由standby变成了Active

    1. ZooKeeper提供目录结构树机制,两个ZKFC进行资源抢夺,谁抢夺上了,谁就可以在ZooKeeper上建立一个节点目录,并且创建一把锁,与此同时将与自身关联的Namenode的状态置为Active活跃状态(主Namenode),另一个置为standBy(静态的也叫备NameNode)。

    2. 事件回调和监控,ZKFC一旦监测到主NameNode发生宕机,则主Namenode节点上的ZKFC会将ZooKeeper上创建的节点目录进行删除,此时ZooKeeper会回调之前备ZKFC在ZooKeeper上注册的事件,将备ZKFC从standBy变成Active的状态。

    3. Session机制:如果ZKFC的进程挂了,那么tcp连接就会断开,tcp断开有个会话超时时间范围,一旦超过这个范围,ZooKeeper就会将主ZKFC之前注册的节点进行删除事件的操作,此时ZooKeeper就会回调备ZKFC注册的节点事件,将备ZKFC下的Namenode进行状态转换为Active,并且同时将主Namenode的状态变成standBy,这样的话就不会同时存在两个Active的NameNode。

    ZKFC(ZooKeeper Failover Controller)和namenode是在同一个节点上。

    搭建图

    HDFS

    在这里插入图片描述

    非HA跟HA框架图

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    HA搭建框架图

    在这里插入图片描述
    在这里插入图片描述
    前期准备就不详细说了 前面的学习都有

    1. 修改Linux主机名
    2. 修改IP
    3. 修改主机名和IP的映射关系
      注意如果你们公司是租用的服务器或是使用的云主机(如华为用主机、阿里云主机等)/etc/hosts里面要配置的是内网IP地址和主机名的映射关系
    4. 关闭防火墙
    5. ssh免登陆
    6. 安装JDK,配置环境变量等

    集群规划:

    主机名 IP 安装的软件 运行的进程
    weekend01 192.168.1.201 jdk、hadoop NameNode、DFSZKFailoverController(ZKFC)
    weekend02 192.168.1.202 jdk、hadoop NameNode、DFSZKFailoverController(ZKFC)
    weekend03 192.168.1.203 jdk、hadoop ResourceManager
    weekend04 192.168.1.204 jdk、hadoop ResourceManager
    weekend05 192.168.1.205 jdk、hadoop、zookeeper DataNode、NodeManager、JournalNode、QuorumPeerMainr
    weekend06 192.168.1.206 jdk、hadoop、zookeeper DataNode、NodeManager、JournalNode、QuorumPeerMainr
    weekend07 192.168.1.207 jdk、hadoop、zookeeper DataNode、NodeManager、JournalNode、QuorumPeerMainr

    说明:

    1. 在hadoop2.0中通常由两个NameNode组成,一个处于active状态,另一个处于standby状态。Active NameNode对外提供服务,而Standby NameNode则不对外提供服务,仅同步active namenode的状态,以便能够在它失败时快速进行切换。

      hadoop2.0官方提供了两种HDFS HA的解决方案,一种是NFS,另一种是QJM。这里我们使用简单的QJM。在该方案中,主备NameNode之间通过一组JournalNode(JN)同步元数据信息,一条数据只要成功写入多数JournalNode即认为写入成功。通常配置奇数个JournalNode(底层也用到了 ZooKeeper)

      这里还配置了一个zookeeper集群,用于ZKFC(DFSZKFailoverController)故障转移,当Active NameNode挂掉了,会自动切换Standby NameNode为standby状态

    2. hadoop-2.2.0中依然存在一个问题,就是 ResourceManager只有一个,存在单点故障,hadoop-2.4.1解决了这个问题,有两个ResourceManager,一个是Active,一个是Standby,状态由 ZooKeeper 进行协调

    ZooKeeper 安装

    1.安装配置zooekeeper集群(在weekend05上)
    1.1解压
    tar -zxvf zookeeper-3.4.5.tar.gz -C /weekend/
    1.2修改配置
    cd /weekend/zookeeper-3.4.5/conf/
    cp zoo_sample.cfg zoo.cfg
    vim zoo.cfg
    修改:dataDir=/weekend/zookeeper-3.4.5/tmp
    在最后添加:
    server.1=weekend05:2888:3888
    server.2=weekend06:2888:3888
    server.3=weekend07:2888:3888
    保存退出
    然后创建一个tmp文件夹
    mkdir /weekend/zookeeper-3.4.5/tmp
    再创建一个空文件
    touch /weekend/zookeeper-3.4.5/tmp/myid
    最后向该文件写入ID
    echo 1 > /weekend/zookeeper-3.4.5/tmp/myid
    1.3将配置好的zookeeper拷贝到其他节点(首先分别在weekend06、weekend07根目录下创建一个weekend目录:mkdir /weekend)
    scp -r /weekend/zookeeper-3.4.5/ weekend06:/weekend/
    scp -r /weekend/zookeeper-3.4.5/ weekend07:/weekend/
    注意:修改weekend06、weekend07对应/weekend/zookeeper-3.4.5/tmp/myid内容
    weekend06:
    echo 2 > /weekend/zookeeper-3.4.5/tmp/myid
    weekend07:
    echo 3 > /weekend/zookeeper-3.4.5/tmp/myid

    hadoop安装配置

    2.安装配置hadoop集群(在weekend01上操作)
    	2.1解压
    		tar -zxvf hadoop-2.4.1.tar.gz -C /weekend/
    	2.2配置HDFS(hadoop2.0所有的配置文件都在$HADOOP_HOME/etc/hadoop目录下)
    		#将hadoop添加到环境变量中
    		vim /etc/profile
    		export JAVA_HOME=/usr/java/jdk1.7.0_55
    		export HADOOP_HOME=/weekend/hadoop-2.4.1
    		export PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin
    		
    		#hadoop2.0的配置文件全部在$HADOOP_HOME/etc/hadoop下
    		cd /home/hadoop/app/hadoop-2.4.1/etc/hadoop
    		
    	2.2.1修改hadoo-env.sh
    			export JAVA_HOME=/home/hadoop/app/jdk1.7.0_55
    

    core-site.xml

    		2.2.2修改core-site.xml
    			<configuration>
    				<!-- 指定hdfs的 nameservice 为ns1 -->
    				<property>
    					<name>fs.defaultFS</name>
    					<value>hdfs://ns1/</value>
    				</property>
    				<!-- 指定hadoop临时目录 -->
    				<property>
    					<name>hadoop.tmp.dir</name>
    					<value>/home/hadoop/app/hadoop-2.4.1/tmp</value>
    				</property>
    				
    				<!-- 故障转移需要的 zookeeper 集群设置一下-->
    				<property>
    					<name>ha.zookeeper.quorum</name>
    					<value>weekend05:2181,weekend06:2181,weekend07:2181</value>
    				</property>
    			</configuration>
    

    HDFS-site.xml

    			<configuration>
    				<!--指定hdfs的 nameservice 为 ns1,需要和core-site.xml中的保持一致 -->
    				<property>
    					<name>dfs.nameservices</name>
    					<value>ns1</value>
    				</property>
    				<!-- ns1下面有两个NameNode,分别是nn1,nn2 -->
    				<property>
    					<name>dfs.ha.namenodes.ns1</name>
    					<value>nn1,nn2</value>
    				</property>
    				<!-- nn1的RPC通信地址 -->
    				<property>
    					<name>dfs.namenode.rpc-address.ns1.nn1</name>
    					<value>weekend01:9000</value>
    				</property>
    				<!-- nn1的http通信地址 -->
    				<property>
    					<name>dfs.namenode.http-address.ns1.nn1</name>
    					<value>weekend01:50070</value>
    				</property>
    				<!-- nn2的RPC通信地址 -->
    				<property>
    					<name>dfs.namenode.rpc-address.ns1.nn2</name>
    					<value>weekend02:9000</value>
    				</property>
    				<!-- nn2的http通信地址 -->
    				<property>
    					<name>dfs.namenode.http-address.ns1.nn2</name>
    					<value>weekend02:50070</value>
    				</property>
    				<!-- 指定 NameNode 的元数据在 JournalNode 上的存放位置 -->
    				<property>
    					<name>dfs.namenode.shared.edits.dir</name>
    					<value>qjournal://weekend05:8485;weekend06:8485;weekend07:8485/ns1</value>
    				</property>
    				<!-- 指定JournalNode在本地磁盘存放数据的位置 -->
    				<property>
    					<name>dfs.journalnode.edits.dir</name>
    					<value>/home/hadoop/app/hadoop-2.4.1/journaldata</value>
    				</property>
    				<!-- 开启NameNode失败自动切换 -->
    				<property>
    					<name>dfs.ha.automatic-failover.enabled</name>
    					<value>true</value>
    				</property>
    				<!-- 配置失败自动切换实现方式 -->
    				<property>
    					<name>dfs.client.failover.proxy.provider.ns1</name>
    					<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
    				</property>
    				<!-- 配置隔离机制方法,多个机制用换行分割,即每个机制暂用一行-->
    				<property>
    					<name>dfs.ha.fencing.methods</name>
    					<value>
    						sshfence
    						shell(/bin/true)
    					</value>
    				</property>
    				<!-- 使用sshfence隔离机制时需要ssh免登陆 -->
    				<property>
    					<name>dfs.ha.fencing.ssh.private-key-files</name>
    					<value>/home/hadoop/.ssh/id_rsa</value>
    				</property>
    				<!-- 配置sshfence隔离机制超时时间 -->
    				<property>
    					<name>dfs.ha.fencing.ssh.connect-timeout</name>
    					<value>30000</value>
    				</property>
    			</configuration>
    

    mapred-site.xml

    			<configuration>
    				<!-- 指定mr框架为yarn方式 -->
    				<property>
    					<name>mapreduce.framework.name</name>
    					<value>yarn</value>
    				</property>
    			</configuration>
    

    yarn-site.xml

    			<configuration>
    					<!-- 开启RM高可用 -->
    					<property>
    					   <name>yarn.resourcemanager.ha.enabled</name>
    					   <value>true</value>
    					</property>
    					<!-- 指定RM的cluster id -->
    					<property>
    					   <name>yarn.resourcemanager.cluster-id</name>
    					   <value>yrc</value>
    					</property>
    					<!-- 指定RM的名字 -->
    					<property>
    					   <name>yarn.resourcemanager.ha.rm-ids</name>
    					   <value>rm1,rm2</value>
    					</property>
    					<!-- 分别指定RM的地址 -->
    					<property>
    					   <name>yarn.resourcemanager.hostname.rm1</name>
    					   <value>weekend03</value>
    					</property>
    					<property>
    					   <name>yarn.resourcemanager.hostname.rm2</name>
    					   <value>weekend04</value>
    					</property>
    					<!-- 指定zk集群地址 -->
    					<property>
    					   <name>yarn.resourcemanager.zk-address</name>
    					   <value>weekend05:2181,weekend06:2181,weekend07:2181</value>
    					</property>
    					<property>
    					   <name>yarn.nodemanager.aux-services</name>
    					   <value>mapreduce_shuffle</value>
    					</property>
    			</configuration>
    

    修改slave

    		2.2.6修改slaves(slaves是指定子节点的位置,因为要在weekend01上启动HDFS、在weekend03启动yarn,
    		所以weekend01上的slaves文件指定的是datanode的位置,weekend03上的slaves文件指定的是nodemanager的位置)
    			weekend05
    			weekend06
    			weekend07
    

    配置免密码登陆

    			#首先要配置weekend01到weekend02、weekend03、weekend04、weekend05、weekend06、weekend07的免密码登陆
    			#在weekend01上生产一对钥匙
    			ssh-keygen -t rsa
    			#将公钥拷贝到其他节点,包括自己
    			ssh-coyp-id weekend01
    			ssh-coyp-id weekend02
    			ssh-coyp-id weekend03
    			ssh-coyp-id weekend04
    			ssh-coyp-id weekend05
    			ssh-coyp-id weekend06
    			ssh-coyp-id weekend07
    			
    			#配置weekend03到weekend04、weekend05、weekend06、weekend07的免密码登陆
    			#在weekend03上生产一对钥匙
    			ssh-keygen -t rsa
    			#将公钥拷贝到其他节点
    			ssh-coyp-id weekend04
    			ssh-coyp-id weekend05
    			ssh-coyp-id weekend06
    			ssh-coyp-id weekend07
    			#注意:两个namenode之间要配置ssh免密码登陆,别忘了配置weekend02到weekend01的免登陆
    			在weekend02上生产一对钥匙
    			ssh-keygen -t rsa
    			ssh-coyp-id -i weekend01
    

    将配置好的hadoop拷贝到其他节点

    		scp -r /weekend/ weekend02:/
    		scp -r /weekend/ weekend03:/
    		scp -r /weekend/hadoop-2.4.1/ hadoop@weekend04:/weekend/
    		scp -r /weekend/hadoop-2.4.1/ hadoop@weekend05:/weekend/
    		scp -r /weekend/hadoop-2.4.1/ hadoop@weekend06:/weekend/
    		scp -r /weekend/hadoop-2.4.1/ hadoop@weekend07:/weekend/	
    

    启动zookeeper集群(分别在weekend05、weekend06、tcast07上启动zk)

    		cd /weekend/zookeeper-3.4.5/bin/
    		./zkServer.sh start
    		#查看状态:一个leader,两个follower
    		./zkServer.sh status
    

    启动journalnode(分别在在weekend05、weekend06、tcast07上执行)

    		cd /weekend/hadoop-2.4.1
    		sbin/hadoop-daemon.sh start journalnode
    		#运行jps命令检验,weekend05、weekend06、weekend07上多了 JournalNode 进程
    

    格式化HDFS
    #在weekend01上执行命令:
    hdfs namenode -format
    #格式化后会在根据core-site.xml中的hadoop.tmp.dir配置生成个文件,这里我配置的是/weekend/hadoop-2.4.1/tmp,然后将/weekend/hadoop-2.4.1/tmp拷贝到weekend02的/weekend/hadoop-2.4.1/下。
    scp -r tmp/ weekend02:/home/hadoop/app/hadoop-2.4.1/
    ##也可以这样,建议hdfs namenode -bootstrapStandby

    2.8格式化ZKFC(在weekend01上执行即可)

    		hdfs zkfc -formatZK	
    

    启动HDFS(在weekend01上执行)

    		sbin/start-dfs.sh	
    

    2.10启动YARN

    (注意:是在weekend03上执行start-yarn.sh,把namenode和resourcemanager分开是因为性能问题,因为他们都要占用大量资源,所以把他们分开了,他们分开了就要分别在不同的机器上启动)
    sbin/start-yarn.sh

    到此,hadoop-2.4.1配置完毕,可以统计浏览器访问:
    	http://192.168.1.201:50070
    	NameNode 'weekend01:9000' (active)
    	http://192.168.1.202:50070
    	NameNode 'weekend02:9000' (standby)
    

    验证HDFS HA

    	首先向hdfs上传一个文件
    	hadoop fs -put /etc/profile /profile
    	hadoop fs -ls /
    	然后再kill掉 active的 NameNode
    	kill -9 <pid of NN>
    	通过浏览器访问:http://192.168.1.202:50070
    	NameNode 'weekend02:9000' (active)
    	这个时候weekend02上的NameNode变成了active
    	在执行命令:
    	hadoop fs -ls /
    	-rw-r--r--   3 root supergroup       1926 2014-02-06 15:36 /profile
    	刚才上传的文件依然存在!!!
    	手动启动那个挂掉的NameNode
    	sbin/hadoop-daemon.sh start namenode
    	通过浏览器访问:http://192.168.1.201:50070
    	NameNode 'weekend01:9000' (standby)
    

    验证YARN:

    	运行一下hadoop提供的demo中的WordCount程序:
    	hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.4.1.jar wordcount /profile /out
    
    OK,大功告成!!!
    

    测试集群工作状态的一些指令 :

    bin/hdfs dfsadmin -report 查看hdfs的各节点状态信息
    bin/hdfs haadmin -getServiceState nn1 获取一个namenode节点的HA状态
    sbin/hadoop-daemon.sh start namenode 单独启动一个namenode进程
    ./hadoop-daemon.sh start zkfc 单独启动一个zkfc进程

    HDFS冗余数据块的自动删除

    在日常维护hadoop集群的过程中发现这样一种情况:
    某个节点由于网络故障或者DataNode进程死亡,被NameNode判定为死亡,
    HDFS马上自动开始数据块的容错拷贝;
    当该节点重新添加到集群中时,由于该节点上的数据其实并没有损坏,
    所以造成了HDFS上某些block的备份数超过了设定的备份数。
    通过观察发现,这些多余的数据块经过很长的一段时间才会被完全删除掉,
    那么这个时间取决于什么呢?
    该时间的长短跟数据块报告的间隔时间有关。
    Datanode会定期将当前该结点上所有的BLOCK信息报告给Namenode,
    参数dfs.blockreport.intervalMsec就是控制这个报告间隔的参数。

    hdfs-site.xml文件中有一个参数:
    
    dfs.blockreport.intervalMsec 10000 Determines block reporting interval in milliseconds. 其中3600000为默认设置,3600000毫秒,即1个小时,也就是说,块报告的时间间隔为1个小时,所以经过了很长时间这些多余的块才被删除掉。通过实际测试发现,当把该参数调整的稍小一点的时候(60秒),多余的数据块确实很快就被删除了。

    hadoop datanode节点超时时间设置

    datanode进程死亡或者网络故障造成datanode无法与namenode通信,namenode不会立即把该节点判定为死亡,要经过一段时间,这段时间暂称作超时时长。
    HDFS默认的超时时长为10分钟+30秒。如果定义超时时间为timeout,则超时时长的计算公式为:
    timeout = 2 * heartbeat.recheck.interval + 10 * dfs.heartbeat.interval。
    而默认的heartbeat.recheck.interval 大小为5分钟,dfs.heartbeat.interval默认为3秒。
    需要注意的是hdfs-site.xml 配置文件中的
    heartbeat.recheck.interval的单位为毫秒,
    dfs.heartbeat.interval的单位为秒。
    所以,举个例子,如果heartbeat.recheck.interval设置为5000(毫秒),dfs.heartbeat.interval设置为3(秒,默认),则总的超时时间为40秒。

    hdfs-site.xml中的参数设置格式:

    <property>
    <name>heartbeat.recheck.interval</name>
    <value>2000</value>
    </property>
    <property>
    <name>dfs.heartbeat.interval</name>
    <value>1</value>
    </property>
    

    复习

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    Hadoop机架感知

    1.背景

    Hadoop在设计时考虑到数据的安全与高效,数据文件默认在HDFS上存放三份,存储策略为本地一份,同机架内其它某一节点上一份,不同机架的某一节点上一份。这样如果本地数据损坏,节点可以从同一机架内的相邻节点拿到数据,速度肯定比从跨机架节点上拿数据要快;同时,如果整个机架的网络出现异常,也能保证在其它机架的节点上找到数据。为了降低整体的带宽消耗和读取延时,HDFS会尽量让读取程序读取离它最近的副本。如果在读取程序的同一个机架上有一个副本,那么就读取该副本。如果一个HDFS集群跨越多个数据中心,那么客户端也将首先读本地数据中心的副本。那么Hadoop是如何确定任意两个节点是位于同一机架,还是跨机架的呢?答案就是机架感知。
    默认情况下,hadoop的机架感知是没有被启用的。所以,在通常情况下,hadoop集群的HDFS在选机器的时候,是随机选择的,也就是说,很有可能在写数据时,hadoop将第一块数据block1写到了rack1上,然后随机的选择下将block2写入到了rack2下,此时两个rack之间产生了数据传输的流量,再接下来,在随机的情况下,又将block3重新又写回了rack1,此时,两个rack之间又产生了一次数据流量。在job处理的数据量非常的大,或者往hadoop推送的数据量非常大的时候,这种情况会造成rack之间的网络流量成倍的上升,成为性能的瓶颈,进而影响作业的性能以至于整个集群的服务

    2. 配置

    默认情况下,namenode启动时候日志是这样的:
    2013-09-22 17:27:26,423 INFO org.apache.hadoop.net.NetworkTopology: Adding a new node: /default-rack/ 192.168.147.92:50010
    每个IP 对应的机架ID都是 /default-rack ,说明hadoop的机架感知没有被启用。
    要将hadoop机架感知的功能启用,配置非常简单,在 NameNode所在节点的/home/bigdata/apps/hadoop/etc/hadoop的core-site.xml配置文件中配置一个选项:

    <property>
      <name>topology.script.file.name</name>
      <value>/home/bigdata/apps/hadoop/etc/hadoop/topology.sh</value>
    </property>
    

    这个配置选项的value指定为一个可执行程序,通常为一个脚本,该脚本接受一个参数,输出一个值。接受的参数通常为某台datanode机器的ip地址,而输出的值通常为该ip地址对应的datanode所在的rack,例如”/rack1”。Namenode启动时,会判断该配置选项是否为空,如果非空,则表示已经启用机架感知的配置,此时namenode会根据配置寻找该脚本,并在接收到每一个datanode的heartbeat时,将该datanode的ip地址作为参数传给该脚本运行,并将得到的输出作为该datanode所属的机架ID,保存到内存的一个map中.
    至于脚本的编写,就需要将真实的网络拓朴和机架信息了解清楚后,通过该脚本能够将机器的ip地址和机器名正确的映射到相应的机架上去。一个简单的实现如下:

    #!/bin/bash
    HADOOP_CONF=/home/bigdata/apps/hadoop/etc/hadoop
    while [ $# -gt 0 ] ; do
      nodeArg=$1
      exec<${HADOOP_CONF}/topology.data
      result=""
      while read line ; do
        ar=( $line )
        if [ "${ar[0]}" = "$nodeArg" ]||[ "${ar[1]}" = "$nodeArg" ]; then
          result="${ar[2]}"
        fi
      done
      shift
      if [ -z "$result" ] ; then
        echo -n "/default-rack"
      else
        echo -n "$result"
      fi
      done
    

    topology.data,格式为:节点(ip或主机名) /交换机xx/机架xx

    192.168.147.91 tbe192168147091 /dc1/rack1
    192.168.147.92 tbe192168147092 /dc1/rack1
    192.168.147.93 tbe192168147093 /dc1/rack2
    192.168.147.94 tbe192168147094 /dc1/rack3
    192.168.147.95 tbe192168147095 /dc1/rack3
    192.168.147.96 tbe192168147096 /dc1/rack3
    

    需要注意的是,在Namenode上,该文件中的节点必须使用IP,使用主机名无效,而Jobtracker上,该文件中的节点必须使用主机名,使用IP无效,所以,最好ip和主机名都配上。
    这样配置后,namenode启动时候日志是这样的:
    2013-09-23 17:16:27,272 INFO org.apache.hadoop.net.NetworkTopology: Adding a new node: /dc1/rack3/ 192.168.147.94:50010
    说明hadoop的机架感知已经被启用了。
    查看HADOOP机架信息命令:

    ./hadoop dfsadmin -printTopology 
    Rack: /dc1/rack1
       192.168.147.91:50010 (tbe192168147091)
       192.168.147.92:50010 (tbe192168147092)
    
    Rack: /dc1/rack2
       192.168.147.93:50010 (tbe192168147093)
    
    Rack: /dc1/rack3
       192.168.147.94:50010 (tbe192168147094)
       192.168.147.95:50010 (tbe192168147095)
       192.168.147.96:50010 (tbe192168147096)
    

    3.增加数据节点,不重启NameNode

    假设Hadoop集群在192.168.147.68上部署了NameNode和DataNode,启用了机架感知,执行bin/hadoop dfsadmin -printTopology看到的结果:
    Rack: /dc1/rack1
    192.168.147.68:50010 (dbj68)
    现在想增加一个物理位置在rack2的数据节点192.168.147.69到集群中,不重启NameNode。
    首先,修改NameNode节点的topology.data的配置,加入:192.168.147.69 dbj69 /dc1/rack2,保存。
    192.168.147.68 dbj68 /dc1/rack1
    192.168.147.69 dbj69 /dc1/rack2
    然后,sbin/hadoop-daemons.sh start datanode启动数据节点dbj69,任意节点执行bin/hadoop dfsadmin -printTopology 看到的结果:

    Rack: /dc1/rack1
       192.168.147.68:50010 (dbj68)
    
    Rack: /dc1/rack2
       192.168.147.69:50010 (dbj69)
    

    说明hadoop已经感知到了新加入的节点dbj69。
    注意:如果不将dbj69的配置加入到topology.data中,执行sbin/hadoop-daemons.sh start datanode启动数据节点dbj69,datanode日志中会有异常发生,导致dbj69启动不成功。

    2013-11-21 10:51:33,502 FATAL org.apache.hadoop.hdfs.server.datanode.DataNode: Initialization failed for block pool Block pool BP-1732631201-192.168.147.68-1385000665316 (storage id DS-878525145-192.168.147.69-50010-1385002292231) service to dbj68/192.168.147.68:9000
    org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.net.NetworkTopology$InvalidTopologyException): Invalid network topology. You cannot have a rack and a non-rack node at the same level of the network topology.
      at org.apache.hadoop.net.NetworkTopology.add(NetworkTopology.java:382)
      at org.apache.hadoop.hdfs.server.blockmanagement.DatanodeManager.registerDatanode(DatanodeManager.java:746)
      at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.registerDatanode(FSNamesystem.java:3498)
      at org.apache.hadoop.hdfs.server.namenode.NameNodeRpcServer.registerDatanode(NameNodeRpcServer.java:876)
      at org.apache.hadoop.hdfs.protocolPB.DatanodeProtocolServerSideTranslatorPB.registerDatanode(DatanodeProtocolServerSideTranslatorPB.java:91)
      at org.apache.hadoop.hdfs.protocol.proto.DatanodeProtocolProtos$DatanodeProtocolService$2.callBlockingMethod(DatanodeProtocolProtos.java:20018)
      at org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker.call(ProtobufRpcEngine.java:453)
      at org.apache.hadoop.ipc.RPC$Server.call(RPC.java:1002)
      at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:1701)
      at org.apache.hadoop.ipc.Server$Handler$1.run(Server.java:1697)
      at java.security.AccessController.doPrivileged(Native Method)
      at javax.security.auth.Subject.doAs(Subject.java:415)
      at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1408)
      at org.apache.hadoop.ipc.Server$Handler.run(Server.java:1695)
    
      at org.apache.hadoop.ipc.Client.call(Client.java:1231)
      at org.apache.hadoop.ipc.ProtobufRpcEngine$Invoker.invoke(ProtobufRpcEngine.java:202)
      at $Proxy10.registerDatanode(Unknown Source)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
      at java.lang.reflect.Method.invoke(Method.java:601)
      at org.apache.hadoop.io.retry.RetryInvocationHandler.invokeMethod(RetryInvocationHandler.java:164)
      at org.apache.hadoop.io.retry.RetryInvocationHandler.invoke(RetryInvocationHandler.java:83)
      at $Proxy10.registerDatanode(Unknown Source)
      at org.apache.hadoop.hdfs.protocolPB.DatanodeProtocolClientSideTranslatorPB.registerDatanode(DatanodeProtocolClientSideTranslatorPB.java:149)
      at org.apache.hadoop.hdfs.server.datanode.BPServiceActor.register(BPServiceActor.java:619)
      at org.apache.hadoop.hdfs.server.datanode.BPServiceActor.connectToNNAndHandshake(BPServiceActor.java:221)
      at org.apache.hadoop.hdfs.server.datanode.BPServiceActor.run(BPServiceActor.java:660)
      at java.lang.Thread.run(Thread.java:722)
    

    4.节点间距离计算

    有了机架感知,NameNode就可以画出下图所示的datanode网络拓扑图。D1,R1都是交换机,最底层是datanode。则H1的rackid=/D1/R1/H1,H1的parent是R1,R1的是D1。这些rackid信息可以通过topology.script.file.name配置。有了这些rackid信息就可以计算出任意两台datanode之间的距离,得到最优的存放策略,优化整个集群的网络带宽均衡以及数据最优分配。

    distance(/D1/R1/H1,/D1/R1/H1)=0  相同的datanode
    distance(/D1/R1/H1,/D1/R1/H2)=2  同一rack下的不同datanode
    distance(/D1/R1/H1,/D1/R2/H4)=4  同一IDC下的不同datanode
    distance(/D1/R1/H1,/D2/R3/H7)=6  不同IDC下的datanode
    

    参考

    HA-hadoop搭建
    itcast-HA搭建
    7台HA搭建
    搭建汇总

    关注公众号 海量干货等你
  • 相关阅读:
    关于重构之Switch的处理【二】
    转,有用
    C#枚举总结和其扩展用法(通过枚举描设置枚举值)
    DataGridView编辑状态和CurrentCellDirtyStateChanged
    C#获取DataGirdView选定子项子控件类型,is,as的用法
    VS2013添加作者注释(C#工程)
    开通博客了 zkh
    CentOS7下在线安装mysql zkh
    设计模式之简单工厂,工厂方法,抽象工厂模式(二) zkh
    asp.net mvc中捕获异常和使用log4net日志记录组件 zkh
  • 原文地址:https://www.cnblogs.com/sowhat1412/p/12734123.html
Copyright © 2011-2022 走看看