当前位置:   article > 正文

利用zookeeper模拟实现HA高可用

利用zookeeper模拟实现HA高可用

                           利用zookeeper模拟实现HA高可用

 

1、需求

在分布式场景中,对于主从架构来说,最大的问题就是单点故障。当学过zookeeper之后,我们都知道,可以利用zookeeper集群来帮助实现Hadoop的HA,那到底Hadoop的HA是如何实现的呢?

 

2、实现思路

zookeeper给我们提供了两个非常重要的组件:

1、znode系统:提供了存储关键数据的能力

2、监听机制:提供了监听感兴趣数据变化的能力

利用zookeeper的这两点能力,我们实现HA

 

3、具体实现功能

  1. 1、当开始启动namenode的时候,所有刚启动的namenode都需要去争抢成为active的namenode,没有争抢成功的则成为standby的状态
  2. 2、当active的namenode死掉之后,需要剩下的所有的stanby都需要去争抢成为active的状态

 

4、具体代码实现

  1. package com.ghgj.zookeeper.zkapp1903;
  2. import org.apache.zookeeper.*;
  3. import org.apache.zookeeper.Watcher.Event.EventType;
  4. import org.apache.zookeeper.ZooDefs.Ids;
  5. import java.util.List;
  6. /**
  7. * 需求:
  8. * 模拟实现HA
  9. * <p>
  10. * 具体的功能:
  11. * 1、当开始启动namenode的时候,所有刚启动的namenode都需要去争抢成为active的namenode
  12. * 没有争抢成功的则成为standby的状态
  13. * 2、当active的namenode死掉之后,需要剩下的所有的stanby都需要去争抢成为active的状态
  14. * <p>
  15. * 在这个模拟实现中,假定所有的namenode之间的数据状态都是同步的。没有数据状态差别
  16. * <p>
  17. * 分析实现思路:
  18. * 见代码注释
  19. */
  20. public class NameNodeHA {
  21. // 连接信息
  22. private static final String CONNECT_STR = "hadoop02:2181,hadoop03:2181";
  23. // 会话超时时长 会话建立成功最长的等待时间
  24. private static final int TIME_OUT = 5000;
  25. // 存储active namenode的父级znode节点
  26. private static final String ACTIVE_PARENT = "/namenode_active";
  27. // 存储standby namenode的父级znode节点
  28. private static final String STANBY_PARENT = "/namenode_standbys";
  29. // 锁节点
  30. private static final String LOCK_ZNODE = "/namenode_lock";
  31. // 当前上线的节点名称
  32. private static final String NAMENODE_HOST = "hadoop02";
  33. static ZooKeeper zookeeper = null;
  34. public static void main(String[] args) throws Exception {
  35. /**
  36. * 获取连接
  37. *
  38. * 关于监听器的知识:
  39. * 有两种添加监听的方式:
  40. * 1、通过会话对象添加,这个会话对象中的所有的相应都能接收到,都在这个监听器对象中的process
  41. * 方法中执行业务逻辑的回调
  42. * 在获取会话的时候添加的监听是属于全局监听,当前这个会话中的任何事件响应,都会回调这个监听器对象中的
  43. * process方法
  44. *
  45. * 2、在对应的三种添加监听的方式中,注入自定义的监听对象,那么注入的监听器对象是谁,
  46. * 当事件响应的时候,就回调这个监听器对象中的process方法
  47. */
  48. zookeeper = new ZooKeeper(CONNECT_STR, TIME_OUT, new Watcher() {
  49. @Override
  50. public void process(WatchedEvent event) {
  51. // 哪个znode节点
  52. String path = event.getPath();
  53. // 事件的类型
  54. EventType type = event.getType();
  55. // 如果是 ACTIVE_PARENT 的 NodeChildrenChanged 事件
  56. // 当active namenode死掉或者增加都会触发process回调
  57. if (path.equals(ACTIVE_PARENT) && type == EventType.NodeChildrenChanged) {
  58. try {
  59. // 争抢成为active namenode
  60. List<String> onlyAtiveNM = zookeeper.getChildren(ACTIVE_PARENT, null);
  61. if (onlyAtiveNM.size() == 0) {
  62. // 原来的active namenode死掉了
  63. // 正式实现:争抢成为active namenode
  64. // 抢锁: 使用创建一个znode来模式实现抢锁,谁创建成功就是谁获取到了这把锁
  65. // 注册监听
  66. // 关注 LOCK_ZNODE 的 NodeCreated 事件
  67. zookeeper.exists(LOCK_ZNODE, true);
  68. // 创建锁节点
  69. // 触发了 LOCK_ZNODE 的 NodeCreated 事件
  70. if (zookeeper.exists(LOCK_ZNODE, false) == null) {
  71. zookeeper.create(LOCK_ZNODE, NAMENODE_HOST.getBytes(),
  72. Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
  73. }
  74. } else if (onlyAtiveNM.size() == 1) {
  75. // 相当于已经有一个anmenode把自己切换成为active了
  76. // 所以不需要做什么操作
  77. }
  78. } catch (Exception e) {
  79. e.printStackTrace();
  80. }
  81. } else if (path.equals(LOCK_ZNODE) && type == EventType.NodeCreated) {
  82. String namenode_lock_znode = null;
  83. try {
  84. // 真正的来判断,谁创建成功的锁节点,如果是自己创建成功的,则切换自己的状态成为 active
  85. byte[] data = zookeeper.getData(LOCK_ZNODE, false, null);
  86. // namenode_lock_znode
  87. // 这个对象 namenode_lock_znode 就是谁创建成功的那个namenode的节点名称
  88. namenode_lock_znode = new String(data, "UTF-8");
  89. } catch (Exception e) {
  90. e.printStackTrace();
  91. }
  92. // 需要判断,是否是自己创建成功的锁节点
  93. if (NAMENODE_HOST.equals(namenode_lock_znode)) {
  94. // 是自己创建成功的锁节点
  95. // 切换自己的状态
  96. try {
  97. // 首先删除自己在 STANDBY_PERENT节点下的该表自己的znode
  98. String deletePath = STANBY_PARENT + "/" + NAMENODE_HOST;
  99. if (zookeeper.exists(deletePath, false) != null) {
  100. zookeeper.delete(deletePath, -1);
  101. }
  102. // 再创建一个znode节点在ACTIVE_PARNET下面
  103. String createPath = ACTIVE_PARENT + "/" + NAMENODE_HOST;
  104. zookeeper.create(createPath, NAMENODE_HOST.getBytes(),
  105. Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
  106. System.out.println(NAMENODE_HOST + " 注册成为active角色");
  107. } catch (InterruptedException e) {
  108. e.printStackTrace();
  109. } catch (KeeperException e) {
  110. e.printStackTrace();
  111. }
  112. } else {
  113. // 判断得出结果 锁节点不是自己创建成功,不要成为active
  114. // 什么都不做
  115. }
  116. }
  117. }
  118. });
  119. /**
  120. * 执行各种操作
  121. */
  122. // 确保两个父节点存在
  123. if (zookeeper.exists(ACTIVE_PARENT, null) == null) {
  124. zookeeper.create(ACTIVE_PARENT, "storage active namenode data".getBytes(),
  125. Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
  126. }
  127. if (zookeeper.exists(STANBY_PARENT, null) == null) {
  128. zookeeper.create(STANBY_PARENT, "storage standby namenode data".getBytes(),
  129. Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
  130. }
  131. // 先来判断是否有active的namenode
  132. List<String> activeNM = zookeeper.getChildren(ACTIVE_PARENT, null);
  133. if (activeNM.size() == 1) {
  134. System.out.println(activeNM.get(0) + " 节点是active角色, 自己 " + NAMENODE_HOST + "成为standby角色");
  135. // 如果有active的namenode, 则自动成为 standby的namenode
  136. // 到 STANBY_PARENT 这个znode节点下,创建一个子节点代表当前这个standby namenode
  137. String standByPath = STANBY_PARENT + "/" + NAMENODE_HOST;
  138. zookeeper.create(standByPath, NAMENODE_HOST.getBytes(),
  139. Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
  140. // 注册监听:关注现在的active namenode 是否死掉
  141. // ACTIVE_PARENT 的 NodeChildrenChanged 事件
  142. // 关心是否 active 的namenode 死掉
  143. zookeeper.getChildren(ACTIVE_PARENT, true);
  144. } else {
  145. // 当发现没有active的namenode的时候:
  146. // 先争抢锁
  147. // 争抢锁争抢到了的话,就切换自己的状态
  148. // 注册监听
  149. // 关注 LOCK_ZNODE 的 NodeCreated 事件
  150. zookeeper.exists(LOCK_ZNODE, true);
  151. // 创建锁节点
  152. // 触发了 LOCK_ZNODE 的 NodeCreated 事件
  153. zookeeper.create(LOCK_ZNODE, NAMENODE_HOST.getBytes(),
  154. Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
  155. System.out.println("发现没有active,去争抢成为" + NAMENODE_HOST + " 节点成为standby节点");
  156. }
  157. /**
  158. * 关闭连接
  159. */
  160. while (true) {
  161. try {
  162. Thread.sleep(10000);
  163. } catch (InterruptedException e) {
  164. e.printStackTrace();
  165. }
  166. }
  167. }
  168. }

 

5、执行效果

当hadoop02节点启动:

当hadoop03启动的时候:

当hadoop04启动的时候:

当现在为active的hadoop02宕机的时候:

当hadoop02被宕机的时候,发现最终,hadoop03和hadoop04争抢成为active角色,最后发现hadoop04竞争成功成为active角色

 

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/965780
推荐阅读
相关标签
  

闽ICP备14008679号