Thrift 客户端 C# ---实现zookeeper监视(1)

17 篇文章 0 订阅
6 篇文章 0 订阅

干货---实现思路:RPC Thrift 服务端 注册服务端信息到zookeeper上。客户端从zookeeper获取服务端信息,并实现负载。
经验---注意事项。
Thrift服务端
使用ZooKeeperNet nugget包。
使用zookeeper的坑,
1、)没有zookeeper.open的方法。
2、)zookeeper 实例化【new ZooKeeper(connectstring, sessionTimeout, watcher);】后,连接CONNECTED并不是同步的。
zookeeper监视,使用一次后就失效。坑
1)、zookeeper 监视某个节点,无论增加删除等操作,一律都只有EventType.NodeChildrenChanged。
2)想检测某个末端节点,使用【_zookeeper.Exists方法即可】。
功能:
1)实现简单负载,轮询负载。随机负载。
2)实现从监视节点取出服务器节点信息。
3)长连接线程池未实现。可以去掉。
4)实现自动释放socket连接资源避免,线上出问题。
使用    public static Client GetSingleInstance(string rpcServicenamespace) 实列化,负载才能正常使用。
    public class Client : IDisposable
    {
        /// <summary>
        /// 客户端池-根据不同业务自动选择对应业务客户端
        /// </summary>
        static Dictionary<string, Client> _clientPool = new Dictionary<string, Client>();
        /// <summary>
        ///客户端-TBufferedTransport
        /// </summary>
        internal Dictionary<string, TBufferedTransport> _tBufferedTransportPool = new Dictionary<string, TBufferedTransport>();
        /// <summary>
        /// zookeeper注册唯一标识
        /// </summary>
        private string _rpcServicenamespace = null;//"XXXX.XXXX.RegionCityRPC"
        /// <summary>
        /// 使用一个zookeeper客户端
        /// </summary>
        private static ZooKeeper _zookeeper = null;
        /// <summary>
        /// 多线程锁
        /// </summary>
        internal static object _look = new object();
        /// <summary>
        /// zookeeper-所有监视节点
        /// </summary>
        public IEnumerable<string> _nodeChildren = null;
        /// <summary>
        /// 轮询负载计数器
        /// </summary>
        private int CountLoadbalance = 0;
        
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="rpcServicenamespace"></param>
        public Client(string rpcServicenamespace)
        {
            this._rpcServicenamespace = rpcServicenamespace;
        }
        /// <summary>
        /// 获取一个唯一实例
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static T GetSingleInstance<T>(Dictionary<string, T> dictionary, string key, T t) where T : class
        {
            if (!dictionary.Keys.Contains(key))
            {
                lock (_look)
                {
                    if (!dictionary.Keys.Contains(key))
                    {
                        TBufferedTransport tbufferedTransport = t as TBufferedTransport;
                        //if (t != null)
                        //{
                        //    try
                        //    {
                        //        tbufferedTransport.Open();
                        //    }
                        //    catch (Exception e)
                        //    {
                        //        Console.WriteLine("初始化TBufferedTransport连接异常!");
                        //    }
                        //}
                        dictionary.Add(key, t);
                    }
                }
            }
            return dictionary[key];
        }
        /// <summary>
        /// 获取一个唯一实例
        /// </summary>
        /// <param name="rpcServicenamespace"></param>
        /// <returns></returns>
        public static Client GetSingleInstance(string rpcServicenamespace)
        {
            /*
            if (!_clientPool.Keys.Contains(rpcServicenamespace))
            {
                lock (_look)
                {
                    if (!_clientPool.Keys.Contains(rpcServicenamespace))
                    {
                        _clientPool.Add(rpcServicenamespace, new Client(rpcServicenamespace));
                    }
                }
            }
            return _clientPool[rpcServicenamespace];
             */
            return GetSingleInstance<Client>(_clientPool, rpcServicenamespace, new Client(rpcServicenamespace));
        }
        //public void FilterTBufferedTransportPool(Client client)
        //{
        //    foreach (var item in client._tBufferedTransportPool)
        //    {
        //        item.Value.IsOpen
        //    }
        //}
        /// <summary>
        /// 获取baoxian/appSettings配置
        /// </summary>
        /// <returns></returns>
        private static NameValueCollection GetConfig()
        {
            return (NameValueCollection)ConfigurationManager.GetSection("baoxian/appSettings");
        }
        /// <summary>
        /// 初始化
        /// </summary>
        public void Init()
        {
            CreateZookeeperClient();
        }
        /// <summary>
        /// 创建一个zookeeper客户端
        /// </summary>
        /// <returns></returns>
        public ZooKeeper CreateZookeeperClient()
        {
            string connectstring = GetConfig()["ZookeeperConnectString"];// "192.168.1.3:2331
            TimeSpan sessionTimeout = new TimeSpan(0, 0, 60);
            var watcher = new ClientWatcher(_rpcServicenamespace);
            if (_zookeeper == null)//单线程
            {
                lock (_look)
                {
                    if (_zookeeper == null)//多线程
                    {
                        _zookeeper = new ZooKeeper(connectstring, sessionTimeout, watcher);
                        string path = string.Format(GetConfig()[_rpcServicenamespace], _rpcServicenamespace);//string.Format("/test/servicecenter-dev/services/{0}/providers", "YinXin.BaoXian.UserOrderCount");
                        int count = 0;
                        while (true)
                        {
                            Console.WriteLine("_zookeeper 重连次数:" + count);
                            count++;
                            System.Threading.Thread.Sleep(1000);//zookeeper的这个第三方有个坑。1、)没有zookeeper.open的方法。2、)zookeeper 实例化【new ZooKeeper(connectstring, sessionTimeout, watcher);】后,连接CONNECTED并不是同步的。
                            if (_zookeeper.State == ZooKeeper.States.CONNECTED)
                            {
                                GetChildrenWatcher();//zookeeper监视,使用一次后就失效。坑1)、zookeeper 监视某个节点,无论增加删除等操作,一律都只有EventType.NodeChildrenChanged。2)想检测某个末端节点,使用【_zookeeper.Exists方法即可】。
                                break;
                            }
                            if (count >= 60)//这里大于1分钟连接不上
                            {
                                Logs.WriteLogInfo("_zookeeper网络连接可能有问题!");
                                Console.WriteLine("_zookeeper网络连接可能有问题!");
                                break;
                            }
                        }

                        /*
                        watcher.WaitUntilConnected();
                        while (true)
                        {
                            System.Threading.Thread.Sleep(5000);
                            var tt = _zookeeper.GetChildren(path, watcher);
                            var aa = tt + "333";
                        }*/
                    }
                }
            }
            return _zookeeper;
        }
        /// <summary>
        /// 客户端监视-想监视的节点
        /// </summary>
        public void GetChildrenWatcher()
        {
            string path = string.Format(GetConfig()[_rpcServicenamespace], _rpcServicenamespace);//string.Format("/test/servicecenter-dev/services/{0}/providers", "XXX.XXX.UserOrderCount");
            //var watcher = new ClientWatcher();
            IEnumerable<string> nodeChildren = null;
            bool isError = false;
            try
            {
                nodeChildren = _zookeeper.GetChildren(path, true);
            }
            catch (Exception e)
            {
                Console.WriteLine(e.StackTrace);
                isError = true;
            }
            if (!isError)
            {
                lock (_look)
                {
                    _nodeChildren = nodeChildren;
                }
            }
            if (nodeChildren == null)
            {
                return;
            }
            foreach (var item in nodeChildren)
            {
                _zookeeper.Exists(path + "/" + item, true);
            }
        }
        /// <summary>
        /// 随机
        /// </summary>
        /// <returns></returns>
        public string Random()
        {
            IEnumerable<string> nodeChildren = null;
            if (_nodeChildren != null)
            {
                lock (_look)
                {
                    nodeChildren = _nodeChildren;
                }
            }
            Random random = new Random();
            int count = nodeChildren.Count();
            if (count == 0)
            {
                return "false";
            }
            int index = random.Next(0, nodeChildren.Count() - 1);
            return nodeChildren.ToList()[index];
        }
        /// <summary>
        /// 根据负载服务器生成TBufferedTransport
        /// </summary>
        /// <returns></returns>
        public TBufferedTransport GetTSocket(string servers)
        {
            //string servers = thriftClient.Random();//随机负载
            if (string.IsNullOrWhiteSpace(servers))
            {
                return null;
            }
            var list = servers.Split(':');
            if (list.Count() == 2)
            {
                //var tbufferedTransport = GetSingleInstance<TBufferedTransport>(_tBufferedTransportPool, servers, new TBufferedTransport(new TSocket(list[0], int.Parse(list[1]))));
                return GetSingleInstance<TBufferedTransport>(_tBufferedTransportPool, servers, new TBufferedTransport(new TSocket(list[0], int.Parse(list[1]))));
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// 轮询
        /// </summary>
        /// <returns></returns>
        public string Loadbalance()
        {
            int index = 0;
            IEnumerable<string> nodeChildren = null;
            if (_nodeChildren != null)
            {
                lock (_look)
                {
                    nodeChildren = _nodeChildren;
                    CountLoadbalance++;
                    CountLoadbalance = CountLoadbalance > _nodeChildren.Count() ? 1 : CountLoadbalance;
                    index = CountLoadbalance;
                }
            }
            if (index - 1 >= 0 && nodeChildren != null && nodeChildren.Count() != 0)
            {
                return nodeChildren.ToList()[index - 1];
            }
            else
            {
                Console.WriteLine("轮询--无节点");
                Logs.WriteLogInfo("轮询--无节点");
                return "轮询无节点";
            }
        }
        /// <summary>
        /// Dispose
        /// </summary>
        public void Dispose()
        {
            //关闭并销毁长连接
            _zookeeper.Dispose();
            foreach (var item in this._tBufferedTransportPool)
            {
                item.Value.Close();
                item.Value.Dispose();
            }
            //throw new NotImplementedException();
        }
    }
    /// <summary>
    /// zookeeper 监测事件实现
    /// </summary>
    internal class ClientWatcher : IWatcher
    {
        private Client client;
        //private readonly ManualResetEventSlim _connected = new ManualResetEventSlim(false);
        //private WatchedEvent _event;
        public ClientWatcher(string _rpcServicenamespace)
        {
            client = Client.GetSingleInstance(_rpcServicenamespace);
        }
        //public void WaitUntilConnected()
        //{
        //    _connected.Wait();
        //    if (_event == null) throw new ApplicationException("bad state");
        //    if (_event.State != KeeperState.SyncConnected)
        //        throw new ApplicationException("cannot connect");
        //}

        /// <summary>
        /// 实现Process监控事件
        /// </summary>
        /// <param name="event"></param>
        public void Process(WatchedEvent @event)
        {
            //_event = @event;
            switch (@event.State)
            {
                case KeeperState.Disconnected:
                    break;
                case KeeperState.Expired:
                    break;
                case KeeperState.NoSyncConnected:
                    break;
                case KeeperState.SyncConnected:
                    //_connected.Set();
                    break;
                case KeeperState.Unknown:
                    break;
                default:
                    break;
            }
            switch (@event.Type)
            {
                case EventType.NodeChildrenChanged:
                    client.GetChildrenWatcher();//监测节点
                    Console.Write(" EventType.NodeChildrenChanged");
                    break;
                case EventType.NodeCreated:
                    Console.Write("EventType.NodeCreated:");
                    break;
                case EventType.NodeDataChanged:
                    Console.Write("EventType.NodeDataChanged:");
                    break;
                case EventType.NodeDeleted:
                    if (!string.IsNullOrWhiteSpace(@event.Path))
                    {
                        #region socket 长连接时使用,慎用
                        string path = @event.Path.Substring(0, @event.Path.LastIndexOf('/'));
                        string name = @event.Path.Substring(@event.Path.LastIndexOf('/') + 1);
                        lock (Client._look)
                        {
                            client._tBufferedTransportPool[name].Close();
                            client._tBufferedTransportPool[name].Dispose();
                            client._tBufferedTransportPool.Remove(name);
                        }
                        #endregion
                    }
                    Console.Write("EventType.NodeDeleted:");
                    break;
                case EventType.None:
                    Console.Write("EventType.None:");
                    break;
                default:
                    break;
            }
        }
    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值