Consul是一個服務網格(微服務間的 TCP/IP,負責服務之間的網絡調用、限流、熔斷和監控)解決方案,它是一個一個分佈式的,高度可用的系統,並且開發使用都很簡便。它提供了一個功能齊全的控制平面,主要特色是:服務發現、健康檢查、鍵值存儲、安全服務通訊、多數據中心。除了 Consul 以外,還有 Eureka、Zookeeper 等相似軟件。web
咱們這裏是直接在Windows上開發,因此對應下載Windows
版本的。下載地址:瀏覽器
下載完成後實際就是consul.exe
,咱們在下載位置運行cmd命令網絡
consul agent -dev
而後咱們打開瀏覽器,輸入http://localhost:8500/app
能夠看到Consul已經啓動了,可是除了他本身外尚未其餘服務註冊進來。異步
咱們建立一個Api項目,好比訂單服務OrderService
。分佈式
安裝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的地址,因此咱們配置一下獲取配置。
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}"); }); }
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看一下,已經能夠看到OrderService
已經註冊好了。並且是有健康檢查的。
咱們建立一個控制檯程序,並安裝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也能夠看到。
咱們啓動下控制檯應用程序
能夠看到咱們註冊的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(); }