Consul初探-服務注冊和發現


前言

經過上一篇的學習,現在已經來到了服務注冊發現環節;Consul 的核心功能就是服務注冊和發現,Consul 客戶端通過將自己注冊到 Consul 服務器集群,然后等待調用方去發現服務,實現代理轉發到真正的業務系統,還可以基於服務發現做負載均衡,甚至可以在客戶端請求到底服務之前進行攔截,做一些基礎性的工作,比如身份驗證、限流、熔斷等等業務系統的前瞻性工作。

服務注冊

引用 Consul.net 客戶端

在 .NETCore 平台下,可以使用 Consul 的客戶端組件,使其嵌入到業務系統中,完成服務自動注冊、健康檢查等工作,為了使用這些自動化的功能,需要在項目中進行 nuget 包引用

截止本文發文時,Consul 的 NETStandard 最新版本是 0.7.2.6,從版本號來看,更新的頻率非常頻繁,但是 Github 上的 star 數量並不多,這就表示 .NETCore 社區在 Consul 的關注度上還是非常小眾的。

改造 Program.cs 程序入口

為了使用服務運行時偵聽的地址和端口作為 Consul 健康檢查的地址,需要對 Program.cs 進行簡單的改造,代碼如下:

        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 文件中,如下圖

在 launchSettings.json 文件中的表現形式為:

{
  "profiles": {
    "Ron.Consul": {
      "commandName": "Project",
      "commandLineArgs": "--scheme http --ip 172.16.10.227 --port 51800"
    }
  }
}
建立 StartupExtension.cs

我們需要在服務啟動后,將服務自動注冊到 Consul 的代理服務器集群中,為此,需要封裝一些簡單的注冊代碼,以便復用

 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 里面增加兩個業務接口,方便調用就好

        [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


免責聲明!

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



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