zoukankan      html  css  js  c++  java
  • [ZooKeeper.net] 1 模仿dubbo实现一个简要的http服务的注册 基于webapi

    今天来试着模仿下dubbo实现一个简要的http服务的注册,虽说是模仿不过是很廉价的那种,只是模仿了一点点点......

    先放上demo目录结构:

     

    开头还是把ZooKeeper的一些简要介绍搬过来看看,这样让大家也能多了解点儿:

          ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,它包含一个简单的原语集,分布式应用程序可以基于它实现同步服务,配置维护和命名服务等。Zookeeper是hadoop的一个子项目,其发展历程无需赘述。在分布式应用中,由于工程师不能很好地使用锁机制,以及基于消息的协调机制不适合在某些应用中使用,因此需要有一种可靠的、可扩展的、分布式的、可配置的协调机制来统一系统的状态。Zookeeper的目的就在于此。

          Zoopkeeper 提供了一套很好的分布式集群管理的机制,就是它这种基于层次型的目录树的数据结构,并对树中的节点进行有效管理,从而可以设计出多种多样的分布式的数据管理模型。

    OK,更多介绍大家自行搜索吧,主要点【基于层次型的目录树的数据结构,并对树中节点进行有效管理】,这句话是不是可以理解就是树形结构,我也放个图,省的还要大家脑补......

                          

    ps.有关ZooKeeper的安装不管是windows还是linux不论是单机还是集群网上一搜好多的,我用的zookeeper-3.4.6 windows版的

    首先我们要获取到ZooKeeper.Net的客户端

     首先定义个IZooKeeperFactory

        public interface IZooKeeperFactory
        {
            ZooKeeper Connect(string address);
            ZooKeeper Connect(string address, TimeSpan timeoutSpan);
            ZooKeeper Connect(string address, TimeSpan timeoutSpan, IWatcher watcher);
            ZooKeeper Connect(string address, TimeSpan timeoutSpan, IWatcher watcher, long sessionId, byte[] password);
        }

    然后ZooKeeperFactory 和 Watcher

     public sealed class ZooKeeperFactory : IZooKeeperFactory
        {
            public static IZooKeeperFactory Instance = new ZooKeeperFactory();
            private ZooKeeperFactory() { }
            //创建一个Zookeeper实例,第一个参数为目标服务器地址和端口,第二个参数为Session超时时间,第三个为节点变化时的回调方法     
            public ZooKeeper Connect(string address)
            {
                return Connect(address, new TimeSpan(0, 0, 0, 30), new Watcher());
            }
            public ZooKeeper Connect(string address, TimeSpan timeoutSpan)
            {
                return Connect(address, timeoutSpan, new Watcher());
            }
            public ZooKeeper Connect(string address, TimeSpan timeoutSpan, IWatcher watcher)
            {
                return new ZooKeeper(address, timeoutSpan, watcher);
            }
            public ZooKeeper Connect(string address, TimeSpan timeoutSpan, IWatcher watcher, long sessionId, byte[] password)
            {
                return new ZooKeeper(address, timeoutSpan, watcher, sessionId, password);
            }
        }
    ZooKeeperFactory
     internal class Watcher : IWatcher
        {
            public void Process(WatchedEvent @event)
            {
                if (@event.Type == EventType.NodeChildrenChanged)
                {
                    // Console.WriteLine(@event.Path + "   此路径节点变化了!");
                }
                if (@event.Type == EventType.NodeDataChanged)
                {
                    // Console.WriteLine(@event.Path + "   此路径节点变化了!");
                }
                if (@event.Type == EventType.NodeDeleted)
                {
                    // Console.WriteLine(@event.Path + "   此路径节点变化了!");
                }
               
            }
        }
    Watcher

    以上直接用于创建Zookeeper的实例,各个参数代码中也写了说明

    然后我们创建UserServicesController 里面写了两个服务 1.User/sayhello  2.User/saybye

    public class UserServicesController : ApiController
        {
            [Route("User/sayhello")]
            public string sayhello()
            {
                return "hello world!";
            }
            [Route("User/saybye")]
            public string saybye()
            {
                return "byebye world!";
            }
        }
    View Code

    我们最终要实现的结果是这样子的:【x】只是为了起到标示作用 

         ︱-------【1】UserServices
         ︱-----------【1.1】User.sayhello 
         ︱----------------【1.1.1】192.168.0.1:80 
         ︱----------------【1.1.2】192.168.0.2:80 
         ︱-----------【1.2】User.saybye 
         ︱----------------【1.2.1】192.168.0.1:81 
         ︱----------------【1.2.2】192.168.0.2:81

     接下来来看看最主要的一个类 ScanConfig.cs

    先说下大概逻辑:

        1.初始化zk客户端 

        2.将服务名称UserServices 注册为主节点 (永久节点)

        3.获取所有webapi服务路径 例如:User/saybye 

        4.循环将所有服务路径注册为zk节点(永久节点)   读取服务器IP地址(临时节点 会话断开 节点自动消失) 注册到 每个服务节点下

    下面把代码贴一下,代码中也有注释,最后会给出demo

     public class ScanConfig
        {
    
            private String connectString = "127.0.0.1:2181";
            private ZooKeeper zk = null;
            public ScanConfig()
            {
                init();
            }
            public void init()
            {
                try
                {
                    //初始化zk客户端
                    buildZKclient();
                    //绑定服务父节点  services名称
                    registBiz();
                    //得到所有服务地址
                    List<String> services = getServicePath();
                    //把服务注册到zk
                    registBizServices(services);
                }
                catch (Exception)
                {
                    //日志记录 
                }
            }
    
            /// <summary>
            /// 初始化连接
            /// </summary>
            private void buildZKclient()
            {
                IZooKeeperFactory _factory = ZooKeeperFactory.Instance;
                zk = _factory.Connect(connectString, new TimeSpan(0, 0, 0, 30));
            }
    
            /// <summary>
            /// 绑定父节点
            /// </summary>
            private void registBiz()
            {
                if (zk.Exists("/" + WebApiConfig.bizCode, true) == null)
                {
                    //创建一个目录节点,不进行ACL权限控制,节点为永久性的  
                    zk.Create("/" + WebApiConfig.bizCode, ("Test:" + WebApiConfig.bizCode).GetBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.Persistent);
                }
            }
            /// <summary>
            ///   通过注解得到所有Api服务地址
            /// </summary>
            /// <returns></returns>
            private List<String> getServicePath()
            {
                List<String> PathString = new List<string>();
                Collection<ApiDescription> ApiString = GlobalConfiguration.Configuration.Services.GetApiExplorer().ApiDescriptions;
                foreach (var api in ApiString)
                {
                    PathString.Add(api.RelativePath.Replace("/", "."));
                }
                return PathString;
            }
            /// <summary>
            ///  把服务注册到zk
            /// </summary>
            /// <param name="Services">所有Api服务地址</param>
            private void registBizServices(List<String> Services)
            {
                //获取服务IP地址端口
                IPAddress[] IPList = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName()).AddressList;
                string hostName = IPList[0].ToString();
                //创建临时节点 会话断开 节点自动消失
                foreach (var apiname in Services)
                {
                    if (zk.Exists("/" + WebApiConfig.bizCode + "/" + apiname, true) == null)
                    {
                        //创建一个目录节点,不进行ACL权限控制,节点为永久性的   服务名称 
                        zk.Create("/" + WebApiConfig.bizCode + "/" + apiname, ("Test:" + WebApiConfig.bizCode).GetBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.Persistent);
                    }
                    //创建一个目录节点,不进行ACL权限控制,节点为临时性的  服务提供者ip地址 
                    zk.Create("/" + WebApiConfig.bizCode + "/" + apiname + "/" + hostName, ("Test:" + WebApiConfig.bizCode).GetBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.Ephemeral);
                }
            }
    
    
    
        }
    ScanConfig

     最后Global.asax中 Application_Start方法加入就OK了

    ScanConfig scan = new ScanConfig();

     有关注册后节点过一段时间消失的问题可以参考下 _xxy 的http://www.cnblogs.com/xxyBlogs/p/5538583.html 这篇文章。

    之前做过一个webservices接口里面有一些数据是调用别的项目的webservices接口,然后第一次访问这个接口处理时间老是很慢,处理方法跟 _xxy 这种处理大体一致,因为iis有闲时超时跟回收设置,所以到时间或回收后,webservices的xml序列化的操作需要从新做,所以调用很耗时,不过往往都是第一次很耗时,序列化过完后面就变的很快,加上当是部署了六台,不定那一台就处于闲时状态,当是就因为这个问题项目耽搁好几天没上线,后来设置了iis的闲时超时跟回收设置,又写了个页面,页面的load事件访问一下webservices,然后Application_Start的时候就启动一个定时器,设置一定时间后就http get一下这个页面,等于也是让序列化的过程在不知不觉中处理掉,这样有实际业务来的时候序列化的操作不用做了,耗时的问题也不存在了,项目也成功上线了,希望能帮助到有此类问题的童鞋哈!

    demo下载:http://pan.baidu.com/s/1bpxifJx

  • 相关阅读:
    编辑器 --- Visual Studio Code 英文界面转换成中文(简体)
    CSS3 -- column 实现瀑布流布局
    CSS3 -- 边框圆角
    CSS3 -- 弹性盒
    自适应布局要素
    Vue -- 基础知识
    Vue -- element-ui el-table 的合计在第一行显示并可点击
    如何在网页标题栏title加入logo(icon)图标?
    linux下暴力破解工具hydra【转】
    linux 服务简介
  • 原文地址:https://www.cnblogs.com/Burt/p/6520455.html
Copyright © 2011-2022 走看看