目录
一、Zk是用java代码进行操作(了解)
使用java代码操作zk 3.5以下版本,使用的技术还是Curator
二、zk的选举机制
三、Hadoop集群的高可用(HA)
1) 搭建namenode的高可用
Java 代码操作 HA 的 hdfs 代码演示:
2)搭建resourcemanager的高可用
四、NameNode的联邦机制【了解】
一、Zk是用java代码进行操作(了解)
有很多的软件都是可以使用命令,也可以使用代码进行操作:
MySQL -- SQL语句、使用java代码(JDBC)
HDFS -- shell、Java代码
zookeeper -- shell、Java代码
有两种操作方案:
JDBC 的代码--原生的
DBUtils 工具包
1、原生的API进行操作
2、Curator 工具包进行操作(建议同学们学习这个东西)
第一步:导入Curator工具包
<dependency><groupId>org.apache.curator</groupId><artifactId>curator-framework</artifactId><version>4.2.0</version>
</dependency>
<dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>4.2.0</version>
</dependency>
<dependency><groupId>com.google.collections</groupId><artifactId>google-collections</artifactId><version>1.0</version>
</dependency>
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>RELEASE</version>
</dependency>
<dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>1.7.25</version>
</dependency>
package com.bigdata;import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.TreeCache;
import org.apache.curator.framework.recipes.cache.TreeCacheEvent;
import org.apache.curator.framework.recipes.cache.TreeCacheListener;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.zookeeper.CreateMode;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;import java.util.Arrays;
import java.util.List;public class TestZk {CuratorFramework curator =null;@Beforepublic void init(){RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000,2);curator = CuratorFrameworkFactory.newClient("bigdata01:2181", retryPolicy);curator.start();}@Afterpublic void destory(){curator.close();}@Test //public void testCreate() throws Exception {// 一个类的对象如果是null, 使用null调用任何方法,都报空指针异常// 创建一个临时的节点,节点的名字是/hello1curator.create().creatingParentContainersIfNeeded().withMode(CreateMode.PERSISTENT).forPath("/xihu/abcd");//Thread.sleep(20000);}@Test //public void testLs() throws Exception {// 一个类的对象如果是null, 使用null调用任何方法,都报空指针异常// 创建一个临时的节点,节点的名字是/hello1//2、查询子节点:lsList<String> list = curator.getChildren().forPath("/");System.out.println(list);}@Test //public void testSetData() throws Exception {curator.setData().forPath("/xihu/abcd","西湖的水,我的泪".getBytes());}@Testpublic void testGetData() throws Exception{byte[] bytes = curator.getData().forPath("/xihu");System.out.println(new String(bytes));}@Testpublic void testString(){// 只学两个东西: 集合(ArrayList HashSet HashMap) 工具类的API (String) 二八原则// 想将一个字符串变为byte数组String a = "hello";byte[] arr = a.getBytes();System.out.println(Arrays.toString(arr));// 想将一个byte数组变为字符串String str = new String(arr);System.out.println(str);}@Testpublic void testDelete() throws Exception{curator.delete().forPath("/xihu/abc");}// 演示watch 监听@Testpublic void testWatch() throws Exception{TreeCache treeCache = new TreeCache(curator, "/xihu");// 一个接口中只有一个未实现的方法,该接口是函数式接口,函数式接口:lambdatreeCache.getListenable().addListener(new TreeCacheListener() {@Overridepublic void childEvent(CuratorFramework curatorFramework, TreeCacheEvent treeCacheEvent) throws Exception {TreeCacheEvent.Type type = treeCacheEvent.getType();ChildData data = treeCacheEvent.getData();if(type == TreeCacheEvent.Type.NODE_ADDED){System.out.println("/xihu 下创建了一个新的节点");// data.getData() 如果节点没有数据,返回的是IP;如果节点上有数据,返回的是节点的值System.out.println("该节点上的数据是:"+new String(data.getData()));System.out.println("新增了个路径:"+data.getPath());}if(type == TreeCacheEvent.Type.NODE_UPDATED){System.out.println("/xihu 下修改了一个节点");// data.getData() 返回的是IPSystem.out.println("该节点上的数据是:"+new String(data.getData()));System.out.println("修改的路径:"+data.getPath());}if(type == TreeCacheEvent.Type.NODE_REMOVED){System.out.println("删除了个路径:"+data.getPath());}}});treeCache.start();Thread.sleep(1000*100);}@Testpublic void testSwith(){String season= "冬";switch (season){case "冬":System.out.println("冬天冷...");break;case "春":System.out.println("春天来了,冬天还会源码?");break;}}@Testpublic void testEnum(){// WINTER 是枚举类的一个实例化对象Season season = Season.WINTER;switch (season){case WINTER:System.out.println("冬天冷...");break;case SPRING:System.out.println("春天来了,冬天还会源码?");break;}}}
使用java代码操作zk 3.5以下版本,使用的技术还是Curator
第一步:创建项目
第二步:导入包:
<!--zk的客户端( curator )-->
<dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>2.7.1</version>
</dependency><!--junit测试-->
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version>
</dependency>
package com.bigdata;import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.cache.*;
import org.apache.curator.retry.RetryNTimes;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.junit.Before;
import org.junit.Test;import java.util.List;public class TestZk {CuratorFramework curator = null;@Beforepublic void init() {// 1. 创建一个连接(自动重连)RetryNTimes retry = new RetryNTimes(2, 5);// 重连10次,每次间隔1000秒// 2. 创建一个客户端对象。curator = CuratorFrameworkFactory.newClient("bigdata01:2181,bigdata02:2181,bigdata03:2181", retry);// 3. 启动客户端curator.start();}// 新增节点 永久的@Testpublic void testAddNode() throws Exception {// 这个里面可以创建四种类型的节点 永久节点 临时节点 永久序列节点 临时序列节点String s = curator.create().withMode(CreateMode.PERSISTENT).forPath("/a1", "测试".getBytes());System.out.println(s);}// 获取zk的数据@Testpublic void testGetData() throws Exception {byte[] bytes = curator.getData().forPath("/a1");// byte数组如何变为字符串,使用 String 的构造方法System.out.println(new String(bytes));}// 修改数据@Testpublic void testSetData() throws Exception {curator.setData().forPath("/a1", "我是打水哥".getBytes());}// 删除节点@Testpublic void testDeleteNode() throws Exception {curator.delete().forPath("/a1");}// 判断一个节点是否存在@Testpublic void testIsExists() throws Exception {// Stat 表示一个节点信息,如果获取不到节点信息,为nullStat stat = curator.checkExists().forPath("/a1");System.out.println(stat == null ? "该节点不存在" : "存在");}// 获取子节点信息,只能获取一层@Testpublic void testGetChild() throws Exception {List<String> list = curator.getChildren().forPath("/");for (String fileName : list) {System.out.println(fileName);}}// 给一个节点添加监听器 get /abc watch@Testpublic void testSetWatch() throws Exception {NodeCache nodeCache = new NodeCache(curator, "/a1");nodeCache.start();nodeCache.getListenable().addListener(new NodeCacheListener() {@Overridepublic void nodeChanged() throws Exception {byte[] data = nodeCache.getCurrentData().getData();System.out.println(new String(data));}});// 这个地方添加这句话的意思是不让程序跑结束,否则一切都白搭了Thread.sleep(Integer.MAX_VALUE);}// 给一个节点的子节点添加监听器 ls /abc watch@Testpublic void testSetWatchChild() throws Exception {PathChildrenCache cache = new PathChildrenCache(curator, "/a1", true);cache.start();// 添加监听cache.getListenable().addListener(new PathChildrenCacheListener() {@Overridepublic void childEvent(CuratorFramework client, PathChildrenCacheEvent event) throws Exception {// 需要知道是新增了还是修改了还是删除了System.out.println(event.getType());switch (event.getType()) {case CHILD_ADDED:System.out.println("添加了一个节点");System.out.println(event.getData().getPath());System.out.println(new String(event.getData().getData()));break;case CHILD_UPDATED:System.out.println("数据更新了");System.out.println(event.getData().getPath());System.out.println(new String(event.getData().getData()));break;case CHILD_REMOVED:System.out.println("节点被删除了");System.out.println(event.getData().getPath());break;default:System.out.println("节点发生了其他变化");break;}}});// 这个地方添加这句话的意思是不让程序跑结束,否则一切都白搭了Thread.sleep(Integer.MAX_VALUE);}}
什么是API?
一般是一个技术诞生后,为了方便开发人员通过代码获取其对应的服务,就会开发出来一些方法,开发人员只需要知道调用这个方法有什么效果即可,不需要懂内部的原理,这样的一系列方法就是该技术的API。
什么是接口?
接口一般存在于web端,规定只要传递响应的参数,我就完成对应的功能,并且返回结果数据。一般是java工程师和web工程师配合工作时使用,很多开源的技术, 为了方便别人使用,会对外开放很多接口,供开发人员进行调用。
枚举类:
package com.bigdata;// 枚举类
public enum Season {SPRING, // Season SPRING = new Season("春");SUMMER,AUTUMN,WINTER;// 以下这四个,分别是Season类的四个实例化对象Season(String a){}Season(){}
}
枚举类的使用:
@Testpublic void testEnum(){// WINTER 是枚举类的一个实例化对象Season season = Season.WINTER;switch (season){case WINTER:System.out.println("冬天冷...");break;case SPRING:System.out.println("春天来了,冬天还会源码?");break;}}
假如新增节点,报如下错误:当然这个错误也影响结果
[main-EventThread] ERROR org.apache.curator.framework.imps.EnsembleTracker - Invalid config event received: {server.1=bigdata01:2888:3888:participant, version=0, server.3=bigdata03:2888:3888:participant, server.2=bigdata02:2888:3888:participant}
[main-EventThread] ERROR org.apache.curator.framework.imps.EnsembleTracker - Invalid config event received: {server.1=bigdata01:2888:3888:participant, version=0, server.3=bigdata03:2888:3888:participant, server.2=bigdata02:2888:3888:participant}
请修改 zoo.cfg 配置文件:
老的版本的配置:
server.1=bigdata01:2888:3888
server.2=bigdata02:2888:3888
server.3=bigdata03:2888:3888
新的版本的配置:
server.1=bigdata01:2888:3888;2181
server.2=bigdata02:2888:3888;2181
server.3=bigdata03:2888:3888;2181配置完成后,分发一下,然后重启zk集群即可。
二、zk的选举机制
zk中有两种角色:Leader 和 Fllower
Leader是自己的集群各台电脑投票选举出来的。
事务:一通操作,要么同时成立,要么都不成立。
举例:Jack 和 Rose
Rose 给 Jack(小李子) 转钱
Rose -100
Jack +100如果中间数据有问题,直接回滚,回复到当初的样子
事务操作:新增,修改,删除等操作
非事务操作: 读数据
但凡跟数据相关的技术,都有事务。
mysql 有事务
jdbc 有事务
mybatis 有事务
zookeeper:
Zookeeper 集群工作的核心。1、事务请求(写操作)的唯一调度和处理者,保证集群事务处理的顺序性;
举例 : 比如添加了一个节点,删除了节点,修改了数据 都是事务操作。
2、集群内部各个服务器的调度者。
3、对于 create, setData, delete 等有写操作的请求,需要统一转发给leader 处理, leader 需要决定编号、执行操作,这个过程称为一个事务。类似于村长
- 处理客户端非事务(读操作)请求,转发事务请求(写操作)给 Leader;
- 参与集群 Leader 选举投票 2n-1台可以做集群投票。 1 3 5 7 9 ....
- 此外,针对访问量比较大的 zookeeper 集群, 还可新增观察者角色。
类似于村民
- 观察者角色,观察 Zookeeper 集群的最新状态变化并将这些状态同步过来,其对于非事务请求可以进行独立处理,对于事务请求,则会转发给 Leader服务器进行处理。
- 不会参与任何形式的投票只提供非事务服务,通常用于在不影响集群事务处理能力的前提下提升集群的非事务处理能力。类似于外来人员(喝汤了)
epoch > zxid > myid先比较 epoch 谁大谁是领导 --资历
逻辑时钟 参与过的选举的次数 类似于老党员。zxid 如果epoch 相等,就看谁的zxid大,谁就是领导
zxid 代表的是事务的次数 如果这个值很大,就表示这个机器上的数据比较的新
如果zxid 也相等,就看每台电脑上的myid了,如果myid谁大谁是领导。
我现在的集群中,有三台zk,为什么第二台是领导?zk01 1zk02 2zk03 3
启动第一台,第一台开始选举,自己投自己一票,因为超过半数才有效,所以zk01不是领导,此时的状态是选举中。
启动第二台,先投自己一票,然后第一台开始投票,比较两者之间谁的myid大,谁的大,就投给谁,zk02再得一票,第二台两票,超过了半数,领导出现了zk02.
启动第三台:发现有领导了,投了吧,当fllower吧。
三、Hadoop集群的高可用(HA)
关于搭建软件的总结:需要拥有三项技能:
1、linux 命令
2、软件的架构以及运行原理
3、会看日志
HA: High Availability,高可用集群,指的是集群7*24小时不间断服务。
Hadoop中存在单点故障问题:NameNode ResourceManager
问题:
NameNode 一个
DataNode 多个
集群中的NameNode挂掉了,整个集群都不可用了。
NameNode存在单点故障。
解决方案:使用zk集群搭建Hadoop的高可用。(NameNode的高可用)我们可以启动两个NameNode ,其中一台Namenode起作用,另一台备用。
关于集群中的高可用的解决方案:
1、主从模式(冷备)有一个正常工作,另一个闲置,当第一台服务停掉了,另一台直接顶上。类似于有两个讲师,一个讲师讲课,另一个讲师在家闲着。
2、双主互备两个都同时工作,一个挂掉了另一个还可以工作。两个收银员,一个生病了,另一个继续收银。
3、多节点互备多个收银员,同时收费(超市结账)
在搭建hadoop集群的高可用之前,先将集群进行快照。
1) 搭建namenode的高可用
先将三台服务器拍摄快照,便于后面的恢复!!!
第一步:bigdata01和bigdata02都能免密登录到其他三台
因为以前bigdata01 已经免密登录其他三台,不需要做。
进入到bigdata02中:
ssh-keygen -t rsa
# 发送公钥(所有NameNode节点都要发送)
ssh-copy-id bigdata01
ssh-copy-id bigdata02
ssh-copy-id bigdata03
第二步:三台电脑上都同时安装psmisc
# ZKFC远程杀死假死NN使用的killall namenode命令属于该软件中的。
# 建议所有节点都安装psmisc
以下命令是在bigdata01上运行的,因为只有01 配置了xcall命令
xcall.sh yum install -y psmisc
第三步:检查jdk以及zk 三台是否都安装完毕
第四步:检查是否安装了hadoop集群,如果以前安装过了,清空数据
先停止集群:stop-all.sh
清理集群中的data数据:
xcall.sh rm -rf /opt/installs/hadoop/tmp/ /opt/installs/hadoop/logs/
第五步:配置hadoop-env.sh
export JAVA_HOME=/opt/installs/jdk/
export HDFS_NAMENODE_USER=root
export HDFS_DATANODE_USER=root
export HDFS_SECONDARYNAMENODE_USER=root
export YARN_RESOURCEMANAGER_USER=root
export YARN_NODEMANAGER_USER=root
export HDFS_JOURNALNODE_USER=root
export HDFS_ZKFC_USER=root
修改完毕之后,记得同步给bigdata02和03
xsync.sh hadoop-env.sh
第六步:修改core-site.xml
<configuration><!--hdfs入口,设置虚拟地址,具体地址后面配置--><property><name>fs.defaultFS</name><value>hdfs://hdfs-cluster</value></property><!--hdfs集群的文件位置--><property><name>hadoop.tmp.dir</name><value>/opt/installs/hadoop/tmp</value></property><!--hdfs要访问zookeeper集群--><property><name>ha.zookeeper.quorum</name><value>bigdata01:2181,bigdata02:2181,bigdata03:2181</value></property>
</configuration>
第七步:修改hdfs-site.xml
<configuration><!-- 副本数 --><property><name>dfs.replication</name><value>3</value></property><!-- 定义hdfs入口的命名服务 --><property><name>dfs.nameservices</name><value>hdfs-cluster</value></property><!-- 定义hdfs入口的命名服务下虚拟ip--><property><name>dfs.ha.namenodes.hdfs-cluster</name><value>nn1,nn2</value></property><!-- 虚拟ip地址1 RPC入口 --><property><name>dfs.namenode.rpc-address.hdfs-cluster.nn1</name><value>bigdata01:9820</value></property><!-- 虚拟ip地址1 HTTP入口 --><property><name>dfs.namenode.http-address.hdfs-cluster.nn1</name><value>bigdata01:9870</value></property><!-- 虚拟ip地址2 PRC入口 --><property><name>dfs.namenode.rpc-address.hdfs-cluster.nn2</name><value>bigdata02:9820</value></property><!-- 虚拟ip地址1 HTTP入口 --><property><name>dfs.namenode.http-address.hdfs-cluster.nn2</name><value>bigdata02:9870</value></property><!-- 定义QJN在linux中保存文件磁盘目录 --><property><!-- Journal Edit Files 的存储目录:() --><name>dfs.journalnode.edits.dir</name><value>/opt/installs/journalnode/data/</value></property><property><name>dfs.namenode.shared.edits.dir</name><value>qjournal://bigdata01:8485;bigdata02:8485;bigdata03:8485/hdfs-cluster</value></property><!-- 是否开启故障切换 --><property><name>dfs.ha.automatic-failover.enabled</name><value>true</value></property><!-- 基于zookeeper的故障切换的代码类 --><property><name>dfs.client.failover.proxy.provider.hdfs-cluster</name><value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value></property><!-- 远程杀死namenode方式(防止namenode假死,导致双主出现) --><property><name>dfs.ha.fencing.methods</name><value>sshfence</value></property><!-- 指定私钥的文件目录,使用免密登录杀死NN进程 --><property><name>dfs.ha.fencing.ssh.private-key-files</name><value>/root/.ssh/id_rsa</value></property><!-- 可以在hdfs上点击结果查看--><property><name>dfs.webhdfs.enabled</name><value>true</value></property>
</configuration>
第八步:检查workers 文件是否为三台服务
第九步:同步 core-site.xml 和 hdfs-site.xml 到剩余两台上去
xsync.sh core-site.xml hdfs-site.xml
第十步:
1、启动zookeeper
zk.sh start
2. 初始化ZKFC在zk中的Znode信息【第一次启动需要做】在bigdata01上进行即可
hdfs zkfc -formatZK
3、在三台服务器上启动jn【journalnode 主要用于存储namenode的元数据】
hdfs --daemon start journalnode,否则报8345
这个为什么在这个时候启动,原因是第四步格式化的时候,需要用到journalnode,否则报8485连接超时的问题,格式化会失败的。
4、对集群进行namenode的格式化
hdfs namenode -format
5、启动hdfs
start-dfs.sh
这个服务默认会启动journalnode,但是由于你之前已经单独启动过了,所以启动它会报三个警告,可以忽略,无所谓。
6、启动第二个namenode
需要在bigdata02上运行:
第一次需要运行如下命令,以后不需要:
hdfs namenode -bootstrapStandby
接着,启动第二个namenode:
hadoop-daemon.sh start namenode本身集群是可以启动两个namenode的,但是由于第一次启动的话,bigdata02上没有格式化,所以无法启动,第二次就不需要了。
综上所述:
只要配置好了以后,以后启动高可用,命令只需要执行 start-dfs.sh 即可。当然zk还是单独管理。
第十一步:通过网页查看两个namenode的状态
查看第二个namenode:
第十二步:测试是否可以高可用
手动将第一台的namenode给关闭,第二台要自动从 standby变为active
假如第一次服务器再次启动namenode,状态应为为standby
Java 代码操作 HA 的 hdfs 代码演示:
@Test
public void testHA() throws Exception{
System.setProperty("HADOOP_USER_NAME","root");String clusterName = "hdfs-cluster";String HADOOP_URL = "hdfs://"+clusterName;
// 连接hdfs
Configuration conf = new Configuration();
conf.set("fs.defaultFS", HADOOP_URL);
conf.set("dfs.nameservices", clusterName);
conf.set("dfs.ha.namenodes."+clusterName, "nn1,nn2");
conf.set("dfs.namenode.rpc-address."+clusterName+".nn1", "bigdata01:9820");
conf.set("dfs.namenode.rpc-address."+clusterName+".nn2", "bigdata02:9820");
conf.set("dfs.client.failover.proxy.provider."+clusterName,"org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider");conf.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem");//fileSystem = FileSystem.newInstance(new URI("hdfs://bigdata01:9820"),conf);
fileSystem = FileSystem.newInstance(new URI("hdfs://hdfs-cluster"),conf);
fileSystem.createNewFile(new Path("/newFile.txt"));fileSystem.close();}
2)搭建resourcemanager的高可用
第一步:检查mapred-site.xml ,里面只有yarn配置和historyServer的配置,不需要修改
第二步:修改yarn-site.xml
<?xml version="1.0"?>
<!--
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License athttp://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. See accompanying LICENSE file.
-->
<configuration><!-- Site specific YARN configuration properties --><property><name>yarn.nodemanager.aux-services</name><value>mapreduce_shuffle</value> </property><property><name>yarn.application.classpath</name><value>/opt/installs/hadoop/etc/hadoop:/opt/installs/hadoop/share/hadoop/common/lib/*:/opt/installs/hadoop/share/hadoop/common/*:/opt/installs/hadoop/share/hadoop/hdfs:/opt/installs/hadoop/share/hadoop/hdfs/lib/*:/opt/installs/hadoop/share/hadoop/hdfs/*:/opt/installs/hadoop/share/hadoop/mapreduce/*:/opt/installs/hadoop/share/hadoop/yarn:/opt/installs/hadoop/share/hadoop/yarn/lib/*:/opt/installs/hadoop/share/hadoop/yarn/*</value> </property><property><name>yarn.log-aggregation-enable</name><value>true</value></property><!-- 历史日志在HDFS保存的时间,单位是秒 --><!-- 默认的是-1,表示永久保存 --><property><name>yarn.log-aggregation.retain-seconds</name><value>604800</value></property><property><name>yarn.log.server.url</name><value>http://bigdata01:19888/jobhistory/logs</value></property><!--配置resourcemanager的HA--><property><name>yarn.resourcemanager.ha.enabled</name><value>true</value></property><!-- RM 集群标识 --><property><name>yarn.resourcemanager.cluster-id</name><value>yarn-cluster</value></property> <!-- RM 的逻辑 ID 列表 --><property><name>yarn.resourcemanager.ha.rm-ids</name><value>rm1,rm2</value></property> <!-- RM1 的主机地址 --><property><name>yarn.resourcemanager.hostname.rm1</name><value>bigdata01</value></property><!-- RM1 的主机web管理界面地址 --> <property><name>yarn.resourcemanager.webapp.address.rm1</name><value>bigdata01:8088</value></property><!-- RM2 的主机地址 --><property><name>yarn.resourcemanager.hostname.rm2</name><value>bigdata02</value></property> <!-- RM2 的主机web管理界面地址 --> <property><name>yarn.resourcemanager.webapp.address.rm2</name><value>bigdata02:8088</value></property><!-- ZooKeeper 集群的地址 --> <property><name>yarn.resourcemanager.zk-address</name><value>bigdata01:2181,bigdata02:2181,bigdata03:2181</value></property> <!-- 启用自动恢复 --> <property><name>yarn.resourcemanager.recovery.enabled</name><value>true</value></property> <!-- 用于yarn故障转移持久化zk的类 --><property><name>yarn.resourcemanager.store.class</name><value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value>
</property> <!-- 关闭虚拟内存检查 -->
<property><name>yarn.nodemanager.vmem-check-enabled</name><value>false</value></property></configuration>
以前配置的yarn以及日志服务的配置不动,添加ha的相关配置。
第三步:将mapred-site.xml 和 yarn-site.xml进行同步
[root@bigdata01 ~]# cd /opt/installs/hadoop/etc/hadoop/
[root@bigdata01 hadoop]# xsync.sh yarn-site.xml只需要同步一个,因为另一个根本没有修改。
第四步:启动yarn
start-yarn.sh
如何查看谁是干活的,谁是备用的呢?
yarn rmadmin -getAllServiceState
假如你在启动过程中,发现resourcemanager有两个,但是都是standby,有可能是版本兼容问题:
hadoop3.1.6 需要兼容 zookeeper 3.4.10
假如你使用的hadoop版本是3.3.1 兼容 zookeeper 3.6.4 ,否则就会有问题。
namenode 高可用没问题,resourcemanager的高可用有问题。
切换zookeeper集群。
先将以前的zk集群停止。
下载一个对应版本的zk安装包,解压
解压到 /opt/installs
将以前的老的zookeeper 文件夹进行重命名
xcall.sh mv /opt/installs/zookeeper /opt/installs/zookeeper-tmp
将新的zk,进行重命名 为zookeeper
接着分发一下:
xsync.sh zookeeper
xcall.sh cp /opt/installs/zookeeper-tmp/conf/zoo.cfg /opt/installs/zookeeper/conf
接着在三台服务上创建文件夹:
xcall.sh mkdir /opt/installs/zookeeper/zkData
接着将不同电脑上的myid拷贝到相应的zkData里面
xcall.sh cp /opt/installs/zookeeper-tmp/zkData/myid /opt/installs/zookeeper/zkData
启动zk集群:
zk.sh start
启动完毕之后,记得格式化一下:
hdfs zkfc -formatZK接着启动start-all.sh 即可
测试一下RM的高可用:
[root@bigdata01 installs]# yarn rmadmin -getAllServiceState
bigdata01:8033 active
bigdata02:8033 standby
停止bigdata01中的RM,继续查看:
yarn --daemon stop resourcemanager
继续查看:
[root@bigdata01 installs]# yarn rmadmin -getAllServiceState
2023-08-23 14:40:15,547 INFO ipc.Client: Retrying connect to server: bigdata01/192.168.233.128:8033. Already tried 0 time(s); retry policy is RetryUpToMaximumCountWithFixedSleep(maxRetries=1, sleepTime=1000 MILLISECONDS)
bigdata01:8033 Failed to connect: Call From bigdata01/192.168.233.128 to bigdata01:8033 failed on connection exception: java.net.ConnectException: 拒绝连接; For more details see: http://wiki.apache.org/hadoop/ConnectionRefused
bigdata02:8033 active
再次启动bigdata01:
[root@bigdata01 installs]# yarn rmadmin -getAllServiceState
bigdata01:8033 standby
bigdata02:8033 active
使用高可用的 yarn 集群,运行一个任务:
hadoop jar WordCount01-1.0-SNAPSHOT.jar com.bigdata.WordCountDriver /wc.txt /output3
访问界面:http://bigdata02:8088/
访问 standby 节点,自动跳转到 active 节点的 IP 网站。
四、NameNode的联邦机制【了解】
解决的是:单台namenode节点内存有限的情况。
联邦机制中,可以同时启动多个NameNode,这些namenode 共同组合成了一个集群。
为了防止其中某一台坏掉,导致集群不可用,每一台namenode 都做了高可用(HA).
可靠的方案是: 联邦机制 + HA