• (转)微服务_.NET Core Consul服务发现与治理


             原文地址:https://www.cnblogs.com/waynechan/p/9354909.html

    Consul官网:https://www.consul.io

    Consul下载地址:https://www.consul.io/downloads.html

    Consul nuget 命令:Install-Package Consul

      我的理解是,Consul是一个服务管理者,系统中所有使用到的服务他都帮你管理好,促销高峰需要新增服务的时候,服务开启来就自动注册到Consul中,服务下线关闭,也自动从Consul注销,无缝衔接,对于使用者来说,你只需要跟Consul说我要某某某服务,Consul就会返回当前在Consul上注册的可用的服务给回你,你也无需像以前那样将服务的地址配置在系统当中,就好像DNS服务器那样,你输入域名,DNS服务器返回其中一个IP地址给你,然后你就可以正常访问, 另外在集群环境下选择服务的策略交给调用方,你可以选择随机、轮询、权重等方式,具体视乎你的需求。

    一、Windows系统启动Consul

    这里以Windows系统进行演示,实际项目中可以搭建在Linux上,下载到本地之后解压,使用命令行模式进入到Consul目录,输入命令启动Consul服务:

    consul.exe agent -dev

    启动Consul成功,命令行信息中显示,可以使用地址:  http://127.0.0.1:8500   打开UI管理界面进行查看管理操作。

     

     

    二、.NET Core+Consul 演示

    1、新建一个ASP.NET Core Web 应用程序,nuget安装Consul:Install-Package Consul 

    2、增加用于Consul健康监测的Controller,这里就是一个简单的Controller、Action,能正常被访问即可。

    复制代码
    namespace MsgService.Controllers
    {
        [Produces("application/json")]
        [Route("api/Health")]
        public class HealthController : Controller
        {
            [HttpGet]
            public IActionResult Get()
            {
                Console.WriteLine("健康检查" + DateTime.Now);
                return Content("ok");
            }
        }
    }
    复制代码

    3、修改应用程序站点的Startup类 ,在函数Configure 中增加多一个参数 IApplicationLifetime appLifeTime,然后在Configure函数中增加注册、注销的代码,这段代码的意思是,当应用程序站点启动或者注销的时候,就会对Consul进行消息通知。这里ConsulConfig方法里写死了我本机运行的Consul地址:http://127.0.0.1:8500,实际项目中肯定是要做成配置的。

    复制代码
        //Consul 新增 IApplicationLifetime appLifeTime参数
        public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime appLifeTime)
        {
                //注册Consul 
                string ip = Configuration["ip"];
                string port = Configuration["port"];
                string serviceName = "MsgService";
                string serviceId = serviceName + Guid.NewGuid();
                using (var consulClient = new ConsulClient(ConsulConfig))
                {
                    AgentServiceRegistration asr = new AgentServiceRegistration
                    {
                        Address = ip,
                        Port = Convert.ToInt32(port),
                        ID = serviceId,
                        Name = serviceName,
                        Check = new AgentServiceCheck
                        {
                            DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),
                            HTTP = $"http://{ip}:{port}/api/Health",
                            Interval = TimeSpan.FromSeconds(10),
                            Timeout = TimeSpan.FromSeconds(5),
                        },
                    };
                    consulClient.Agent.ServiceRegister(asr).Wait();
                }
     
                //注销Consul 
                appLifeTime.ApplicationStopped.Register(() =>
                {
                    using (var consulClient = new ConsulClient(ConsulConfig))
                    {
                        Console.WriteLine("应用退出,开始从consul注销");
                        consulClient.Agent.ServiceDeregister(serviceId).Wait();
                    }
                });
            }
           
           //Consul 配置委托
            private void ConsulConfig(ConsulClientConfiguration config)
            {
                config.Address = new Uri("http://127.0.0.1:8500"); //Demo硬编码Consul的地址
                config.Datacenter = "dc1";
            }
    复制代码

    4、修改应用程序站点的Program.BuildWebHost 方法,目的是方便我们在web应用程序bin目录下以指定的IP地址、指定的端口启动服务

    复制代码
            /// <summary>
            /// 设置NetCore监听端口取命令行中的参数
            /// </summary>
            /// <param name="args"></param>
            /// <returns></returns>
            public static IWebHost BuildWebHost(string[] args)
            {
                var config = new ConfigurationBuilder()
                 .AddCommandLine(args)
                 .Build();
                string ip = config["ip"];
                string port = config["port"];
                Console.WriteLine($"ip={ip},port={port}");
                return WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .UseUrls($"http://{ip}:{port}")
                .Build();
            }
    复制代码

    5、启动服务

    打开应用程序目录定位在bin目录下,使用命令行模式输入命令,以指定的IP、指定的端口启动服务, 一切正常的话,在consul管理界面可以看到已经注册上的服务信息。

    这里只注册一个服务进行演示,在实际微服务项目中,肯定是集群环境的,比如同一个服务,你有4台机器,那consul上就注册了4个,服务名字都是一样的,只是URL地址不一样,当遇上促销的时候,服务压力比较大,这时候当要加多一台服务器,新的服务就自动加到consul上来,消费者就从consul取其中一个服务进行调用。

    dotnet  【应用程序.dll】 --ip 127.0.0.1 --port 6001

    三、服务消费

     1、新建一个.NET Core 控制台应用程序;

     2、nuget安装Consul组件;

    3、取出已经在Consul注册的全部服务

    复制代码
           static void Main(string[] args)
            {
     
                using (var consul = new Consul.ConsulClient(c =>
                {
                    c.Address = new Uri("http://127.0.0.1:8500");
                }))
                {
                    //取在Consul注册的全部服务
                    var services = consul.Agent.Services().Result.Response;
                    foreach (var s in services.Values)
                    {
                        Console.WriteLine($"ID={s.ID},Service={s.Service},Addr={s.Address},Port={s.Port}");
                    }
                }
     
                Console.ReadKey();
            }
        }
    复制代码

    现在在Consul已经注册了3个MsgService服务,打印在控制台上。

    4、随机从注册的服务中取出其中一个服务

    当我们在consul上注册了N个相同的服务之后,我们肯定不能每次都选取某一个服务的,不然得累死那台服务,而其他服务却是空闲的状态,因此我们加入随机选取的逻辑,从注册的N个服务中,随机选取其中一个服务,另外还有其他比如轮询,权重等等的策略,使得我们更灵活的调用服务。

    复制代码
    using (var consul = new Consul.ConsulClient(c =>
     {
          c.Address = new Uri("http://127.0.0.1:8500"); //Consul地址
      }))
     {
           //取出全部的MsgService服务
           var services = consul.Agent.Services().Result.Response.Values.Where(p => p.Service.Equals("MsgService", StringComparison.OrdinalIgnoreCase));
     
           //客户端负载均衡,随机选出一台服务
            Random rand = new Random();
            var index = rand.Next(services.Count());
            var s = services.ElementAt(index);
            Console.WriteLine($"Index={index},ID={s.ID},Service={s.Service},Addr={s.Address},Port={s.Port}");
     }
    复制代码

    5、服务调用

    复制代码
    //向服务发送请求
    using (var httpClient = new HttpClient())
    using (var httpContent = new StringContent("{phoneNum:'119',msg:'help me'}", Encoding.UTF8, "application/json"))
    {
            var result = httpClient.PostAsync($"http://{s.Address}:{s.Port}/api/SMS/Send_LX", httpContent);
            Console.WriteLine($"调用{s.Service},状态:{result.Result.StatusCode}");
     }
    复制代码

    其它参考资料

    1)https://www.cnblogs.com/xuanye/p/10223924.html

    2) 健康检测https://www.cnblogs.com/duanxz/p/9662862.html

    3)https://www.cnblogs.com/Leo_wl/p/9142530.html

    4)https://www.cnblogs.com/alan-lin/p/9403762.html

  • 相关阅读:
    在Unix上使用管道压缩exp导出文件
    自制CPU的黑暗历程一
    Error C1189: #error: Please use the /MD switch for _AFXDLL builds
    Redis乐观锁解决高并发抢红包的问题
    PHP分页类
    汇编基础——使用nasm和bochs学习汇编
    数据同步工具DBsync
    完成端口的一些教程
    sdf
    (转)C#(WIN FORM)两个窗体间LISTVIEW值的修改
  • 原文地址:https://www.cnblogs.com/hhhh2010/p/11113564.html
Copyright © 2020-2023  润新知