通过上一篇的学习,如今已经来到了服务注册发现环节;Consul 的核心功能就是服务注册和发现,Consul 客户端经过将本身注册到 Consul 服务器集群,而后等待调用方去发现服务,实现代理转发到真正的业务系统,还能够基于服务发现作负载均衡,甚至能够在客户端请求到底服务以前进行拦截,作一些基础性的工做,好比身份验证、限流、熔断等等业务系统的前瞻性工做。node
在 .NETCore 平台下,可使用 Consul 的客户端组件,使其嵌入到业务系统中,完成服务自动注册、健康检查等工做,为了使用这些自动化的功能,须要在项目中进行 nuget 包引用git
截止本文发文时,Consul 的 NETStandard 最新版本是 0.7.2.6,从版本号来看,更新的频率很是频繁,可是 Github 上的 star 数量并很少,这就表示 .NETCore 社区在 Consul 的关注度上仍是很是小众的。github
为了使用服务运行时侦听的地址和端口做为 Consul 健康检查的地址,须要对 Program.cs 进行简单的改造,代码以下:json
public static IWebHost BuildWebHost(string[] args) { var config = new ConfigurationBuilder().AddCommandLine(args).Build(); var url = $"{config["scheme"]}://{config["ip"]}:{config["port"]}"; return WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>() .UseConfiguration(config) .UseUrls(url) .Build(); }
上面的代码将命令行的参数编译为配置文件对象,这些参数为了方便调试,我一次性的写入了Properties\launchSettings.json 文件中,以下图api
在 launchSettings.json 文件中的表现形式为:服务器
{ "profiles": { "Ron.Consul": { "commandName": "Project", "commandLineArgs": "--scheme http --ip 172.16.10.227 --port 51800" } } }
咱们须要在服务启动后,将服务自动注册到 Consul 的代理服务器集群中,为此,须要封装一些简单的注册代码,以便复用app
public static class StartupExtension { /// <summary> /// 定义服务健康检查的url地址 /// </summary> public const string HEALTH_CHECK_URI = "/consul/health/check"; /// <summary> /// 读取 Consul 配置,注入服务 /// </summary> /// <param name="service"></param> /// <param name="configuration"></param> /// <returns></returns> public static IServiceCollection AddConsulConfig(this IServiceCollection service, IConfiguration configuration) { var clientConfig = configuration.GetSection("Consul").Get<ConsulConfig>(); service.Configure<ConsulConfig>(configuration.GetSection("Consul")); return service; } /// <summary> /// 将 ConsulClient 注入管道 /// </summary> /// <param name="app"></param> /// <param name="configuration"></param> /// <param name="lifetime"></param> /// <param name="cc"></param> /// <returns></returns> public static IApplicationBuilder UseConsul(this IApplicationBuilder app, IConfiguration configuration, IApplicationLifetime lifetime, IOptions<ConsulConfig> cc) { var clientConfig = cc.Value; //获取服务运行侦听的地址和端口做为健康检查的地址 var clientIP = new Uri($"{configuration["scheme"]}://{configuration["ip"]}:{configuration["port"]}"); var serviceId = $"{clientConfig.ClientName}-{clientIP.Host}-{clientIP.Port}"; var ipv4 = clientIP.Host; var consulClient = new ConsulClient(config => { config.Address = new Uri(clientConfig.Server); config.Datacenter = clientConfig.DataCenter; }); var healthCheck = new AgentServiceCheck() { DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(7), // 服务启动 7 秒后注册服务 Interval = TimeSpan.FromSeconds(9), // 健康检查的间隔时间为:9秒 HTTP = $"{clientIP.Scheme}://{ipv4}:{clientIP.Port}{HEALTH_CHECK_URI}" }; var regInfo = new AgentServiceRegistration() { Checks = new[] { healthCheck }, Address = ipv4, ID = serviceId, Name = clientConfig.ClientName, Port = clientIP.Port }; consulClient.Agent.ServiceRegister(regInfo).GetAwaiter().GetResult(); lifetime.ApplicationStopped.Register(() => { consulClient.Agent.ServiceRegister(regInfo); }); return app; } /// <summary> /// 实现健康检查输出,无需另行定义 Controller /// </summary> /// <param name="app"></param> /// <returns></returns> public static IApplicationBuilder MapHealthCheck(this IApplicationBuilder app) { app.Map(HEALTH_CHECK_URI, s => { s.Run(async context => { Console.ForegroundColor = ConsoleColor.Blue; Console.WriteLine("Health check {0}", DateTime.Now); Console.ForegroundColor = ConsoleColor.Gray; await context.Response.WriteAsync("ok"); }); }); return app; } }
上面的代码,实现是服务注册和健康检查的逻辑,代码比较简单,每一个方法头部都有注释,应该仍是比较清晰,这里就再也不过多解释了,接下来开始在 Startup.cs 中启用 ConsulClient。负载均衡
public void ConfigureServices(IServiceCollection services) { services.AddConsulConfig(this.Configuration); ... }
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime lifetime, IOptions<ConsulConfig> cc) { app.UseConsul(this.Configuration, lifetime, cc); app.MapHealthCheck(); ... }
下面简单的实现一个 Controller,在该 Controller 里面增长两个业务接口,方便调用就好async
[HttpGet("index")] public ActionResult<string> Index() { return "Hello wrold"; } [HttpGet("add/{x:int}/{y:int}")] public ActionResult<int> Add(int x, int y) { var result = x + y; Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("x+y={0}", result); Console.ForegroundColor = ConsoleColor.Gray; return result; }
好了,到这里,服务注册的准备工做基本完成,接下来,按 F5 启动程序,程序将自动进行服务注册等工做学习
图中蓝色部分,就是 Consul 代理服务器集群对当前服务执行的健康检查,健康检查的原则只有一条,执行 http 请求,并返回 httpstatus=200 即视为健康,打开 Consul 的 Web 控制台界面,查看实际的服务状态
从上图中能够看到,服务状态是正常的(绿色)
Consul 系统了许多 api 接口,供服务网关(或者代理)从 Consul 中获取已注册的健康的服务,好比下面的 api 地址
http://172.16.1.218:8500/v1/agent/services
http://172.16.1.218:8500/v1/agent/service/node-1-172.16.10.227-51800
上图中的内容,就是单个服务的注册信息,图中红色部分,是真实的服务的主机地址和侦听的端口,网关代理能够将指定路由转发到该地址实现业务调用。
截止目前为止,咱们实现了部署 Consul 代理服务器集群、服务注册、发现,可是目前来讲,尚未彻底实现业务调用,如今,还缺乏关键的一环:那就是服务网关;服务网关的调用,咱们放在下一篇
本示例全部代码都已托管到 Github,欢迎下载:https://github.com/lianggx/Examples/tree/master/Ron.Consul