.net core consul 服務配置 服務發現 服務健康檢測 服務變更加載


准備環境

 安裝consul之后

1. 創建一個.net core webapi 舉例為UsercenterService

2. nuget引用Consul組件  https://github.com/PlayFab/consuldotnet

3. 創建配置實體類 (后面涉及功能介紹時候再解釋屬性含義)

 1     public class AppSettings
 2     {
 3         /// <summary>
 4         /// 數據庫連接字符串
 5         /// </summary>
 6         public string DbConnection { get; set; }
 7 
 8         /// <summary>
 9         /// 服務注冊參數
10         /// </summary>
11         public ServiceRegisterOptions ServiceRegisterOptions { get; set; }
12     }
13 
14     public class ServiceRegisterOptions
15     {
16         /// <summary>
17         /// 是否啟用
18         /// </summary>
19         public bool IsActive { get; set; }
20         /// <summary>
21         /// 服務名稱
22         /// </summary>
23         public string ServiceName { get; set; }
24         /// <summary>
25         /// 服務IP或者域名
26         /// </summary>
27         public string ServiceHost { get; set; }
28         /// <summary>
29         /// 服務端口號
30         /// </summary>
31         public int ServicePort { get; set; }
32         /// <summary>
33         /// consul注冊地址
34         /// </summary>
35         public string ConsulRegisterUrl { get; set; }
36         /// <summary>
37         /// 標簽 例如laiwutest
38         /// </summary>
39         public string[] Tags { get; set; }
40     }
View Code

4. appsettings配置consul服務地址和UserService配置在consul的節點key

  4.1 配置consul地址(舉例是在VS調試開發環境。所以在appsettings.Development.json中配置) 

1 {
2   "ConsulForConfig": {
3     "Host": "{IP}:8500",//這里替換成自己consul服務的IP地址
4     "Prefix": "git-dev/huangqiang/usercenterRegionIIS.json"
5   }
6 }
View Code

       4.2 在consul上創建該節點並且配置

 1 {
 2     "DbConnection": "111111111111111111111111111111111111111",
 3     "ServiceRegisterOptions":
 4     {
 5         "IsActive":true,
 6         "ServiceName":"UserCenterRegion",
 7         "ServiceHost":"{IP}",//修改{IP}為你注入的服務的ip地址
 8         "ServicePort":"{Port}",//修改{Port}為你注入的服務的端口
 9         "ConsulRegisterUrl":"{IP}:8500",//修改{IP}為你的consul服務的IP
10         "Tags":["浙江杭州"]
11     },
12 }
View Code

   


獲取配置  

 1   public static AppSettings AddAppSettingByConsul(this IServiceCollection sc, IConfiguration configuration)
 2         {
 3             try
 4             {
 5                 //get local consul service address configration consulclient
 6                 var consulAddress = $"http://" + configuration["ConsulForConfig:Host"];
 7                 var key = configuration["ConsulForConfig:Prefix"];
 8                 if (string.IsNullOrWhiteSpace(consulAddress) || string.IsNullOrWhiteSpace(key))
 9                 {
10                     throw new Exception("無法獲取consulAddress地址或者consul key");
11                 }
12                 var consulClient = new ConsulClient(cfg => { cfg.Address = new Uri(consulAddress); });
13                 sc.AddSingleton<IConsulClient>(p => consulClient);
14                 //get app config
15                 var res = consulClient.KV.Get(key).GetAwaiter().GetResult();
16                 var resStr = Encoding.UTF8.GetString(res.Response.Value);
17                 var appSettings = JsonConvert.DeserializeObject<AppSettings>(resStr);
18                 if (appSettings == null)
19                 {
20                     throw new Exception($"appSettings 為null,consul 配置:{resStr}");
21                 }
22                 sc.AddSingleton<AppSettings>(appSettings);
23                 return appSettings;
24             }
25             catch (Exception e)
26             {
27                 _log.Main.Error($"獲取consul appsettings配置異常:{e.Message}");
28                 Environment.Exit(-1);
29             }
30             return null;
31         }
View Code

這里抽了一個擴展方法。使用的時候在Startup.cs類中的方法ConfigureServices中加入,這里弄了返回值只是偷懶下。

AddAppSettingByConsul方法邏輯:先是拿到配置的consull服務地址和Key,再通過前面nuget引用的consul組件中的consulclient獲取配置,最后注入到容器

調試下 就拿到配置了。這樣方便分布式服務,不用每台都配置,直接consul管理

 


 

 

配置健康檢測和服務注冊

 准備健康檢測接口:

1     [Route("api/v1/[controller]")]
2     [ApiController]
3     public class HealthController : ControllerBase
4     {
5         [HttpGet]
6         public IActionResult Get() => Ok("ok");
7     }
View Code

.net core 配置注冊和健康檢測的地址

 1  public static void UseConsul(this IApplicationBuilder app, IApplicationLifetime appLife)
 2         {
 3             try
 4             {
 5                 var appSettings = app.ApplicationServices.GetService<AppSettings>();
 6                 var consulClient = app.ApplicationServices.GetService<IConsulClient>();
 7 
 8                 //config consul health check
 9                 var healthCheck = new AgentServiceCheck
10                 {
11                     DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),
12                     Interval = TimeSpan.FromSeconds(30),
13                     HTTP = $"{appSettings.ServiceRegisterOptions.ServiceHost}:{appSettings.ServiceRegisterOptions.ServicePort}/api/v1/Health",
14                 };
15 
16                 //service register
17                 var serviceId = $"{appSettings.ServiceRegisterOptions.ServiceName}_{appSettings.ServiceRegisterOptions.ServiceHost}:{appSettings.ServiceRegisterOptions.ServicePort}";
18                 var registration = new AgentServiceRegistration
19                 {
20                     Checks = new[] { healthCheck },
21                     Address = appSettings.ServiceRegisterOptions.ServiceHost,
22                     Port = appSettings.ServiceRegisterOptions.ServicePort,
23                     ID = serviceId,
24                     Name = appSettings.ServiceRegisterOptions.ServiceName,
25                     Tags = appSettings.ServiceRegisterOptions.Tags
26                 };
27                 consulClient.Agent.ServiceRegister(registration).GetAwaiter().GetResult();
28 
29                 //service Deregister when app stop
30                 appLife.ApplicationStopped.Register(() =>
31                 {
32                     consulClient.Agent.ServiceDeregister(serviceId).GetAwaiter().GetResult();
33                 });
34 
35 
36             }
37             catch (Exception e)
38             {
39                 _logger.Main.Error($"UseConsul error:{e.Message}");
40                 Environment.Exit(-1);
41             }
42 
43         }
View Code

 

這里也是抽了個擴展方法。調用放到Startup

 

UseConsul方法解釋:先是從容器中拿到前面注入的配置實體AppSettings和ConsulClient。再配置健康檢測,再配置服務注冊,再配置當服務關閉時候注銷服務。

其中健康檢測的DeregisterCriticalServiceAfter表示如果服務啟動失敗,多少時間內注銷consul上的該服務。

服務注冊的參數就不介紹了

然后跑起來之后,到consul ui瞧一瞧。是不是注冊成功,心跳正常

狀態為passing為正常的,剛啟動時候狀態會為critical。 當你的狀態一直為critical時候,過了前面DeregisterCriticalServiceAfter的時間,服務將會注銷,也就是注冊失敗。可能原因:服務地址配置有問題,consul無法訪問你的health地址,也可能你的端口沒打開。telnet看看

 

當都成功的時候,服務已經正常注冊到consul。下面再說說服務發現和服務變更發現


 

 

服務發現和服務變更發現

服務發現調用的方法有很多,agent,catalog,health,都可以獲取列表。但是agent是查詢本地自己的,catalog是整個集群的,heath是查詢健康的。這里用health獲取舉例

關鍵就一句話:_consulClient.Health.Service(serviceName, tag, true, queryOptions).Result。

這樣就能獲取到注冊到consul的服務列表了,但是如果有服務變更了(新的服務注冊,舊的服務停止),應該怎么辦?

一般想到啟動一個線程不停的去拿,是沒有問題,但是有個更好的東西,“Blocking Queries”  https://www.consul.io/api/index.html

這個東西簡單來說就是會記錄一個版本,consul服務端通過這個版本來判斷是不是已經是最新的服務列表,如果是的話,那么將會阻塞一定時間(這個時間可配置)

在c# 里面體現就是第三個參數queryOptions的WaitIndex和WaitTime,以及返回LastIndex,下面po出一部分代碼。

        public void GetAllService()
        {
            _serviceIndexList.ForEach(p =>
            {
                Task.Run(() =>
                {
                    var queryOptions = new QueryOptions { WaitTime = TimeSpan.FromSeconds(_waitTime) };
                    while (true)
                    {
                        GetAgentServices(queryOptions, p.ServiceName, p.Tag);
                    }
                });
            });
        }

        public void GetAgentServices(QueryOptions queryOptions, string serviceName, string tag = null)
        {
            try
            {
                var res = _consulClient.Health.Service(serviceName, tag, true, queryOptions).Result;
                _logger.Main.Info($"GetServiceList:{serviceName} {tag} waitIndex:{res.LastIndex}");
                if (queryOptions.WaitIndex != res.LastIndex)
                {
                    queryOptions.WaitIndex = res.LastIndex;
                    var currentService = _consulServices.FirstOrDefault(p => p.ServiceName == serviceName);
                    if (currentService == null)
                    {
                        _consulServices.Add(new ConsulService
                        {
                            ServiceName = serviceName,
                            Tag = tag,
                            ServiceEntries = new ConcurrentBag<ServiceEntry>(res.Response)
                        });
                    }
                    else
                    {
                        currentService.ServiceEntries = new ConcurrentBag<ServiceEntry>(res.Response);
                    }
                }
            }
            catch (AggregateException ae)
            {
                _logger.Main.Error($"consul獲取{serviceName},{tag}服務列表資源錯誤:{ae.Flatten()}",ae);
            }
            catch (Exception e)
            {
                _logger.Main.Error($"consul獲取{serviceName},{tag}服務列表資源錯誤",e);
            }
        }
View Code

注:代碼中的_serviceIndexList是存着需要獲取哪些服務的服務tag,_consulServices是程序維護的最新服務列表

 


免責聲明!

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



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