Consul服務治理發現學習記錄


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

image-20200807102531448

然后我們打開瀏覽器,輸入http://localhost:8500/

image-20200807102643159

可以看到Consul已經啟動了,但是除了他自己外還沒有其他服務注冊進來。

服務注冊

我們創建一個Api項目,比如訂單服務OrderService

image-20200807103033654

安裝Consul

image-20200807172615740

健康檢查

創建完成后就是默認的項目結構,我們添加一個健康檢查的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

image-20200807173332007

打開Consul看一下,已經可以看到OrderService已經注冊好了。而且是有健康檢查的。

image-20200807173700185

服務消費

我們創建一個控制台程序,並安裝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也可以看到。

image-20200807174901894

image-20200807174817333

我們啟動下控制台應用程序

image-20200807175037168

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

image-20200810094937530


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM