Hadoop高可用集群

若HDFS集群中只配置了一个NameNode,那么当该NameNode所在的节点宕机,则整个HDFS就不能进行文件的上传和下载。

若YARN集群中只配置了一个ResourceManager,那么当该ResourceManager所在的节点宕机,则整个YARN就不能进行任务的计算。

*Hadoop依赖Zookeeper进行各个模块的HA配置,其中状态为Active的节点对外提供服务,而状态为StandBy的节点则只负责数据的同步,在必要时提供快速故障转移。

2.HDFS HA集群

2.1 模型

当有两个NameNode时,提供哪个NameNode地址给客户端?

1.Hadoop提供了NameService进程,其是NameNode的代理,维护NameNode列表并存储NameNode的状态,客户端直接访问的是NameService,NameService会将请求转发给当前状态为Active的NameNode。

2.当启动HDFS时,DataNode将同时向两个NameNode进行注册。

怎样发现NameNode无法提供服务以及如何进行NameNode间状态的切换?

1.Hadoop提供了FailoverControllerActive和FailoverControllerStandBy两个进程用于NameNode的生命监控。

2.FailoverControllerActive和FailoverControllerStandBy会分别监控对应状态的NameNode,若NameNode无异常则定期向Zookeeper集群发送心跳,若在一定时间内Zookeeper集群没收到FailoverControllerActive发送的心跳,则认为此时状态为Active的NameNode已经无法对外提供服务,因此将状态为StandBy的NameNode切换为Active状态。

NameNode之间的数据如何进行同步和共享?

1.Hadoop提供了JournalNode用于存放NameNode中的编辑日志。

2.当激活的NameNode执行任何名称空间上的修改时,它将修改的记录保存到JournalNode集群中,备用的NameNode能够实时监控JournalNode集群中日志的变化,当监控到日志发生改变时会将其同步到本地。

*当状态为Active的NameNode无法对外提供服务时,Zookeeper将会自动的将处于StandBy状态的NameNode切换成Active。

2.2 HDFS HA高可用集群搭建

1.配置HDFS(hdfs-site.xml)

<configuration>

<!-- 指定NameService的名称 -->

<property>

<name>dfs.nameservices</name>

<value>mycluster</value>

</property>

<!-- 指定NameService下两个NameNode的名称 -->

<property>

<name>dfs.ha.namenodes.mycluster</name>

<value>nn1,nn2</value>

</property>

<!-- 分别指定NameNode的RPC通讯地址 -->

<property>

<name>dfs.namenode.rpc-address.mycluster.nn1</name>

<value>192.168.1.80:8020</value>

</property>

<property>

<name>dfs.namenode.rpc-address.mycluster.nn2</name>

<value>192.168.1.81:8020</value>

</property>

<!-- 分别指定NameNode的Web监控页面地址 -->

<property>

<name>dfs.namenode.http-address.mycluster.nn1</name>

<value>192.168.1.80:50070</value>

</property>

<property>

<name>dfs.namenode.http-address.mycluster.nn2</name>

<value>192.168.1.81:50070</value>

</property>

<!-- 指定NameNode编辑日志存储在JournalNode集群中的目录-->

<property>

<name>dfs.namenode.shared.edits.dir</name>

<value>qjournal://192.168.1.80:8485;192.168.1.81:8485;192.168.1.82:8485/mycluster</value>

</property>

<!-- 指定JournalNode集群存放日志的目录-->

<property>

<name>dfs.journalnode.edits.dir</name>

<value>/usr/hadoop/hadoop-2.9.0/journalnode</value>

</property>

<!-- 配置NameNode失败自动切换的方式-->

<property>

<name>dfs.client.failover.proxy.provider.mycluster</name>

<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>

</property>

<!-- 配置隔离机制-->

<property>

<name>dfs.ha.fencing.methods</name>

<value>sshfence</value>

</property>

<!-- 由于使用SSH,那么需要指定密钥的位置-->

<property>

<name>dfs.ha.fencing.ssh.private-key-files</name>

<value>/root/.ssh/id_rsa</value>

</property>

<!-- 开启失败故障自动转移-->

<property>

<name>dfs.ha.automatic-failover.enabled</name>

<value>true</value>

</property>

<!-- 配置Zookeeper地址-->

<property>

<name>ha.zookeeper.quorum</name>

<value>192.168.1.80:2181,192.168.1.81:2181,192.168.1.82:2181</value>

</property>

<!-- 文件在HDFS中的备份数(小于等于NameNode) -->

<property>

<name>dfs.replication</name>

<value>3</value>

</property>

<!-- 关闭HDFS的访问权限 -->

<property>

<name>dfs.permissions.enabled</name>

<value>false</value>

</property>

<!-- 指定一个配置文件,使NameNode过滤配置文件中指定的host -->

<property>

<name>dfs.hosts.exclude</name>

<value>/usr/hadoop/hadoop-2.9.0/etc/hadoop/hdfs.exclude</value>

</property>

</configuration>

*指定NameNode的RPC通讯地址是为了接收FailoverControllerActive和FailoverControllerStandBy以及DataNode发送的心跳。

2.配置Hadoop公共属性(core-site.xml)

<configuration>

<!-- Hadoop工作目录,用于存放Hadoop运行时NameNode、DataNode产生的数据 -->

<property>

<name>hadoop.tmp.dir</name>

<value>/usr/hadoop/hadoop-2.9.0/data</value>

</property>

<!-- 默认NameNode,使用NameService的名称 -->

<property>

<name>fs.defaultFS</name>

<value>hdfs://mycluster</value>

</property>

<!-- 开启Hadoop的回收站机制,当删除HDFS中的文件时,文件将会被移动到回收站(/usr/<username>/.Trash),在指定的时间过后再对其进行删除,此机制可以防止文件被误删除 -->

<property>

<name>fs.trash.interval</name>

<!-- 单位是分钟 -->

<value>1440</value>

</property>

</configuration>

*在HDFS HA集群中,StandBy的NameNode会对namespace进行checkpoint操作,因此就不需要在HA集群中运行SecondaryNameNode、CheckpintNode、BackupNode。

2.启动HDFS HA高可用集群

1.分别启动JournalNode

2.格式化第一个NameNode并启动

3.第二个NameNode同步第一个NameNode的信息

4.启动第二个NameNode

5.启动Zookeeper集群

6.格式化Zookeeper

*当格式化ZK后,ZK中将会多了hadoop-ha节点。

7.重启HDFS集群

当HDFS HA集群启动完毕后,可以分别访问NameNode管理页面查看当前NameNode的状态

*可以查看到主机名为hadoop1的NamNode其状态为StandBy,而主机名为hadoop2的NameNode其状态为Active。

8.模拟NameNode宕机,手动杀死进程。

此时访问NameNode管理页面,可见主机名为hadoop1的NameNode其状态从原本的StandBy切换成Active。

2.3 JAVA操作HDFS HA集群

*由于在HDFS HA集群中存在两个NameNode,且服务端暴露的是NameService,因此在通过JAVA连接HDFS HA集群时需要使用Configuration实例进行相关的配置。

/**

* @Auther: ZHUANGHAOTANG

* @Date: 2018/11/6 11:49

* @Description:

*/

public class HDFSUtils {

/**

* HDFS NamenNode URL

*/

private static final String NAMENODE_URL = "hdfs://mycluster:8020";

/**

* 配置项

*/

private static Configuration conf = null;

static {

conf = new Configuration();

//指定默认连接的NameNode,使用NameService的名称

conf.set("fs.defaultFS", "hdfs://mycluster");

//指定NameService的名称

conf.set("dfs.nameservices", "mycluster");

//指定NameService下的NameNode列表

conf.set("dfs.ha.namenodes.mycluster", "nn1,nn2");

//分别指定NameNode的RPC通讯地址

conf.set("dfs.namenode.rpc-address.mycluster.nn1", "hadoop1:8020");

conf.set("dfs.namenode.rpc-address.mycluster.nn2", "hadoop2:8020");

//配置NameNode失败自动切换的方式

conf.set("dfs.client.failover.proxy.provider.mycluster", "org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider");

}

/**

* 创建目录

*/

public static void mkdir(String dir) throws Exception {

if (StringUtils.isBlank(dir)) {

throw new Exception("Parameter Is NULL");

}

dir = NAMENODE_URL + dir;

FileSystem fs = FileSystem.get(URI.create(NAMENODE_URL), conf);

if (!fs.exists(new Path(dir))) {

fs.mkdirs(new Path(dir));

}

fs.close();

}

/**

* 删除目录或文件

*/

public static void delete(String dir) throws Exception {

if (StringUtils.isBlank(dir)) {

throw new Exception("Parameter Is NULL");

}

dir = NAMENODE_URL + dir;

FileSystem fs = FileSystem.get(URI.create(NAMENODE_URL), conf);

fs.delete(new Path(dir), true);

fs.close();

}

/**

* 遍历指定路径下的目录和文件

*/

public static List<String> listAll(String dir) throws Exception {

List<String> names = new ArrayList<>();

if (StringUtils.isBlank(dir)) {

throw new Exception("Parameter Is NULL");

}

dir = NAMENODE_URL + dir;

FileSystem fs = FileSystem.get(URI.create(dir), conf);

FileStatus[] files = fs.listStatus(new Path(dir));

for (int i = 0, len = files.length; i < len; i++) {

if (files[i].isFile()) { //文件

names.add(files[i].getPath().toString());

} else if (files[i].isDirectory()) { //目录

names.add(files[i].getPath().toString());

} else if (files[i].isSymlink()) { //软或硬链接

names.add(files[i].getPath().toString());

}

}

fs.close();

return names;

}

/**

* 上传当前服务器的文件到HDFS中

*/

public static void uploadLocalFileToHDFS(String localFile, String hdfsFile) throws Exception {

if (StringUtils.isBlank(localFile) || StringUtils.isBlank(hdfsFile)) {

throw new Exception("Parameter Is NULL");

}

hdfsFile = NAMENODE_URL + hdfsFile;

FileSystem fs = FileSystem.get(URI.create(NAMENODE_URL), conf);

Path src = new Path(localFile);

Path dst = new Path(hdfsFile);

fs.copyFromLocalFile(src, dst);

fs.close();

}

/**

* 通过流上传文件

*/

public static void uploadFile(String hdfsPath, InputStream inputStream) throws Exception {

if (StringUtils.isBlank(hdfsPath)) {

throw new Exception("Parameter Is NULL");

}

hdfsPath = NAMENODE_URL + hdfsPath;

FileSystem fs = FileSystem.get(URI.create(NAMENODE_URL), conf);

FSDataOutputStream os = fs.create(new Path(hdfsPath));

BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);

byte[] data = new byte[1024];

while (bufferedInputStream.read(data) != -1) {

os.write(data);

}

os.close();

fs.close();

}

/**

* 从HDFS中下载文件

*/

public static byte[] readFile(String hdfsFile) throws Exception {

if (StringUtils.isBlank(hdfsFile)) {

throw new Exception("Parameter Is NULL");

}

hdfsFile = NAMENODE_URL + hdfsFile;

FileSystem fs = FileSystem.get(URI.create(NAMENODE_URL), conf);

Path path = new Path(hdfsFile);

if (fs.exists(path)) {

FSDataInputStream is = fs.open(path);

FileStatus stat = fs.getFileStatus(path);

byte[] data = new byte[(int) stat.getLen()];

is.readFully(0, data);

is.close();

fs.close();

return data;

} else {

throw new Exception("File Not Found In HDFS");

}

}

}

2.YARN HA集群

2.1 模型

*启动两个ResourceManager后分别向Zookeeper注册,通过Zookeeper管理他们的状态,一旦状态为Active的ResourceManager无法正常提供服务,Zookeeper将会立即将状态为StandBy的ResourceManager切换为Active。

2.2 YARN HA高可用集群搭建

1.配置YARN(yarn-site.xml)

<configuration>

<!-- 配置Reduce取数据的方式是shuffle(随机) -->

<property>

<name>yarn.nodemanager.aux-services</name>

<value>mapreduce_shuffle</value>

</property>

<!-- 开启日志 -->

<property>

<name>yarn.log-aggregation-enable</name>

<value>true</value>

</property>

<!-- 设置日志的删除时间 -1:禁用,单位为秒 -->

<property>

<name>yarn.log-aggregation。retain-seconds</name>

<value>864000</value>

</property>

<!-- 设置yarn的内存大小,单位是MB -->

<property>

<name>yarn.nodemanager.resource.memory-mb</name>

<value>8192</value>

</property>

<!-- 设置yarn的CPU核数 -->

<property>

<name>yarn.nodemanager.resource.cpu-vcores</name>

<value>8</value>

</property>

<!-- YARN HA配置 -->

<!-- 开启yarn ha -->

<property>

<name>yarn.resourcemanager.ha.enabled</name>

<value>true</value>

</property>

<!-- 指定yarn ha的名称 -->

<property>

<name>yarn.resourcemanager.cluster-id</name>

<value>cluster1</value>

</property>

<!-- 分别指定两个ResourceManager的名称 -->

<property>

<name>yarn.resourcemanager.ha.rm-ids</name>

<value>rm1,rm2</value>

</property>

<!-- 分别指定两个ResourceManager的地址 -->

<property>

<name>yarn.resourcemanager.hostname.rm1</name>

<value>192.168.1.80</value>

</property>

<property>

<name>yarn.resourcemanager.hostname.rm2</name>

<value>192.168.1.81</value>

</property>

<!-- 分别指定两个ResourceManager的Web访问地址 -->

<property>

<name>yarn.resourcemanager.webapp.address.rm1</name>

<value>192.168.1.80:8088</value>

</property>

<property>

<name>yarn.resourcemanager.webapp.address.rm2</name>

<value>192.168.1.81:8088</value>

</property>

<!-- 配置使用的Zookeeper集群 -->

<property>

<name>yarn.resourcemanager.zk-address</name>

<value>192.168.1.80:2181,192.168.1.81:2181,192.168.1.82:2181</value>

</property>

<!-- ResourceManager Restart配置 -->

<!-- 启用ResourceManager的restart功能,当ResourceManager重启时将会保存运行时信息到指定的位置,重启成功后再进行读取 -->

<property>

<name>yarn.resourcemanager.recovery.enabled</name>

<value>true</value>

</property>

<!-- ResourceManager Restart使用的存储方式(实现类) -->

<property>

<name>yarn.resourcemanager.store.class</name>

<value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value>

</property>

<!-- ResourceManager重启时数据保存在Zookeeper中的目录 -->

<property>

<name>yarn.resourcemanager.zk-state-store.parent-path</name>

<value>/rmstore</value>

</property>

<!-- NodeManager Restart配置 -->

<!-- 启用NodeManager的restart功能,当NodeManager重启时将会保存运行时信息到指定的位置,重启成功后再进行读取 -->

<property>

<name>yarn.nodemanager.recovery.enabled</name>

<value>true</value>

</property>

<!-- NodeManager重启时数据保存在本地的目录 -->

<property>

<name>yarn.nodemanager.recovery.dir</name>

<value>/usr/hadoop/hadoop-2.9.0/data/rsnodemanager</value>

</property>

<!-- 配置NodeManager的RPC通讯端口 -->

<property>

<name>yarn.nodemanager.address</name>

<value>0.0.0.0:45454</value>

</property>

</configuration>

ResourceManager Restart使用的存储方式(实现类)

1.ResourceManager运行时的数据保存在ZK中:org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore

2.ResourceManager运行时的数据保存在HDFS中:org.apache.hadoop.yarn.server.resourcemanager.recovery.FileSystemRMStateStore

3.ResourceManager运行时的数据保存在本地:org.apache.hadoop.yarn.server.resourcemanager.recovery.LeveldbRMStateStore

*使用不同的存储方式将需要额外的配置项,可参考官网,http://hadoop.apache.org/docs/current/hadoop-yarn/hadoop-yarn-site/ResourceManagerRestart.html

2.启动YARN HA高可用集群

1.在ResourceManager所在节点中启动YARN集群

2.手动启动另一个ResourceManager

*当启动YARN HA集群后,可以分别访问ResourceManager管理页面,http://192.168.1.80:8088、http://192.168.1.81:8088。

访问状态为StandBy的ResourceManager时,会将请求重定向到状态为Active的ResourceManager的管理页面。

3.模拟ResourceManager宕机,手动杀死进程

*Zookeeper在一定时间内无法接收到状态为Active的ResourceManager发送的心跳时,将会立即将状态为StandBy的ResourceManager切换为Active。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • 一、系统参数配置优化 1、系统内核参数优化配置 修改文件/etc/sysctl.conf,添加如下配置,然后执行s...
    张伟科阅读 3,720评论 0 14
  • 软件环境: 主机配置: 一共m1, m2, m3这五部机, 每部主机的用户名都为centos 前期准备 1.配置主...
    咸鱼翻身记阅读 1,090评论 0 5
  • 1、在hadoop用户的家目录下创建一个data文件 指定hadoop/etc/hadoop下配置文件core-s...
    夙夜M阅读 367评论 0 1
  • 之前的有点忘记了,这里在云笔记拿出来再玩玩.看不懂的可以留言 大家可以尝试下Ambari来配置Hadoop的相关环...
    HT_Jonson阅读 2,941评论 0 50
  • 秋已睡,夜初眠。声戾吵香酣。 饿来悠走满归欢,奇痒惹心烦。 身憔悴,心思睡,恨尔不该多嘴。 叫嚣如此好良辰,拖起困乏身。
    琴诗音阅读 192评论 0 3