• Consul服务治理发现学习记录


    Consul 简介

    Consul是一个服务网格(微服务间的 TCP/IP,负责服务之间的网络调用、限流、熔断和监控)解决方案,它是一个一个分布式的,高度可用的系统,而且开发使用都很简便。它提供了一个功能齐全的控制平面,主要特点是:服务发现、健康检查、键值存储、安全服务通信、多数据中心。除了 Consul 之外,还有 Eureka、Zookeeper 等类似软件。

    https://www.jianshu.com/p/7d20dc58c9fc

    安装Consul

    我们这里是直接在Windows上开发,所以对应下载Windows版本的。下载地址:

    https://www.consul.io/downloads

    下载完成后实际就是consul.exe,我们在下载位置运行cmd命令

    consul agent -dev
    

    image-20200807102531448

    然后我们打开浏览器,输入http://localhost:8500/

    image-20200807102643159

    可以看到Consul已经启动了,但是除了他自己外还没有其他服务注册进来。

    服务注册

    我们创建一个Api项目,比如订单服务OrderService

    image-20200807103033654

    安装Consul

    image-20200807172615740

    健康检查

    创建完成后就是默认的项目结构,我们添加一个健康检查的Controller。健康检查的意思是Consul会根据我们的配置定时的去请求健康检查接口,判断当前服务是不是可用。避免提供挂掉的服务给消费者,当然间隔时间也会有,需要配合后面的熔断、降级使用。

    using System;
    using Microsoft.AspNetCore.Mvc;
    
    namespace Consul.OrderService.Controllers
    {
        [ApiController]
        [Route("[controller]")]
        public class HealthController : ControllerBase
        {
            public IActionResult Get()
            {
                Console.WriteLine("调用了健康检查" + DateTime.Now);
                return Ok("OK");
            }
        }
    }
    

    调用时我们输出下当前时间,可以看到Consul有没有调用健康检查。

    服务注册及注销

    因为这里需要指定Api的地址,所以我们配置一下获取配置。

    修改Program.cs

     public static IHostBuilder CreateHostBuilder(string[] args)
            {
                var config = new ConfigurationBuilder().AddCommandLine(args).Build();
                string ip = config["ip"];
                string port = config["port"];
    
                return Host.CreateDefaultBuilder(args)
                     .ConfigureWebHostDefaults(webBuilder =>
                     {
                         webBuilder.UseStartup<Startup>()
                             .UseUrls($"http://{ip}:{port}");
                     });
            }
    

    修改Startup.cs

             public void Configure(IApplicationBuilder app, IWebHostEnvironment env,IHostApplicationLifetime applicationLifetime)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
    
                app.UseRouting();
    
                app.UseAuthorization();
    
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllers();
                });
                string ip = Configuration["ip"];
                int port = Convert.ToInt32(Configuration["port"]);
                string serveiceName = "OrderService";
                string serviceId = serveiceName + Guid.NewGuid();
                using (var consulClient = new ConsulClient(ConsulConfig))
                {
                    AgentServiceRegistration agentServiceRegistration = new AgentServiceRegistration();
    
                    //服务编号,不能重复,用 Guid 最简单 
                    agentServiceRegistration.ID = serviceId;
                    //服务的名字
                    agentServiceRegistration.Name = serveiceName;
                    //服务提供者的能被消费者访问的 ip 地址(可以被其他应用访问的 地址,本地测试可以用 127.0.0.1,机房环境中一定要写自己的内网 ip 地址) 
                    agentServiceRegistration.Address = ip;
                    // 服务提供者的能被消费者访问的端口 
                    agentServiceRegistration.Port = port;
                    agentServiceRegistration.Check = new AgentServiceCheck()
                    {
                        //服务停止多久 后反注册(注销) 
                        DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),
                        //健康检查时间间隔,或者称为心跳 间隔 
                        Interval = TimeSpan.FromSeconds(10),
                        //健康检查地址 
                        HTTP = $"http://{ip}:{port}/health",
                        Timeout = TimeSpan.FromSeconds(5)
                    };
                    //注册服务到 Consul 
                    consulClient.Agent.ServiceRegister(agentServiceRegistration).Wait();//Consult 客户端的所有方法几乎都是异步方法,但是都没按照规范加上 Async 后缀,所以容易误导。记得调用后要 Wait()或者 await 
                }
                //程序正常退出的时候从 Consul 注销服务
                ////要通过方法参数注入 IHostApplicationLifetime 
                applicationLifetime.ApplicationStopped.Register(() =>
                {
                    using (var consulClient = new ConsulClient(ConsulConfig))
                    {
                        Console.WriteLine($"应用退出,开始从consul注销{serveiceName}");
                        consulClient.Agent.ServiceDeregister(serviceId).Wait();
                    }
                });
            }
            private void ConsulConfig(ConsulClientConfiguration configuration)
            {
                configuration.Address = new Uri("http://127.0.0.1:8500/");
                configuration.Datacenter = "dc1";
            }
    

    启动

    我们生成下Api项目,用命令启动

    dotnet Consul.OrderService.dll --ip localhost --port 5000
    

    image-20200807173332007

    打开Consul看一下,已经可以看到OrderService已经注册好了。而且是有健康检查的。

    image-20200807173700185

    服务消费

    我们创建一个控制台程序,并安装Consul

    修改下Program.cs

    class Program
        {
            static void Main(string[] args)
            {
                using (var consulClient = new ConsulClient(c =>
                {
                    c.Address = new Uri("http://127.0.0.1:8500");
                }))
                {
                    var services = consulClient.Agent.Services().Result.Response;
                    foreach (var agentService in services.Values)
                    {
                        Console.WriteLine($"id={agentService.ID},name={agentService.Service},ip={agentService.Address},port={agentService.Port}");
                    }
                }
                 
                Console.ReadKey();
            }
        }
    

    由于刚才我们只开了一个OrderService,现在我们多打开几个。

    dotnet Consul.OrderService.dll --ip localhost --port 5001
    dotnet Consul.OrderService.dll --ip localhost --port 5002
    dotnet Consul.OrderService.dll --ip localhost --port 5003
    

    我们可以看到4个服务都有健康检查,并且Consul也可以看到。

    image-20200807174901894

    image-20200807174817333

    我们启动下控制台应用程序

    image-20200807175037168

    可以看到我们注册的4个服务都是可以获取到的,那么我们随便请求一个试一下。

     static void Main(string[] args)
            {
                using (var consulClient = new ConsulClient(c =>
                {
                    c.Address = new Uri("http://127.0.0.1:8500");
                }))
                {
                    var services = consulClient.Agent.Services().Result.Response.Values.Where(s => s.Service.Equals("OrderService", StringComparison.OrdinalIgnoreCase));
                    if (!services.Any())
                    {
                        Console.WriteLine("找不到服务的实例");
                    }
                    else
                    {
                        //随机获取
                        var service = services.ElementAt(Environment.TickCount % services.Count());
    
                        using (HttpClient client=new HttpClient())
                        {
                           var result= client.GetAsync(new Uri($"http://{service.Address}:{service.Port}/WeatherForecast")).Result;
                           Console.WriteLine(result.Content.ReadAsStringAsync().Result);
                        }
    
                    }
                }
    
                Console.ReadKey();
            }
    

    image-20200810094937530

  • 相关阅读:
    C# base64编码、解码
    C#异常重试通用类Retry
    C#操作Control异步工具类
    Notepad++的Json格式化插件
    CG 标准函数库
    Unity 几种优化建议
    基于Unity的Profiler性能分析
    Time.timeScale、游戏暂停
    Lua 中的string库(字符串函数库)总结
    Lua 日志
  • 原文地址:https://www.cnblogs.com/jellydong/p/13468073.html
Copyright © 2020-2023  润新知