上一篇【.Net Core微服務入門全紀錄(一)——項目搭建】講到要作到服務的靈活伸縮,那麼須要有一種機制來實現它,這個機制就是服務註冊與發現。固然這也並非必要的,若是你的服務實例不多,而且很穩定,那麼就沒有必要使用服務註冊與發現。html
有了服務註冊與發現,客戶端就不用再去配置各個服務實例的地址,改成從註冊中心統一獲取。
那註冊中心又是怎麼保證每一個地址的可用狀態呢,假如某個實例掛了怎麼辦呢?原則上掛掉的實例不該該被客戶端獲取到,因此就要提到:健康檢查 。git
常見註冊中心有 Consul、ZooKeeper、etcd、Eureka。github
Consul官網:https://www.consul.io/
Consul的主要功能有服務註冊與發現、健康檢查、K-V存儲、多數據中心等。docker
consul.exe agent -dev
首先Nuget安裝一下Consul:
這個類庫裏封裝了Consul的api操做,方便咱們直接使用。固然本身去寫http調用Consul的接口也不是不行。。。接口說明:https://www.consul.io/api-docsjson
改造一下訂單服務的代碼:
api
ConsulHelper.cs:瀏覽器
public static class ConsulHelper { /// <summary> /// 服務註冊到consul /// </summary> /// <param name="app"></param> /// <param name="lifetime"></param> public static IApplicationBuilder RegisterConsul(this IApplicationBuilder app, IConfiguration configuration, IHostApplicationLifetime lifetime) { var consulClient = new ConsulClient(c => { //consul地址 c.Address = new Uri(configuration["ConsulSetting:ConsulAddress"]); }); var registration = new AgentServiceRegistration() { ID = Guid.NewGuid().ToString(),//服務實例惟一標識 Name = configuration["ConsulSetting:ServiceName"],//服務名 Address = configuration["ConsulSetting:ServiceIP"], //服務IP Port = int.Parse(configuration["ConsulSetting:ServicePort"]),//服務端口 由於要運行多個實例,端口不能在appsettings.json裏配置,在docker容器運行時傳入 Check = new AgentServiceCheck() { DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服務啓動多久後註冊 Interval = TimeSpan.FromSeconds(10),//健康檢查時間間隔 HTTP = $"http://{configuration["ConsulSetting:ServiceIP"]}:{configuration["ConsulSetting:ServicePort"]}{configuration["ConsulSetting:ServiceHealthCheck"]}",//健康檢查地址 Timeout = TimeSpan.FromSeconds(5)//超時時間 } }; //服務註冊 consulClient.Agent.ServiceRegister(registration).Wait(); //應用程序終止時,取消註冊 lifetime.ApplicationStopping.Register(() => { consulClient.Agent.ServiceDeregister(registration.ID).Wait(); }); return app; } }
appsettings.json:服務器
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*", "ConsulSetting": { "ServiceName": "OrderService", "ServiceIP": "localhost", "ServiceHealthCheck": "/healthcheck", "ConsulAddress": "http://host.docker.internal:8500"//注意,docker容器內部沒法使用localhost訪問宿主機器,若是是控制檯啓動的話就用localhost } }
Startup.cs:app
public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllers(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime lifetime) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); //服務註冊 app.RegisterConsul(Configuration, lifetime); } }
OrdersController.cs:微服務
[Route("[controller]")] [ApiController] public class OrdersController : ControllerBase { private readonly ILogger<OrdersController> _logger; private readonly IConfiguration _configuration; public OrdersController(ILogger<OrdersController> logger, IConfiguration configuration) { _logger = logger; _configuration = configuration; } [HttpGet] public IActionResult Get() { string result = $"【訂單服務】{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}——" + $"{Request.HttpContext.Connection.LocalIpAddress}:{_configuration["ConsulSetting:ServicePort"]}"; return Ok(result); } }
HealthCheckController.cs:
[Route("[controller]")] [ApiController] public class HealthCheckController : ControllerBase { /// <summary> /// 健康檢查接口 /// </summary> /// <returns></returns> [HttpGet] public IActionResult Get() { return Ok(); } }
至此就完成了服務註冊,取消註冊,健康檢查等功能的代碼編寫。
繼續在docker中運行服務實例,不習慣docker的話用控制檯啓動也行。--ConsulSetting:ServicePort參數就是傳入容器的端口信息。
docker build -t orderapi:1.0 -f ./Order.API/Dockerfile . docker run -d -p 9060:80 --name orderservice orderapi:1.0 --ConsulSetting:ServicePort="9060" docker run -d -p 9061:80 --name orderservice1 orderapi:1.0 --ConsulSetting:ServicePort="9061" docker run -d -p 9062:80 --name orderservice2 orderapi:1.0 --ConsulSetting:ServicePort="9062" docker build -t productapi:1.0 -f ./Product.API/Dockerfile . docker run -d -p 9050:80 --name productservice productapi:1.0 --ConsulSetting:ServicePort="9050" docker run -d -p 9051:80 --name productservice1 productapi:1.0 --ConsulSetting:ServicePort="9051" docker run -d -p 9052:80 --name productservice2 productapi:1.0 --ConsulSetting:ServicePort="9052"
至此,6個服務器實例都已運行,而且成功註冊到Consul。
隨便中止2個服務:
能夠看到中止的服務已經在Consul中被移除。注意,這個是咱們中止程序時主動調用Consul移除的。
//應用程序終止時,取消註冊 lifetime.ApplicationStopping.Register(() => { consulClient.Agent.ServiceDeregister(registration.ID).Wait(); });
固然程序發生異常,健康檢查不能正確響應的話,Consul也會移除,有一點區別。
那麼註冊,發現,健康檢查功能都完成了,下一步就該考慮客戶端如何拿到這些服務實例的地址了。
代碼放在:https://github.com/xiajingren/NetCoreMicroserviceDemo
未完待續...