zookeeper学习系列:三、构建一个分布式master、slave系统

之前只理解zk可以做命名,配置服务,现在学习下他怎么用作构建master-slave模式的分布式系统。

为什么叫Zoo?“因为要协调的分布式系统是一个动物园”。

ZooKeeper是一个中性化的Service,用于管理配置信息、命名、提供分布式同步,还能组合Service。所有这些种类的Service都会在分布式应用程序中使用到。每次编写这些Service都会涉及大量的修bug和竞争情况。正因为这种编写这些Service有一定难度,所以通常都会忽视它们,这就使得在应用程序有变化时变得难以管理应用程序。即使处理得当,实现这些服务的不同方法也会使得部署应用程序变得难以管理。

下边代码是参考文献的java版本,通过service来协调各个独立的PHP脚本,并让它们同意某个成为Leader(所以称作Leader选举)。当Leader退出(或崩溃)时,worker可检测到并再选出新的leader。通过这种方式即可理解一般的master-slave结构分布式系统是如何实现如何调度的,zk是个好东西。

首先需要了解创建节点的模式:

PERSISTENT:持久化目录节点,这个目录节点存储的数据不会丢失;

PERSISTENT_SEQUENTIAL:顺序自动编号的目录节点,这种目 录节点会根据当前已近存在的节点数自动加 1,然后返回给客户端已经成功创建的目录节点名;

EPHEMERAL:临时目录节点,一旦创建这个节点的客户端与服务器端口也就是 session 超时,这种节点会被自动删除;

EPHEMERAL_SEQUENTIAL:临时自动编号节点。

程序逻辑:

1)首先创建根节点/cluster,并创建自身子节点,以 /cluster/w- 为前缀,使用临时自动编号节点模式创建节点

2)获取/cluster的所有子节点并排序,当发现自身是第一个节点时,则自我选举为leader,否则认定为follower

3)注册监听事件,当/cluster里前一个节点有变动时,回到2)

这样,便实现了自动选举,当有节点在timeout时段后不可用时,自动产生新的leader,也可根据当前节点数进行预警。

package zookeeper;

import org.apache.zookeeper.*;

import java.io.IOException;
import java.util.Collections;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 *
 * @author guanpu
 *         Date: 14-10-22
 *         Time: 下午5:11
 *         To change this template use File | Settings | File Templates.
 */
public class Worker extends ZooKeeper implements Runnable, Watcher {
    public static final String NODE_NAME = "/cluster";
    public String znode;
    private boolean leader;

    public Worker(String connectString, int sessionTimeout, Watcher watcher) throws IOException {
        super(connectString, sessionTimeout, watcher);
    }

    public boolean register() throws InterruptedException, KeeperException {
        if (this.exists(NODE_NAME, null) == null) {
            this.create(NODE_NAME, "test".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE,
                    CreateMode.PERSISTENT);
        }
        znode = this.create(NODE_NAME + "/w-", null, ZooDefs.Ids.OPEN_ACL_UNSAFE,
                CreateMode.EPHEMERAL_SEQUENTIAL);
        znode = znode.replace(NODE_NAME + "/", "");
        String node = watchPrevious();
        if (node.equals(znode)) {
            System.out.println("nobody here ,i am leader");
            leader = true;
        } else {
            System.out.println("i am watching");
        }
        return true;
    }

    private String watchPrevious() throws InterruptedException, KeeperException {
        List<String> works = this.getChildren(NODE_NAME, this);
        Collections.sort(works);
        System.out.println(works);
        int i = 0;
        for (String work : works) {
            if (znode.equals(work)) {
                if (i > 0) {
                   //this.getData(NODE_NAME + "/" + works.get(i - 1), this, null);
                    return works.get(i - 1);
                }
                return works.get(0);
            }
        }
        return "";

    }

    @Override
    public void run() {
        try {
            this.register();
        } catch (InterruptedException e) {
        } catch (KeeperException e) {
        }
        while (true) {
            try {
                if (leader) {
                    System.out.println("leading");
                } else {
                    System.out.println("following");
                }
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            }
        }
    }

    public static void main(String[] args) {
        try {
            String hostPort = "10.16.73.22,10.16.73.12,10.16.73.13";
            new Thread(new Worker(hostPort, 3000, null)).start();
        } catch (IOException e) {
        }
    }

    @Override
    public void process(WatchedEvent event) {
        String t = String.format("hello event! type=%s, stat=%s, path=%s", event.getType(), event.getState(), event.getPath());
        System.out.println(t);
        System.out.println("hello ,my cluster id is :"+znode);
        String node = "";
        try {
            node = this.watchPrevious();
        } catch (InterruptedException e) {
        } catch (KeeperException e) {
        }

        if (node.equals(znode)) {
            System.out.println("process: nobody here ,i am leader");
            leader = true;
        } else {
            System.out.println("process: i am watching");
        }
    }
}

启动至少三个终端,模拟Leader崩溃的情形。使用Ctrl+c或其他方法退出第一个脚本。刚开始不会有任何变化,worker可以继续工作。后来,ZooKeeper会发现超时,并选举出新的leader。

php移植到java有两个问题,第一个是watcher注册,第一次父类初始化未完成时不能调用自身作为watcher,会报一次watcher调用空指针。

第二个问题:

this.getData(NODE_NAME + "/" + works.get(i - 1), this, null);

这个不生效,看方法注释是当改动和移除节点时,触发watcher的process,但实验中并未触发,在java里系统的自动删除并不归类在这两个操作之内?

php版本的是正常的,作为遗留问题。为了程序正常运行,更改为 List<String> works = this.getChildren(NODE_NAME, this);   当子节点有变动时执行process方法。

参考文献:

http://anykoro.sinaapp.com/2013/04/05/使用apache-zookeeper分布式部署php应用程序/

时间: 2024-11-07 20:58:14

zookeeper学习系列:三、构建一个分布式master、slave系统的相关文章

[转帖]Zookeeper学习系列【一】 教会你Zookeeper的一些基础概念

Zookeeper学习系列[一] 教会你Zookeeper的一些基础概念 https://segmentfault.com/a/1190000018927058 前言 最近加入了部门的技术兴趣小组,被分配了Zookeeper的研究任务.在研究过程当中,发现Zookeeper由于其开源的特性和其卓越的性能特点,在业界使用广泛,有很多的应用场景,而这些不同的应用场景实际上底层的原理都是差不多的,只要你真正理解了Zookeeper的一些基础概念和机制,就能够触类旁通. 于是乎,在第一次和项目小组内成员

第三周——构建一个简单的Linux系统MenuOS

[洪韶武 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ] 第三周  构建一个简单的Linux系统MenuOS

Android学习系列(39)--Android主题和样式之系统篇(上)

Android学习系列(39)--Android主题和样式之系统篇(上) [基于最新的Android4.4的源码分析] 每家公司或者每个移动团队无不想开发出一套自己的UI框架,融入自己的设计和特性,这必然会去修改android的ui.所以,学习和理解android的UI设计是最基础和非常有必要的.android ui设计最重要的就是主题和样式. 1.位置在Android的frameworks/base/core/res/res/values目录下有一下几个文件: 1 2 3 4 themes.x

构建一个简单的Linux系统 MenuOs —— start_kernel到init进程(20135304刘世鹏)

构建一个简单的Linux系统 MenuOs —— start_kernel到init进程 作者:刘世鹏20135304 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 Linux内核代码简介 内核源码三个个重要目录 arch占有代码量最大,支持不同cpu的源代码,arch/x86目录下的代码是我们关注的重点 init,内核启动相关的代码基本都在init目录下,init/main.c中start_kernel是整

Zookeeper学习系列【一】 教会你Zookeeper的一些基础概念

前言 最近加入了部门的技术兴趣小组,被分配了Zookeeper的研究任务.在研究过程当中,发现Zookeeper由于其开源的特性和其卓越的性能特点,在业界使用广泛,有很多的应用场景,而这些不同的应用场景实际上底层的原理都是差不多的,只要你真正理解了Zookeeper的一些基础概念和机制,就能够触类旁通. 于是乎,在第一次和项目小组内成员分享过Zookeeper作为服务注册中心的原理和客户端demo演示之后,我萌生出了整理一个专题的想法,以此为起点,慢慢捡起自己的博客分享之路. 本篇的内容主要介绍

Identity Server4学习系列三

1.简介 在Identity Server4学习系列一和Identity Server4学习系列二之令牌(Token)的概念的基础上,了解了Identity Server4的由来,以及令牌的相关知识,本文开始实战,实现Identity Server4基本的功能. 2.前提 本文基于.Net Core2.1和Indetity Server4 2.3.0,令牌处理包采用IdentityServer4.AccessTokenValidation 2.7.0 3.实战一Identity Server4服

《Linux内核分析》第三周 构建一个简单的Linux系统MenuOS

[刘蔚然 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] WEEK THREE(2.29——3.6)构造一个简单的Linux系统MenuOS SECTION 1 Linux内核源代码简介 1.操作系统的两把宝剑(回顾上一讲) 中断上下文的切换——保存现场&恢复现场 进程上下文的切换 2.Linux内核源代码简介 打开内核源代码页面 arch/目录:支持不同CPU的源代码:其中的

C# Redis学习系列三:Redis配置主从

Redis配置主从 主IP :端口      192.168.0.103 6666 从IP:端口       192.168.0.108 3333 配置从库 (1)安装服务: redis-server --service-install --service-name redisService6666 --port 6666 (2)启动进程: redis-server --service-start --service-name redisService6666 (3)连接redis:redis-

使用C++ boost从零构建一个异步文件IO系统

前言 因为本科毕业设计中要做一个分布式文件系统,其中一个模块需要实现文件IO.为了验证我对异步IO的理解,决定造一个异步文件IO的轮子.操作系统已经给出各种异步操作的API,如重叠IO, IOCP,kqueue,select,poll,epoll等机制,而且C++也有很多跨平台的异步IO库,如libevent,boost::asio等.我参考已有的实现来完善这个小系统的功能. 渣技术,渣代码,出现问题请各位指出. 概述 同步与异步: 同步:假如我想对一个文件(socket也同理)进行处理,那么一