• 利用Zookeeper实现分布式锁及服务注册中心


    对于Zookeeper的定义以及原理,网上已经有很多的优秀文章对其进行了详细的介绍,所以本文不再进行这方面的阐述。

    本文主要介绍一些基本的准备工作以及zookeeper.net的使用。

    本文源代码github地址:https://github.com/Mike-Zrw/ZookeeperHelper

    zookeeper下载地址:https://archive.apache.org/dist/zookeeper/

    ZooInspector下载地址:https://issues.apache.org/jira/secure/attachment/12436620/ZooInspector.zip

    Zookeeper下载及安装

    目前版本最新的为3.5.3 。 本文使用的版本为3.4.10

    随意下载一个版本的压缩包,解压到某个文件夹中. zookeeper服务的启动脚本在bin目录下的文件:zkServer.cmd

    在服务启动之前,需要对配置文件进行基本的设置:

    conf目录下的zoo_sample.cfg改名为 zoo.cf

    修改里面的日志文件路径,我修改完之后的文件内容如下

    The number of milliseconds of each tick

    tickTime=2000

    The number of ticks that the initial

    synchronization phase can take

    initLimit=10

    The number of ticks that can pass between

    sending a request and getting an acknowledgement

    syncLimit=5

    the directory where the snapshot is stored.

    do not use /tmp for storage, /tmp here is just

    example sakes.

    dataDir=data
    dataLogDir=datalog

    the port at which the clients will connect

    clientPort=2181

    the maximum number of client connections.

    increase this if you need to handle more clients

    maxClientCnxns=60

    Be sure to read the maintenance section of the

    administrator guide before turning on autopurge.

    http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance

    The number of snapshots to retain in dataDir

    autopurge.snapRetainCount=3

    Purge task interval in hours

    Set to "0" to disable auto purge feature

    autopurge.purgeInterval=1

    • tickTime:Zookeeper之间维持心跳的时间间隔
    • initLimit:集群中的follower服务器(F)与leader服务器(L)之间 初始连接 时能容忍的最多心跳数(tickTime的数量),这里为2000*10 ,超过10次心跳仍然没同步完成,会重新选举leader
    • syncLimit:集群中的follower服务器(F)与leader服务器(L)之间 请求和应答 之间能容忍的最多心跳数(tickTime的数量)。超时follwer将被丢弃
    • dataDir:Zookeeper保存数据的目录 ,目录不可含中文字符
    • dataLogDir:Zookeeper保存日志文件的目录
    • clientPort:Zookeeper服务器的端口

    配置完成之后就可以双击zkServer.cmd启动zookeeper服务了

    ZooInspector的安装

    ZooInspector是zookeeper的监视工具,可以查看zookeeper的数据信息

    下载完成后直接解压,运行zookeeper-dev-ZooInspector.jar。如果默认端口没有修改,直接点击连接就可以了

    ZooKeeper.Net

    通过Nuget来安装ZooKeeper.Net的开发包到项目中

    下面的代码会建立一个zookeeper的连接,并创建一个名为parent的临时目录

       public static void TestConnect()
        {
            Console.WriteLine("建立连接");
            //服务地址为:localhost:2181  超时连接30秒
            using (ZooKeeper Instance = new ZooKeeperNet.ZooKeeper("localhost:2181", new TimeSpan(0, 0, 30), new Watcher("new")))
            {
                Console.WriteLine("检测是否有parent目录");
                var sdata = Instance.Exists("/parent", new Watcher("exists"));
                Console.WriteLine(sdata==null?"否":"是");
                if (sdata==null)
                {
                    Console.WriteLine("开始创建parent目录");
                    //data:目录关联的data为:this is the parentnode data
                    //acl:目录的访问权限控制
                    //CreateMode:Ephemeral:目录为临时目录,断开连接目录会自动清除  永久目录:Persistent  自增目录:***Sequential
                    Instance.Create("/parent", "this is the parentnode data".GetBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.Ephemeral);
                    Console.WriteLine("创建parent目录完成");
                    Console.WriteLine("检测是否有parent目录");
                    sdata = Instance.Exists("/parent", new Watcher("exists2"));
                    Console.WriteLine(sdata == null ? "否" : "是");
                    if (sdata != null)
                    {
                        Console.WriteLine("删除parent目录");
                        Instance.Delete("/parent", 0);
                    }
                }
            }
        }
    

    运行结果如下

    需要注意的是执行这段代码可能会报错提示connection loss,出现错误的原因是建立连接的这一步是异步的操作,应当等待zookeeper连接成功之后再执行下面的代码。所以这段代码只是进行一个简单的演示,nuget上附有正确的使用方式

    关于zookeeper的watch定义如下:

    监视是一种简单的机制,使客户端收到关于ZooKeeper集合中的更改的通知。客户端可以在读取特定znode时设置Watches。Watches会向注册的客户端发送任何znode(客户端注册表)更改的通知。

    Znode更改是与znode相关的数据的修改或znode的子项中的更改。只触发一次watches。如果客户端想要再次通知,则必须通过另一个读取操作来完成。当连接会话过期时,客户端将与服务器断开连接,相关的watches也将被删除。

    Zookeeper的每个节点称之为znode,znode的类型分为四种:持久节点,临时节点,持久顺序节点,临时顺序节点

    这里简单说下顺序节点:比如我需要建立一个名称为 /app的节点,那么zookeeper会建立一个名为/app0000000001的节点,如果再有人要创建一个名为/app的顺序节点,新建的节点名称会变为/app0000000002

    也就是说顺序节点生成之后的名字是指定的名字加十位序列号,序列号不会重复,即使是两个操作同时创建。 我们可以利用这一个特性来实现分布式锁:

    分布式锁的伪代码如下:

    public void lock(){
    var parentpath=/lock_
    var path = CreateEphemeralSequentialNode(parentpath)
    while(true){
    var children = 获取父节点的所有子节点
    if(path是children中的最小的){
    成功获取锁
    return;
    }else{
    监控等待前一个节点删除
    wait();
    }
    }
    }

    具体的代码可以在github上查看

  • 相关阅读:
    【jQuery EasyUI系列】使用属性介绍
    【jQuery EasyUI系列】创建CRUD数据网格
    [jQuery EasyUI系列] 创建增删改查应用
    [JQuery EasyUI系列]简介
    Javascript 使用小案例
    Spring学习进阶(一)初识Spring
    No plugin found for prefix 'jetty' in the current project and in the plugin groups 【转】
    工作框架各种使用整理 --创建的时候使用前面创建成功的输出
    工作框架各种使用整理---自己处理分页
    策略模式
  • 原文地址:https://www.cnblogs.com/bluesummer/p/8334802.html
Copyright © 2020-2023  润新知