通過上一篇的學習,如今已經來到了服務註冊發現環節;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