netcore 集成 consul集群

169 阅读3分钟

本文已参与「新人创作礼」活动.一起开启掘金创作之路。

netcore 集成 consul集群

分两步 第一步是服务内部集成consul,这个相对简单 第二步是ocelot集成consul网关,这个相对麻烦一点

1、内部微服务集成consul集群

需要的配置

public class ConsulConfig
        {
            public string IP { get; set; } //程序的本机地址 默认是本机的所有地址
            public int port { get; set; }//程序的本机端口 注册中心使用
            public string consulAddress { get; set; } //consul 地址
            public string serviceId { get; set; } //程序的服务id 唯一值
            public string serviceName { get; set; } //服务的名称 
            public string checkUrl { get; set; } //服务的名称
            public int checkInterval { get; set; } //服务检查间隔

            public string dataCenter { get; set; } //数据中心名称 默认的是dc1


            public string enable { get; set; } //是否启用


        }
配置:"Consul": {
    //单节点
    //"Address": "http://xxxx:8500",
    //"Address": "http://xxxx:8500",
    "CheckUrl": "/Heath/check",
    "CheckInterval": 60, //检查间隔(单位:秒)
    "DataCenter": "", //为空则是默认的 dc1
    "enable": "1", //是否启用  默认是不启用  1启用 其他不启用
    "ignoreNetwork": ".*Sangfor.*,.*Microsoft.*,.*TAP-Windows.*,.*VMware.*,.*VirtualBox.*,.*vEthernet.*,.*Virtual.*,.*Hyper-V.*" //忽略的网卡, //"Address": "http://xxxx:8500",
   "enable": "0", //是否启用  默认是不启用  1启用 其他不启用
     //集群模式
   "Address": "http://xxxx:8500,http://xxxx:8500,http://xxxx:8500",
   "DataCenter": "zz"

  },

集成方法

/// <summary>
        /// 添加consul客户端
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddConsulClient(this IServiceCollection services)
        {
            ConsulConfig consulConfig = getConfig(services);

            if (consulConfig.enable != "1")
            {
                //因为其他服务注入了 IConsulClient 当不启用consul是会报错 这里注入一个空的consul

                services.AddConsul(options =>
                {
                    options.Datacenter = consulConfig.dataCenter;
                    options.Address = new Uri("http://localhost:8500");
                    //options.Token = token1;
                    options.WaitTime = TimeSpan.FromSeconds(consulConfig.checkInterval);
                });

                return services;
            }


            foreach (string url in consulConfig.consulAddress.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries))
            {
                services.AddConsul(options =>
                {
                    options.Datacenter = consulConfig.dataCenter;
                    options.Address = new Uri(url);
                    //options.Token = token1;
                    options.WaitTime = TimeSpan.FromSeconds(consulConfig.checkInterval);
                });
            }
                  //覆盖原来的ConsulClientFactory工厂
            services.RemoveAll(typeof(IConsulClientFactory));
            services.TryAddSingleton<IConsulClientFactory, MyConsulClientFactory>();
            return services;
        }
        
        /// <summary>
        /// 添加客户端以及注册到注册中心
        /// </summary>
        /// <param name="services"></param>
        /// <returns></returns>
        public static IServiceCollection AddConsulClientAndRegistration(this IServiceCollection services)
        {
            ConsulConfig consulConfig = getConfig(services);

            services.AddConsulClient();
            if (consulConfig.enable != "1")
            {
                return services;
            }
            services.AddConsulServiceRegistration(options =>
            {
                options.Checks = new[]
                {
                    new AgentServiceCheck()
                    {
                        DeregisterCriticalServiceAfter = TimeSpan.FromMilliseconds(1), //服务停止后多久注销
                        Interval = TimeSpan.FromSeconds(10), //服务健康检查间隔
                        Timeout = TimeSpan.FromSeconds(10), //检查超时的时间
                        HTTP = consulConfig.checkUrl //检查的地址
                    }
                };
                options.Address = consulConfig.IP; //本程序的IP地址
                options.ID = consulConfig.serviceId; //服务编号,不可重复
                options.Name = consulConfig.serviceName; //服务名称
                options.Port = consulConfig.port;
            });

            return services;
        }
替换原来的ConsulClientFactory 默认的ConsulClientFactory不支持配置多个consul客户端public class MyConsulClientFactory : IConsulClientFactory
    {
        private readonly IOptionsMonitor<ConsulClientConfiguration> _optionsMonitor;

        public MyConsulClientFactory(IOptionsMonitor<ConsulClientConfiguration> optionsMonitor)
        {
            this._optionsMonitor = optionsMonitor;
        }

        public IConsulClient CreateClient()
        {
            return this.CreateClient(RegisterToConsulExtension.currentUseConsulName);
        }

        public IConsulClient CreateClient(string name)
        {
            return (IConsulClient)new ConsulClient(this._optionsMonitor.Get(name));
        }


    }

注意 需要在健康检查中或者定时任务中设置可用的consul客户端 调用如下的方法,如果某个consul客户端挂掉了可以切换到其他的consul服务(需要定义两个变量,用于维护目前使用的是哪个consul客户端)

//保存所有的consul客户端名称
        public static List<String> consulNames = new List<string>();

        //当前使用的consul客户端名字
        public static string currentUseConsulName = "ConsulClient0";

\


/// <summary>
        /// 设置可用的consul客户端
        /// 检查当前的consul客户端是否可用 不可用时会找一个可用的consul客户端
        /// </summary>
        /// <param name="consulClientFactory"></param>
        public static void SetCurrentConsulClient(IConsulClientFactory consulClientFactory)
        {
            IConsulClient consulClient = consulClientFactory.CreateClient();
            try
            {
                string result = consulClient.Agent.GetNodeName().Result;
            }
            catch (Exception e)
            {
                List<String> badConsulNames = new List<string>()
                    {RegisterToConsulExtension.currentUseConsulName};
                Random random = new Random();

                while (true)
                {
                    List<string> okConsulNames = RegisterToConsulExtension.consulNames.FindAll(o => !badConsulNames.Contains(o));
                    if (okConsulNames.Count == 0)
                    {
                        break;
                    }

                    int next = random.Next(0, okConsulNames.Count);
                    String consulName = okConsulNames[next];
                    try
                    {
                        consulClient = consulClientFactory.CreateClient(consulName);
                        //如果这里异常这说明这个consul客户端不能用
                        string result = consulClient.Agent.GetNodeName().Result;

                        RegisterToConsulExtension.currentUseConsulName = consulName;
                        break;
                    }
                    catch (Exception exception)
                    {
                        badConsulNames.Add(consulName);
                    }
                }
            }
            LogUtils.Info($"当前使用的consul:{RegisterToConsulExtension.currentUseConsulName}");
        }

\

\

//注册到consul
            services.AddConsulClientAndRegistration();

2、ocelot 集成consul (ocelot 默认不支持consul集群(也可能是我没找到),需要重写部分方法)

除了上面要调用 services.AddConsulClientAndRegistration(); 外还需要修改ocelot注入

该方法参照 ocelot的 AddConsul 并且需要注入自定义的 MyConsulClientFactory ,重写get方法 覆盖原来的ConsulClientFactory
修改注入的方法
        public static IServiceCollection AddOcelotConsul(this IServiceCollection services)        {
            //添加客户端以及注册到注册中心
            services.AddConsulClientAndRegistration();

            //注入ocelot需要的类
            services.AddSingleton<ServiceDiscoveryFinderDelegate>(ConsulProviderFactory.Get);

            services.RemoveAll(typeof(Ocelot.Provider.Consul.IConsulClientFactory));
            services.AddSingleton<Ocelot.Provider.Consul.IConsulClientFactory, MyOcelotConsulClientFactory>();
            services.RemoveAll(typeof(IFileConfigurationPollerOptions));
            services.AddSingleton<IFileConfigurationPollerOptions, ConsulFileConfigurationPollerOption>();
            return services;
        }
自定义ConsulClientFactory 该工厂是ocelot里面的工厂不是 consul包里面的工厂public class MyOcelotConsulClientFactory: IConsulClientFactory
    {
        private Consul.AspNetCore.IConsulClientFactory consulClientFactory;
        public MyConsulClientFactory(Consul.AspNetCore.IConsulClientFactory consulClientFactory)
        {
            this.consulClientFactory = consulClientFactory;
        }
        public IConsulClient Get(ConsulRegistryConfiguration config)
        {
            return consulClientFactory.CreateClient();
        }
    }

如何使用?

直接注入 private Consul.AspNetCore.IConsulClientFactory consulClientFactory;

`创建 consul客户端 consulClientFactory.CreateClient();```