C#使用zookeeper

https://blog.csdn.net/XuWei_XuWei/article/details/80611659

1.简述

zookeeper适用于分布式锁,配置管理,服务器管理,服务发现场景
c#使用zookeeper基于开源组件ZooKeeperNetEx,详情GitHub搜一下

2.安装开发包

使用nuget安装ZooKeeperNetEx和ZooKeeperNetEx.Recipes,版本是3.4.9.3

3.配置

<runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-2.6.8.0" newVersion="2.6.8.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Threading.Tasks" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-2.6.8.0" newVersion="2.6.8.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <appSettings>
    <add key="forcerun" value="0"/>
    <add key="pathname" value="ZooKeeperTest"/>
    <add key="servicename" value="ZooKeeperTest1"/>
    <add key="isonline" value="0"/>
  </appSettings>

4.封装(依赖log4net)

--------AuthEnum.cs------
    public enum AuthEnum
    {
        world = 0,
        auth = 1,
        digest = 2,
        ip = 3,
        super = 4
    }

-------DefaultWatcher.cs-----
/// <summary>
    /// 默认监听
    /// </summary>
    public class DefaultWatcher : Watcher
    {
        private readonly ILog _log;
        internal static readonly Task CompletedTask = TaskEx.FromResult(1);

public DefaultWatcher(ILog log)
        {
            _log = log;
        }

/// <summary>
        /// 接收通知
        /// </summary>
        /// <param name="event"></param>
        /// <returns></returns>
        public override Task process(WatchedEvent @event)
        {
            _log.ErrorFormat("接收到ZooKeeper服务端的通知,State是:{0},EventType是:{1},Path是:{2}", @event.getState(), @event.get_Type(), @event.getPath() ?? string.Empty);
            return CompletedTask;
        }
    }

---------NodeWatcher.cs--------
/// <summary>
    /// 节点监听
    /// </summary>
    public class NodeWatcher : Watcher
    {
        private readonly ILog _log;
        private string _state;
        private Event.EventType _type;
        private string _path;
        internal static readonly Task CompletedTask = TaskEx.FromResult(1);

public NodeWatcher(ILog log)
        {
            _log = log;
        }

public override Task process(WatchedEvent @event)
        {
            _state = @event.getState().ToString();
            _type = @event.get_Type();
            _path = @event.getPath();
            switch (_type)
            {
                case Event.EventType.NodeCreated:
                    HandleCreate();
                    break;
                case Event.EventType.NodeDeleted:
                    HandleDelete();
                    break;
                case Event.EventType.NodeDataChanged:
                    HandleDataChange();
                    break;
                case Event.EventType.NodeChildrenChanged:
                    HandleChildrenChange();
                    break;
                default:
                    HandleNone();
                    break;
            }
            return CompletedTask;
        }

/// <summary>
        /// 创建节点事件
        /// </summary>
        private void HandleCreate()
        {
            _log.ErrorFormat("NodeCreated");
        }

private void HandleDelete()
        {
            _log.ErrorFormat("NodeDeleted");
        }

private void HandleDataChange()
        {
            _log.ErrorFormat("NodeDataChanged");
        }

private void HandleChildrenChange()
        {
            _log.ErrorFormat("NodeChildrenChanged");
        }

private void HandleNone()
        {
            _log.ErrorFormat(_state);
        }
    }

--------ZooKeeperHelper.cs--------           
public class ZooKeeperHelper
    {
        private readonly ILog _log;
        private bool _isonline = Convert.ToBoolean(ConfigurationManager.AppSettings["isonline"].ConventToInt32());
        private List<string> _address;
        private int _sessiontTimeout = 10*1000;//10秒
        private ZooKeeper _zooKeeper;
        private int _connectTimeout = 3*30*1000;//每个zookeeper实例尝试连接最长30秒
        private string _success = "success";
        private string _fail = "fail";

public ZooKeeperHelper(ILog log,int sessionTimeOut = 10*1000)
        {
            _log = log;
            _sessiontTimeout = sessionTimeOut;
            if (_isonline)
            {
                //正式环境
                _address = new List<string> { "192.168.204.92:2181", "192.168.204.92:2182", "192.168.204.92:2183" };
            }
            else
            {
                //本地调试环境
                _address = new List<string> { "10.168.100.102:2181", "10.168.100.102:2182", "10.168.100.102:2183" };
            }
        }

/// <summary>
        /// 返回null表示连接不成功
        /// </summary>
        /// <param name="authEnum"></param>
        /// <param name="authInfo"></param>
        /// <returns></returns>
        public ZooKeeper Connect(AuthEnum authEnum ,string authInfo) {
            try
            {
                foreach (string address in _address)
                {
                    _zooKeeper = new ZooKeeper(address, _sessiontTimeout, new DefaultWatcher(_log));
                    if (authEnum != AuthEnum.world)
                    {
                        _zooKeeper.addAuthInfo(authEnum.ToString(), System.Text.Encoding.UTF8.GetBytes(authInfo));
                    }
                    Stopwatch stopwatch = new Stopwatch();
                    stopwatch.Start();
                    while (stopwatch.ElapsedMilliseconds < _connectTimeout/_address.Count)
                    {
                        ZooKeeper.States states = _zooKeeper.getState();
                        if (states == ZooKeeper.States.CONNECTED || states == ZooKeeper.States.CONNECTEDREADONLY)
                        {
                            break;
                        }
                    }
                    stopwatch.Stop();
                    if (_zooKeeper.getState().ToString().ToUpper().Contains("CONNECTED"))
                    {
                        break;
                    }
                }
               
                return _zooKeeper;
            }
            catch (Exception ex)
            {
                _log.ErrorFormat("连接zookeeper发生异常:{0}", ex.Message + ex.StackTrace);
            }
            return null;
        }

/// <summary>
        /// 创建节点,不能在临时节点下创建子节点
        /// </summary>
        /// <param name="path">不要使用path等关键字作为路径</param>
        /// <param name="data"></param>
        /// <param name="persistent"></param>
        /// <returns></returns>
        public string CreateNode(string path,string data,bool persistent = false) {
            try {
                Task<string> task = _zooKeeper.createAsync(path, System.Text.Encoding.UTF8.GetBytes(data), ZooDefs.Ids.OPEN_ACL_UNSAFE, persistent ? CreateMode.PERSISTENT : CreateMode.EPHEMERAL);
                task.Wait();
                if (!string.IsNullOrEmpty(task.Result) && task.Status.ToString().ToLower() == "RanToCompletion".ToLower())
                {
                    return task.Result;
                }
            }
            catch (Exception ex) {
                _log.ErrorFormat("创建节点发生异常:{0}({1}),{2}",path ,data,ex.Message + ex.StackTrace);
            }
            return _fail;
        }

/// <summary>
        /// 删除节点,删除节点的子节点个数必须为0,否则请先删除子节点
        /// </summary>
        /// <param name="path">不要使用path等关键字作为路径</param>
        /// <returns></returns>
        public string DeleteNode(string path) {
            try
            {
                Task task = _zooKeeper.deleteAsync(path);
                task.Wait();
                if (task.Status.ToString().ToLower() == "RanToCompletion".ToLower())
                {
                    return _success;
                }
            }
            catch (Exception ex)
            {
                _log.ErrorFormat("删除节点发生异常:{0},{1}", path,ex.Message + ex.StackTrace);
            }
            return _fail;
        }

/// <summary>
        /// 给节点设置数据
        /// </summary>
        /// <param name="path">不要使用path等关键字作为路径</param>
        /// <param name="data"></param>
        /// <returns></returns>
        public string SetData(string path,string data) {
            try
            {
                Task<org.apache.zookeeper.data.Stat> stat = _zooKeeper.setDataAsync(path, System.Text.Encoding.UTF8.GetBytes(data));
                stat.Wait();
                if (stat.Result != null && stat.Status.ToString().ToLower() == "RanToCompletion".ToLower())
                {
                    return _success;
                }
            }
            catch (Exception ex)
            {
                _log.ErrorFormat("设置节点数据发生异常:{0}({1}),{2}",path,data, ex.Message + ex.StackTrace);
            }
            return _fail;
        }

/// <summary>
        /// 判断节点是否存在
        /// </summary>
        /// <param name="path">不要使用path等关键字作为路径</param>
        /// <param name="watcher"></param>
        /// <returns></returns>
        public string ExistsNode(string path, Watcher watcher = null) {
            try
            {
                Task<org.apache.zookeeper.data.Stat> stat = _zooKeeper.existsAsync(path, watcher);
                stat.Wait();
                if (stat.Result != null && stat.Status.ToString().ToLower() == "RanToCompletion".ToLower())
                {
                    return _success;
                }
            }
            catch (Exception ex)
            {
                _log.ErrorFormat("判定节点存在与否发生异常:{0},{1}", path, ex.Message + ex.StackTrace);
            }
            return _fail;
        }

/// <summary>
        /// 得到节点相关信息
        /// </summary>
        /// <param name="path">不要使用path等关键字作为路径</param>
        /// <param name="watcher"></param>
        /// <returns></returns>
        public Stat GetNode(string path, Watcher watcher = null)
        {
            try
            {
                Task<org.apache.zookeeper.data.Stat> stat = _zooKeeper.existsAsync(path, watcher);
                stat.Wait();
                if (stat.Result != null && stat.Status.ToString().ToLower() == "RanToCompletion".ToLower())
                {
                    return stat.Result;
                }
            }
            catch (Exception ex)
            {
                _log.ErrorFormat("得到节点信息发生异常:{0},{1}", path, ex.Message + ex.StackTrace);
            }
            return null;
        }

/// <summary>
        /// 得到节点数据
        /// </summary>
        /// <param name="path">不要使用path等关键字作为路径</param>
        /// <param name="watcher"></param>
        /// <returns></returns>
        public string GetData(string path, Watcher watcher = null) {
            try
            {
                Task<DataResult> dataResult = _zooKeeper.getDataAsync(path, watcher);
                dataResult.Wait();
                if (dataResult.Result != null && dataResult.Status.ToString().ToLower() == "RanToCompletion".ToLower())
                {
                    return Encoding.UTF8.GetString(dataResult.Result.Data);
                }
            }
            catch (Exception ex)
            {
                _log.ErrorFormat("得到节点数据发生异常:{0},{1}", path, ex.Message + ex.StackTrace);
            }
            return _fail;
        }

/// <summary>
        /// 得到后代节点路径
        /// </summary>
        /// <param name="path">不要使用path等关键字作为路径</param>
        /// <param name="watcher"></param>
        /// <returns></returns>
        public List<string> GetChildren(string path,Watcher watcher = null) {
            try
            {
                Task<ChildrenResult> childrenResult = _zooKeeper.getChildrenAsync(path, watcher);
                childrenResult.Wait();
                if (childrenResult.Result != null && childrenResult.Status.ToString().ToLower() == "RanToCompletion".ToLower())
                {
                    return childrenResult.Result.Children;
                }
            }
            catch (Exception ex)
            {
                _log.ErrorFormat("得到后代节点发生异常:{0},{1}", path, ex.Message + ex.StackTrace);
            }
            return null;
        }

/// <summary>
        /// 关闭连接
        /// </summary>
        /// <returns></returns>
        public string Close() {
            try
            {
                Task task = _zooKeeper.closeAsync();
                task.Wait();
                if (task.Status.ToString().ToLower() == "RanToCompletion".ToLower())
                {
                    return _success;
                }
            }
            catch (Exception ex)
            {
                LogHelper.GetLoger().ErrorFormat("关闭zookeeper发生异常:{0}", ex.Message + ex.StackTrace);
            }
            return _fail;
        }

/// <summary>
        /// 得到连接状态
        /// </summary>
        /// <returns></returns>
        public string GetState() {
            try
            {
                if (_zooKeeper != null)
                {
                    ZooKeeper.States states = _zooKeeper.getState();
                    return states.ToString();
                }
            }
            catch (Exception ex)
            {
                _log.ErrorFormat("获取zookeeper连接状态发生异常:{0}", ex.Message + ex.StackTrace);
            }
            return _fail;
        }

/// <summary>
        /// 是否已经连接
        /// </summary>
        /// <returns></returns>
        public bool Connected()
        {
            try
            {
                if (_zooKeeper != null)
                {
                    ZooKeeper.States states = _zooKeeper.getState();
                    if (states == ZooKeeper.States.CONNECTED || states == ZooKeeper.States.CONNECTEDREADONLY)
                    {
                        return true;
                    }
                }
            }
            catch (Exception ex)
            {
                _log.ErrorFormat("获取zookeeper连接状态发生异常:{0}", ex.Message + ex.StackTrace);
            }
            return false;
        }
    }

--------TaskHelper.cs--------
public class TaskHelper
    {
        private readonly ILog _log;
        private int forcerun = Convert.ToInt32(ConfigurationManager.AppSettings["forcerun"]);
        private string servicename = ConfigurationManager.AppSettings["servicename"];
        private string pathname = ConfigurationManager.AppSettings["pathname"];
        private ZooKeeperHelper _zooKeeperHelper;
        private ZooKeeper _zooKeeper;
        //单例输出,否则通知过多可能导致内存溢出
        private static TaskHelper _taskHelper;
        private static object _obj = new object();

private TaskHelper(ILog log,int sessionTimeOut = 10 * 1000)
        {
            _log = log;
            _zooKeeperHelper = new ZooKeeperHelper(_log,sessionTimeOut);
        }

public static TaskHelper GetInstance(ILog log, int sessionTimeOut = 10 * 1000)
        {
            if (_taskHelper == null)
            {
                lock (_obj)
                {
                    if (_taskHelper == null)
                    {
                        _taskHelper = new TaskHelper(log,sessionTimeOut);
                    }
                }
            }
            return _taskHelper;
        }

public bool Return()
        {
            if (forcerun != 1)
            {
                try
                {
                    if (!_zooKeeperHelper.Connected())
                    {
                        _zooKeeper = _zooKeeperHelper.Connect(AuthEnum.world, "");
                        if (_zooKeeper == null)
                        {
                            _log.ErrorFormat("连接zooKeeper失败,时间是:{0}", DateTime.Now);
                            return true;
                        }
                    }
                    string path = ("/" + pathname);
                    string data = servicename;
                    string str = _zooKeeperHelper.ExistsNode(path, new NodeWatcher(_log));
                    if (str != "success")
                    {
                        str = _zooKeeperHelper.CreateNode(path, data);
                        if (str != path)
                        {
                            _log.ErrorFormat("创建路径失败,时间是:{0}", DateTime.Now);
                            return true;
                        }
                    }

string lockname = _zooKeeperHelper.GetData(path, new NodeWatcher(_log));

#region 测试通知
                    //string cg = _zooKeeperHelper.SetData(path, "hahhahahah");
                    //cg = _zooKeeperHelper.GetData(path, new NodeWatcher(_log));
                    //cg = _zooKeeperHelper.SetData(path, "1111111111");
                    //cg = _zooKeeperHelper.GetData(path, new NodeWatcher(_log));
                    //cg = _zooKeeperHelper.DeleteNode(path);
                    #endregion

//执行标识
                    if (lockname != servicename)
                    {
                        _log.ErrorFormat("非工作时间,当前执行的服务是:{0},时间是:{1}", lockname, DateTime.Now);
                        return true;
                    }
                }
                catch (Exception exception)
                {
                    _log.ErrorFormat("zooKeeperHelper出现异常:{0},时间是:{1}", exception.Message + exception.StackTrace, DateTime.Now);
                }
            }
            return false;
        }
    }

5.分布式锁应用场景

//协调分布式服务
TaskHelper.GetInstance(log).Return()
---------------------
作者:DO_DAJIANGJUN
来源:CSDN
原文:https://blog.csdn.net/XuWei_XuWei/article/details/80611659
版权声明:本文为博主原创文章,转载请附上博文链接!

C#使用zookeeper的更多相关文章

  1. 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)

    一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...

  2. [译]ZOOKEEPER RECIPES-Leader Election

    选主 使用ZooKeeper选主的一个简单方法是,在创建znode时使用Sequence和Ephemeral标志.主要思想是,使用一个znode,比如"/election",每个客 ...

  3. zookeeper源码分析之六session机制

    zookeeper中session意味着一个物理连接,客户端连接服务器成功之后,会发送一个连接型请求,此时就会有session 产生. session由sessionTracker产生的,sessio ...

  4. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

  5. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

  6. zookeeper源码分析之三客户端发送请求流程

    znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...

  7. zookeeper源码分析之二客户端启动

    ZooKeeper Client Library提供了丰富直观的API供用户程序使用,下面是一些常用的API: create(path, data, flags): 创建一个ZNode, path是其 ...

  8. zookeeper源码分析之一服务端启动过程

    zookeeper简介 zookeeper是为分布式应用提供分布式协作服务的开源软件.它提供了一组简单的原子操作,分布式应用可以基于这些原子操作来实现更高层次的同步服务,配置维护,组管理和命名.zoo ...

  9. zookeeper集群的搭建以及hadoop ha的相关配置

    1.环境 centos7 hadoop2.6.5 zookeeper3.4.9 jdk1.8 master作为active主机,data1作为standby备用机,三台机器均作为数据节点,yarn资源 ...

  10. 如何编译Zookeeper源码

    1. 安装Ant Ant下载地址:http://ant.apache.org/bindownload.cgi 解压即可. 2. 下载Zookeeper源码包 https://github.com/ap ...

随机推荐

  1. 【转】cs231n学习笔记-CNN-目标检测、定位、分割

    原文链接:http://blog.csdn.net/myarrow/article/details/51878004 1. 基本概念 1)CNN:Convolutional Neural Networ ...

  2. English trip -- VC(情景课)4 A Health

    Word doctor doctor's office medicine   [ˈmɛdɪsɪn]  n. 药:医学:内科:巫术  vt. 用药物治疗:给…用药 pill  n. 药丸 nurse   ...

  3. LeetCode--110--平衡二叉树

    问题描述: 给定一个二叉树,判断它是否是高度平衡的二叉树. 本题中,一棵高度平衡二叉树定义为: 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过1. 示例 1: 给定二叉树 [3,9,20,n ...

  4. SQL 基础学习(2) Joining 和function , 作业没有做,需要看百宝箱。NOsql的概念

    SQL 基础学习(2) Joining 可以同时关联(joining)多张表进行复杂的查询. 相比于用Rails捞出数据再用Ruby进行过滤组合,使用SQL更加高效,节能. 以下是 users has ...

  5. Python并行(parallel)之谈

    简介 可以先看看并发Concurrent与并行Parallel的区别 在谈并行前,头脑中总会浮出多线程.多进程.线程/进程同步.线程/进程通信等词语. 那为什么需要同步.通信,它们之间的作用是怎样的呢 ...

  6. 最小生成树(模板 Kruskal)

    Description 某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离.省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达 ...

  7. 用POI导出excel时,较长的数字不想被自动变为科学计数法的解决方式(转)

    做过很多次导出excel了.都碰到一个问题,内容里如果包含一个比较长的数字,比如订单号“2546541656596”,excel会自动变成科学计数法... 弄过好几次都没有解决,最近又要导出excel ...

  8. spting Boot 创建一个springBoot项目

    spting Boot 创建一个springBoot项目 1)学习springBoot使用软件:IDEA软件(前面的文章有安装idea的过程). 也可以使用另一种方法在https://start.sp ...

  9. vue2.0对不同数据类型的显示

  10. 程序中使用7z.exe解压不完整的问题

    今天在代码中使用7x.exe解压一个tar压缩包,完成之后,发现关键性的文件不存在, 再细看发现,很多文件都没解压出来. 经研究,发现是这个压缩包中,有2个文件解压位置一样, 7z.exe在中途弹出提 ...