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. Android蓝牙通信功能开发

    1. 概述 Bluetooth 是几乎现在每部手机标准配备的功能,多用于耳机 mic 等设备与手机的连接,除此之外,还可以多部手机之间建立 bluetooth 通信,本文就通过 SDK 中带的一个聊天 ...

  2. Android 上传大文件

    最近工作需要实现使用 Android 手机上传图片的功能, 参考了网络上的很多资料, 不过网络上的代码都仅仅适合上传较小的文件, 当上传较大文件时(我在自己的测试机器上发现是 2M 左右), 就会因为 ...

  3. react notes

    jsx 在JSX中嵌入用户输入是安全的,默认情况下, 在渲染之前, React DOM 会格式化(escapes) JSX中的所有值. 从而保证用户无法注入任何应用之外的代码. 在被渲染之前,所有的数 ...

  4. 5-13 Rspec实际; validates处理Errors, TDD, 单元测试和验收测试,capybara

    validates处理验证错误:详见ActiveModel::Errors文档 一,errors ActiveModel::Errors的实例包含所有的❌.每个错误:key是每个属性的name, va ...

  5. 12月22日 update_columns,完成第9节。

    Update_columns(attributes) //等同于update_column 直接更新database. 使用UPdate SQL 语法. ⚠️ :忽略了validations, Cal ...

  6. javaScript 的 map() reduce() foreach() filter()

    map(映射), reduce(规约), forEach(遍历), filter(过滤),它们都是高阶函数,都是以传入不同的函数来以不同的方式操作数组元.ie都不支持 一.map方法 *概述 map( ...

  7. python-day20--正则表达式与re模块

    1.通过re模块可以做一些关于正则的相关操作 2.正则表达式:做字符串匹配的规则 1)字符组:在同一个位置可能出现的各种字符组成了一个字符组,在正则表达式中用[ ]表示 [0-9][a-f][A-F] ...

  8. 秒杀多线程第七篇 经典线程同步 互斥量Mutex

    本文转载于:http://blog.csdn.net/morewindows/article/details/7470936 前面介绍了关键段CS.事件Event在经典线程同步问题中的使用.本篇介绍用 ...

  9. Oracle HRMS APIs

    Oracle HRMS APIs..... Here I will be sharing all the Oracle HRMS APIs related articles. 参考地址: Oracle ...

  10. Java容器——Map接口

    1.定义 Map用于保存存在映射关系<key, value>的数据.其中key值不能重复(使用equals()方法比较),value值可以重复. 2.常用实现类 HashMap:和Hash ...