Zookeeper 05 示例代码-主备节点切换

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/yanliang1/article/details/46548819

收起

 

主备节点的切换,是分布式应用的基本要求。现在用 Zookeeper 实现主备节点自动切换功能。

基本思路:

1 多个服务启动后,都尝试在 Zookeeper中创建一个 EPHEMERAL 类型的节点,Zookeeper本身会保证,只有一个服务会创建成功,其他服务抛出异常。

2 成功创建节点的服务,作为主节点,继续运行

3 其他服务设置一个Watcher监控节点状态,

4 如果主节点消失,其他服务会接到通知,再次尝试创建EPHEMERAL 类型的节点。

 

 
  1. public class Master implements Watcher {

  2. private static final Logger LOG = LoggerFactory.getLogger(Master.class);

  3. enum MasterStates {RUNNING, ELECTED, NOTELECTED};

  4. private volatile MasterStates state = MasterStates.RUNNING;

  5.  
  6. MasterStates getState() {

  7. return state;

  8. }

  9.  
  10. private static final int SESSION_TIMEOUT = 5000;

  11. private static final String CONNECTION_STRING = "10.58.69.142:2181";

  12. private static final String ZNODE_NAME = "/master";

  13. private Random random = new Random(System.currentTimeMillis());

  14. private ZooKeeper zk;

  15. private String serverId = Integer.toHexString(random.nextInt());

  16.  
  17. private volatile boolean connected = false;

  18. private volatile boolean expired = false;

  19.  
  20. public void startZk() throws IOException {

  21. zk = new ZooKeeper(CONNECTION_STRING, SESSION_TIMEOUT, this);

  22. }

  23.  
  24. public void stopZk() {

  25. if (zk != null) {

  26. try {

  27. zk.close();

  28. } catch (InterruptedException e) {

  29. LOG.warn("Interrupted while closing ZooKeeper session.", e);

  30. }

  31. }

  32. }

  33.  
  34. /**

  35. * 抢注节点

  36. */

  37. public void enroll() {

  38. zk.create(ZNODE_NAME,

  39. serverId.getBytes(),

  40. ZooDefs.Ids.OPEN_ACL_UNSAFE,

  41. CreateMode.EPHEMERAL,

  42. masterCreateCallBack, null);

  43. }

  44.  
  45. AsyncCallback.StringCallback masterCreateCallBack = new AsyncCallback.StringCallback() {

  46. @Override

  47. public void processResult(int rc, String path, Object ctx, String name) {

  48. switch (KeeperException.Code.get(rc)) {

  49. case CONNECTIONLOSS:

  50. //网络问题,需要检查节点是否创建成功

  51. checkMaster();

  52. return;

  53. case OK:

  54. state = MasterStates.ELECTED;

  55. break;

  56. case NODEEXISTS:

  57. state = MasterStates.NOTELECTED;

  58. // 添加Watcher

  59. addMasterWatcher();

  60. break;

  61. default:

  62. state = MasterStates.NOTELECTED;

  63. LOG.error("Something went wrong when running for master.",

  64. KeeperException.create(KeeperException.Code.get(rc), path));

  65. }

  66. LOG.info("I'm " + (state == MasterStates.ELECTED ? "" : "not ") + "the leader " + serverId);

  67. }

  68. };

  69.  
  70. public void checkMaster() {

  71. zk.getData(ZNODE_NAME, false, masterCheckCallBack, null);

  72. }

  73.  
  74. AsyncCallback.DataCallback masterCheckCallBack = new AsyncCallback.DataCallback() {

  75. @Override

  76. public void processResult(int rc, String path, Object ctx, byte[] data, Stat stat) {

  77. switch (KeeperException.Code.get(rc)) {

  78. case CONNECTIONLOSS:

  79. checkMaster();

  80. return;

  81. case NONODE:

  82. // 节点未创建,再次注册

  83. enroll();

  84. return;

  85. case OK:

  86. if (serverId.equals(new String(data))) {

  87. state = MasterStates.ELECTED;

  88. } else {

  89. state = MasterStates.NOTELECTED;

  90. addMasterWatcher();

  91. }

  92. break;

  93. default:

  94. LOG.error("Error when reading data.",KeeperException.create(KeeperException.Code.get(rc), path));

  95. }

  96. }

  97. };

  98.  
  99. void addMasterWatcher() {

  100. zk.exists(ZNODE_NAME,

  101. masterExistsWatcher,

  102. masterExistsCallback,

  103. null);

  104. }

  105. Watcher masterExistsWatcher = new Watcher() {

  106. @Override

  107. public void process(WatchedEvent event) {

  108. if(event.getType() == Event.EventType.NodeDeleted){

  109. assert ZNODE_NAME.equals(event.getPath());

  110. enroll();

  111. }

  112. }

  113. };

  114. AsyncCallback.StatCallback masterExistsCallback = new AsyncCallback.StatCallback() {

  115. public void processResult(int rc, String path, Object ctx, Stat stat) {

  116. switch (KeeperException.Code.get(rc)) {

  117. case CONNECTIONLOSS:

  118. addMasterWatcher();

  119. break;

  120. case OK:

  121. break;

  122. case NONODE:

  123. state = MasterStates.RUNNING;

  124. enroll();

  125. LOG.info("It sounds like the previous master is gone, " +

  126. "so let's run for master again.");

  127. break;

  128. default:

  129. checkMaster();

  130. break;

  131. }

  132. }

  133. };

  134.  
  135. public static void main(String[] args) throws InterruptedException, IOException {

  136. Master m = new Master( );

  137. m.startZk();

  138.  
  139. while (!m.isConnected()) {

  140. Thread.sleep(100);

  141. }

  142. m.enroll();

  143. while (!m.isExpired()) {

  144. Thread.sleep(1000);

  145. }

  146.  
  147. m.stopZk();

  148. }

  149. boolean isConnected() {

  150. return connected;

  151. }

  152.  
  153. boolean isExpired() {

  154. return expired;

  155. }

  156.  
  157. @Override

  158. public void process(WatchedEvent e) {

  159. LOG.info("Processing event: " + e.toString());

  160. if (e.getType() == Event.EventType.None) {

  161. switch (e.getState()) {

  162. case SyncConnected:

  163. connected = true;

  164. break;

  165. case Disconnected:

  166. connected = false;

  167. break;

  168. case Expired:

  169. expired = true;

  170. connected = false;

  171. LOG.error("Session expiration");

  172. default:

  173. break;

  174. }

  175. }

  176. }

  177.  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值