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

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

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

 

Hadoop各个模块剖析:https://www.cnblogs.com/funyoung/p/9889719.html

Hadoop集群管理:https://www.cnblogs.com/funyoung/p/9920828.html

 

 

 

 

当有两个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。

 

 

 

https://www.cnblogs.com/funyoung/p/8778106.html 

 

  1. <configuration>
  2. <!-- 指定NameService的名称 -->
  3. <property>
  4. <name>dfs.nameservices</name>
  5. <value>mycluster</value>
  6. </property>
  7. <!-- 指定NameService下两个NameNode的名称 -->
  8. <property>
  9. <name>dfs.ha.namenodes.mycluster</name>
  10. <value>nn1,nn2</value>
  11. </property>
  12. <!-- 分别指定NameNode的RPC通讯地址 -->
  13. <property>
  14. <name>dfs.namenode.rpc-address.mycluster.nn1</name>
  15. <value>192.168.1.80:8020</value>
  16. </property>
  17. <property>
  18. <name>dfs.namenode.rpc-address.mycluster.nn2</name>
  19. <value>192.168.1.81:8020</value>
  20. </property>
  21. <!-- 分别指定NameNode的Web监控页面地址 -->
  22. <property>
  23. <name>dfs.namenode.http-address.mycluster.nn1</name>
  24. <value>192.168.1.80:50070</value>
  25. </property>
  26. <property>
  27. <name>dfs.namenode.http-address.mycluster.nn2</name>
  28. <value>192.168.1.81:50070</value>
  29. </property>
  30. <!-- 指定NameNode编辑日志存储在JournalNode集群中的目录-->
  31. <property>
  32. <name>dfs.namenode.shared.edits.dir</name>
  33. <value>qjournal://192.168.1.80:8485;192.168.1.81:8485;192.168.1.82:8485/mycluster</value>
  34. </property>
  35. <!-- 指定JournalNode集群存放日志的目录-->
  36. <property>
  37. <name>dfs.journalnode.edits.dir</name>
  38. <value>/usr/hadoop/hadoop-2.9.0/journalnode</value>
  39. </property>
  40. <!-- 配置NameNode失败自动切换的方式-->
  41. <property>
  42. <name>dfs.client.failover.proxy.provider.mycluster</name>
  43. <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
  44. </property>
  45. <!-- 配置隔离机制-->
  46. <property>
  47. <name>dfs.ha.fencing.methods</name>
  48. <value>sshfence</value>
  49. </property>
  50. <!-- 由于使用SSH,那么需要指定密钥的位置-->
  51. <property>
  52. <name>dfs.ha.fencing.ssh.private-key-files</name>
  53. <value>/root/.ssh/id_rsa</value>
  54. </property>
  55. <!-- 开启失败故障自动转移-->
  56. <property>
  57. <name>dfs.ha.automatic-failover.enabled</name>
  58. <value>true</value>
  59. </property>
  60. <!-- 配置Zookeeper地址-->
  61. <property>
  62. <name>ha.zookeeper.quorum</name>
  63. <value>192.168.1.80:2181,192.168.1.81:2181,192.168.1.82:2181</value>
  64. </property>
  65. <!-- 文件在HDFS中的备份数(小于等于NameNode) -->
  66. <property>
  67. <name>dfs.replication</name>
  68. <value>3</value>
  69. </property>
  70. <!-- 关闭HDFS的访问权限 -->
  71. <property>
  72. <name>dfs.permissions.enabled</name>
  73. <value>false</value>
  74. </property>
  75. <!-- 指定一个配置文件,使NameNode过滤配置文件中指定的host -->
  76. <property>
  77. <name>dfs.hosts.exclude</name>
  78. <value>/usr/hadoop/hadoop-2.9.0/etc/hadoop/hdfs.exclude</value>
  79. </property>
  80. </configuration>

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

 

  1. <configuration>
  2. <!-- Hadoop工作目录,用于存放Hadoop运行时NameNode、DataNode产生的数据 -->
  3. <property>
  4. <name>hadoop.tmp.dir</name>
  5. <value>/usr/hadoop/hadoop-2.9.0/data</value>
  6. </property>
  7. <!-- 默认NameNode,使用NameService的名称 -->
  8. <property>
  9. <name>fs.defaultFS</name>
  10. <value>hdfs://mycluster</value>
  11. </property>
  12. <!-- 开启Hadoop的回收站机制,当删除HDFS中的文件时,文件将会被移动到回收站(/usr/<username>/.Trash),在指定的时间过后再对其进行删除,此机制可以防止文件被误删除 -->
  13. <property>
  14. <name>fs.trash.interval</name>
  15. <!-- 单位是分钟 -->
  16. <value>1440</value>
  17. </property>
  18. </configuration>

 

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

 

1.分别启动JournalNode

 

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

 

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

 

4.启动第二个NameNode

 

5.启动Zookeeper集群

 

6.格式化Zookeeper

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

 

7.重启HDFS集群

 

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

 

 

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

 

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

 

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

 

 

 

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

 

  1. /**
  2. * @Auther: ZHUANGHAOTANG
  3. * @Date: 2018/11/6 11:49
  4. * @Description:
  5. */
  6. public class HDFSUtils {
  7. /**
  8. * HDFS NamenNode URL
  9. */
  10. private static final String NAMENODE_URL = "hdfs://mycluster:8020";
  11. /**
  12. * 配置项
  13. */
  14. private static Configuration conf = null;
  15. static {
  16. conf = new Configuration();
  17. //指定默认连接的NameNode,使用NameService的名称
  18. conf.set("fs.defaultFS", "hdfs://mycluster");
  19. //指定NameService的名称
  20. conf.set("dfs.nameservices", "mycluster");
  21. //指定NameService下的NameNode列表
  22. conf.set("dfs.ha.namenodes.mycluster", "nn1,nn2");
  23. //分别指定NameNode的RPC通讯地址
  24. conf.set("dfs.namenode.rpc-address.mycluster.nn1", "hadoop1:8020");
  25. conf.set("dfs.namenode.rpc-address.mycluster.nn2", "hadoop2:8020");
  26. //配置NameNode失败自动切换的方式
  27. conf.set("dfs.client.failover.proxy.provider.mycluster", "org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider");
  28. }
  29. /**
  30. * 创建目录
  31. */
  32. public static void mkdir(String dir) throws Exception {
  33. if (StringUtils.isBlank(dir)) {
  34. throw new Exception("Parameter Is NULL");
  35. }
  36. dir = NAMENODE_URL + dir;
  37. FileSystem fs = FileSystem.get(URI.create(NAMENODE_URL), conf);
  38. if (!fs.exists(new Path(dir))) {
  39. fs.mkdirs(new Path(dir));
  40. }
  41. fs.close();
  42. }
  43. /**
  44. * 删除目录或文件
  45. */
  46. public static void delete(String dir) throws Exception {
  47. if (StringUtils.isBlank(dir)) {
  48. throw new Exception("Parameter Is NULL");
  49. }
  50. dir = NAMENODE_URL + dir;
  51. FileSystem fs = FileSystem.get(URI.create(NAMENODE_URL), conf);
  52. fs.delete(new Path(dir), true);
  53. fs.close();
  54. }
  55. /**
  56. * 遍历指定路径下的目录和文件
  57. */
  58. public static List<String> listAll(String dir) throws Exception {
  59. List<String> names = new ArrayList<>();
  60. if (StringUtils.isBlank(dir)) {
  61. throw new Exception("Parameter Is NULL");
  62. }
  63. dir = NAMENODE_URL + dir;
  64. FileSystem fs = FileSystem.get(URI.create(dir), conf);
  65. FileStatus[] files = fs.listStatus(new Path(dir));
  66. for (int i = 0, len = files.length; i < len; i++) {
  67. if (files[i].isFile()) { //文件
  68. names.add(files[i].getPath().toString());
  69. } else if (files[i].isDirectory()) { //目录
  70. names.add(files[i].getPath().toString());
  71. } else if (files[i].isSymlink()) { //软或硬链接
  72. names.add(files[i].getPath().toString());
  73. }
  74. }
  75. fs.close();
  76. return names;
  77. }
  78. /**
  79. * 上传当前服务器的文件到HDFS中
  80. */
  81. public static void uploadLocalFileToHDFS(String localFile, String hdfsFile) throws Exception {
  82. if (StringUtils.isBlank(localFile) || StringUtils.isBlank(hdfsFile)) {
  83. throw new Exception("Parameter Is NULL");
  84. }
  85. hdfsFile = NAMENODE_URL + hdfsFile;
  86. FileSystem fs = FileSystem.get(URI.create(NAMENODE_URL), conf);
  87. Path src = new Path(localFile);
  88. Path dst = new Path(hdfsFile);
  89. fs.copyFromLocalFile(src, dst);
  90. fs.close();
  91. }
  92. /**
  93. * 通过流上传文件
  94. */
  95. public static void uploadFile(String hdfsPath, InputStream inputStream) throws Exception {
  96. if (StringUtils.isBlank(hdfsPath)) {
  97. throw new Exception("Parameter Is NULL");
  98. }
  99. hdfsPath = NAMENODE_URL + hdfsPath;
  100. FileSystem fs = FileSystem.get(URI.create(NAMENODE_URL), conf);
  101. FSDataOutputStream os = fs.create(new Path(hdfsPath));
  102. BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
  103. byte[] data = new byte[1024];
  104. while (bufferedInputStream.read(data) != -1) {
  105. os.write(data);
  106. }
  107. os.close();
  108. fs.close();
  109. }
  110. /**
  111. * 从HDFS中下载文件
  112. */
  113. public static byte[] readFile(String hdfsFile) throws Exception {
  114. if (StringUtils.isBlank(hdfsFile)) {
  115. throw new Exception("Parameter Is NULL");
  116. }
  117. hdfsFile = NAMENODE_URL + hdfsFile;
  118. FileSystem fs = FileSystem.get(URI.create(NAMENODE_URL), conf);
  119. Path path = new Path(hdfsFile);
  120. if (fs.exists(path)) {
  121. FSDataInputStream is = fs.open(path);
  122. FileStatus stat = fs.getFileStatus(path);
  123. byte[] data = new byte[(int) stat.getLen()];
  124. is.readFully(0, data);
  125. is.close();
  126. fs.close();
  127. return data;
  128. } else {
  129. throw new Exception("File Not Found In HDFS");
  130. }
  131. }
  132. }

 

 

 

 

 

 

 

 

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

 

 

 

  1. <configuration>
  2. <!-- 配置Reduce取数据的方式是shuffle(随机) -->
  3. <property>
  4. <name>yarn.nodemanager.aux-services</name>
  5. <value>mapreduce_shuffle</value>
  6. </property>
  7. <!-- 开启日志 -->
  8. <property>
  9. <name>yarn.log-aggregation-enable</name>
  10. <value>true</value>
  11. </property>
  12. <!-- 设置日志的删除时间 -1:禁用,单位为秒 -->
  13. <property>
  14. <name>yarn.log-aggregation。retain-seconds</name>
  15. <value>864000</value>
  16. </property>
  17. <!-- 设置yarn的内存大小,单位是MB -->
  18. <property>
  19. <name>yarn.nodemanager.resource.memory-mb</name>
  20. <value>8192</value>
  21. </property>
  22. <!-- 设置yarn的CPU核数 -->
  23. <property>
  24. <name>yarn.nodemanager.resource.cpu-vcores</name>
  25. <value>8</value>
  26. </property>
  27. <!-- YARN HA配置 -->
  28. <!-- 开启yarn ha -->
  29. <property>
  30. <name>yarn.resourcemanager.ha.enabled</name>
  31. <value>true</value>
  32. </property>
  33. <!-- 指定yarn ha的名称 -->
  34. <property>
  35. <name>yarn.resourcemanager.cluster-id</name>
  36. <value>cluster1</value>
  37. </property>
  38. <!-- 分别指定两个ResourceManager的名称 -->
  39. <property>
  40. <name>yarn.resourcemanager.ha.rm-ids</name>
  41. <value>rm1,rm2</value>
  42. </property>
  43. <!-- 分别指定两个ResourceManager的地址 -->
  44. <property>
  45. <name>yarn.resourcemanager.hostname.rm1</name>
  46. <value>192.168.1.80</value>
  47. </property>
  48. <property>
  49. <name>yarn.resourcemanager.hostname.rm2</name>
  50. <value>192.168.1.81</value>
  51. </property>
  52. <!-- 分别指定两个ResourceManager的Web访问地址 -->
  53. <property>
  54. <name>yarn.resourcemanager.webapp.address.rm1</name>
  55. <value>192.168.1.80:8088</value>
  56. </property>
  57. <property>
  58. <name>yarn.resourcemanager.webapp.address.rm2</name>
  59. <value>192.168.1.81:8088</value>
  60. </property>
  61. <!-- 配置使用的Zookeeper集群 -->
  62. <property>
  63. <name>yarn.resourcemanager.zk-address</name>
  64. <value>192.168.1.80:2181,192.168.1.81:2181,192.168.1.82:2181</value>
  65. </property>
  66. <!-- ResourceManager Restart配置 -->
  67. <!-- 启用ResourceManager的restart功能,当ResourceManager重启时将会保存运行时信息到指定的位置,重启成功后再进行读取 -->
  68. <property>
  69. <name>yarn.resourcemanager.recovery.enabled</name>
  70. <value>true</value>
  71. </property>
  72. <!-- ResourceManager Restart使用的存储方式(实现类) -->
  73. <property>
  74. <name>yarn.resourcemanager.store.class</name>
  75. <value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value>
  76. </property>
  77. <!-- ResourceManager重启时数据保存在Zookeeper中的目录 -->
  78. <property>
  79. <name>yarn.resourcemanager.zk-state-store.parent-path</name>
  80. <value>/rmstore</value>
  81. </property>
  82. <!-- NodeManager Restart配置 -->
  83. <!-- 启用NodeManager的restart功能,当NodeManager重启时将会保存运行时信息到指定的位置,重启成功后再进行读取 -->
  84. <property>
  85. <name>yarn.nodemanager.recovery.enabled</name>
  86. <value>true</value>
  87. </property>
  88. <!-- NodeManager重启时数据保存在本地的目录 -->
  89. <property>
  90. <name>yarn.nodemanager.recovery.dir</name>
  91. <value>/usr/hadoop/hadoop-2.9.0/data/rsnodemanager</value>
  92. </property>
  93. <!-- 配置NodeManager的RPC通讯端口 -->
  94. <property>
  95. <name>yarn.nodemanager.address</name>
  96. <value>0.0.0.0:45454</value>
  97. </property>
  98. </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

 

 

 

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

 

2.手动启动另一个ResourceManager

 

 

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

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

 

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

 

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

 

版权声明:本文为funyoung原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/funyoung/p/9936407.html