Consul服务治理发现学习记录

  • A+
所属分类:.NET技术
摘要

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


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 

Consul服务治理发现学习记录

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

Consul服务治理发现学习记录

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

服务注册

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

Consul服务治理发现学习记录

安装Consul

Consul服务治理发现学习记录

健康检查

创建完成后就是默认的项目结构,我们添加一个健康检查的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 

Consul服务治理发现学习记录

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

Consul服务治理发现学习记录

服务消费

我们创建一个控制台程序,并安装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也可以看到。

Consul服务治理发现学习记录

Consul服务治理发现学习记录

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

Consul服务治理发现学习记录

可以看到我们注册的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();         } 

Consul服务治理发现学习记录