一、什麼是consul?
首先我們來了解什麼是consul,consul是服務註冊與發現的一種常用工具之一,翻閲了網上的部分資料,指把服務地址註冊到consul,然後在consul中讀取來消費;但在我的理解中,consul的作用是服務治理,屬於可以橫向伸縮的註冊中心;為什麼這麼説呢?在以前我們用Nginx做負載時,需要把服務地址一個個手動集成進去的,如果服務多了會有什麼問題呢?1.需要新增一個服務,必須要重新配置Nginx然後重啓;2.感知不了哪個服務停止了;3.如果某個服務停止了,無法自動創建新的服務代替;因為微服務其中一個特點是基礎設施自動化,所以明顯Nginx滿足不了需求,那麼服務註冊與發現就橫空而生了(除了consul外還可以使用etcd,K8S Services等)。
二、consul有幾大核心功能:
1.服務註冊
其他客户端可以使用 Consul 發現給定服務的提供者。使用 DNS 或 HTTP,應用程序可以輕鬆找到它們所依賴的服務(它是通過代理註冊的方式註冊到註冊中心,提供業務代碼的解耦)
2.健康檢查
其實就是在程序中,建立一個接口,只返回狀態使用,consul通過這個接口來檢查服務是否健康,如果不健康,則通過策略去移除
3.多個數據中心
其實就是支持集羣,通過3個,或5個的單數服務端的consul來支持高可用(因為單數更適合做選舉算法,如果數量太多又影響性能,所以這是官網標配);
4.安全服務通信
Consul 可以為服務生成和分發 TLS 證書以建立相互 TLS 連接
consul工作流程圖:
三、consul安裝
安裝分2種,一種是二進制,以命令行的形式安裝;一種是以exe文件免安裝的形式;
四、consul運行問題
運行時,最可能出現的問題就是端口占用,可新增文件,修改文件端口號,然後執行命令即可,百度上很多解決,請自行搜索命令
五、net6的代碼實現
1.服務註冊代碼,目的是把當前服務推送到consul,並且設置健康檢查
依賴組件
consul
1 public static class RegisterToConsul
2 {
3 /// <summary>
4 /// 把本服務註冊到Consul
5 /// </summary>
6 /// <param name="config">參數配置</param>
7 /// <param name="appLifetime">程序生命週期</param>
8 public static void RegToConsul(this IConfiguration config)
9 {
10 //Consul地址
11 var address= AppHelper.ReadAppSettings("Consul", "consulAddress");
12 var consulClient = new ConsulClient(p => { p.Address = new Uri(address); });
13
14 //本地IP
15 var localIP = AppHelper.ReadAppSettings("Consul", "currentIp");
16 //本地服務端口
17 var localPort = Convert.ToInt32(AppHelper.ReadAppSettings("Consul", "currentPort")); //端口號從命令行參數獲取(注:目前沒找到直接獲取本服務監聽的端口的方法)
18
19 //心跳檢測設置
20 var httpCheck = new AgentServiceCheck()
21 {
22 DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(60), //心跳檢測失敗多久後註銷
23 Interval = TimeSpan.FromSeconds(10), //間隔多久心跳檢測一次
24 HTTP = $"http://{localIP}:{localPort}/api/Health/Check", //心跳檢查地址,本服務提供的地址
25 Timeout = TimeSpan.FromSeconds(5) //心跳檢測超時時間
26 };
27
28 //服務名(這裏通過命令行參數傳入不同的服務名,模擬我們有不同的服務[其實只是同一個接口項目的不同運行實例])
29 var serviceName = AppHelper.ReadAppSettings("Consul", "serviceName");
30
31 //註冊信息
32 var registration = new AgentServiceRegistration()
33 {
34 ID = $"{localIP}:{localPort}", //服務ID,唯一
35 Name = serviceName, //服務名(如果服務搭集羣,它們的服務名應該是一樣的,但是ID不一樣)
36 Address = $"{localIP}", //服務地址
37 Port = localPort, //服務端口
38 Tags = new string[] { }, //服務標籤,一般可以用來設置權重等本地服務特有信息
39 Checks = new[] { httpCheck }, //心跳檢測設置
40 };
41
42 //向Consul註冊服務
43 consulClient.Agent.ServiceRegister(registration).Wait();
44
45 }
46 }
1 "Consul": {
2
3 "consulAddress": "http://127.0.0.1:8500",
4
5 "serviceName": "Consultest",
6
7 "currentIp": "127.0.0.1",
8
9 "currentPort": "5247"
10
11 }
appseting設置
1 public class AppHelper
2 {
3 private static IConfiguration _config;
4
5 public AppHelper(IConfiguration configuration)
6 {
7 _config = configuration;
8 }
9
10 /// <summary>
11 /// 讀取指定節點的字符串
12 /// </summary>
13 /// <param name="sessions"></param>
14 /// <returns></returns>
15 public static string ReadAppSettings(params string[] sessions)
16 {
17 try
18 {
19 if (sessions.Any())
20 {
21 return _config[string.Join(":", sessions)];
22 }
23 }
24 catch
25 {
26 return "";
27 }
28 return "";
29 }
30
31 /// <summary>
32 /// 讀取實體信息
33 /// </summary>
34 /// <typeparam name="T"></typeparam>
35 /// <param name="session"></param>
36 /// <returns></returns>
37 public static List<T> ReadAppSettings<T>(params string[] session)
38 {
39 List<T> list = new List<T>();
40 _config.Bind(string.Join(":", session), list);
41 return list;
42 }
43 }
獲取appsetting文件類
1 [Route("api/[controller]")]
2 [ApiController]
3 public class HealthController : ControllerBase
4 {
5 [HttpGet]
6 [Route("Check")]
7 public IActionResult Check()
8 {
9 return Ok();
10 }
11 }
心跳代碼
2.服務發現代碼,目的是通過調用consul註冊中心的服務
1 private static int index = 0;
2 [HttpGet]
3 [Route("Contents")]
4 public IActionResult Contents()
5 {
6 string url = $"http://{AppHelper.ReadAppSettings("Consul", "serviceName")}/api/values";
7 ConsulClient client = new ConsulClient(c=>
8 {
9 c.Address = new Uri(AppHelper.ReadAppSettings("Consul", "consulAddress"));
10 }
11 );
12 var res = client.Agent.Services().Result.Response;
13 Uri uris = new Uri(url);
14 string groupname = uris.Host;
15 var dic = res.Where(s => s.Value.Service.Equals(groupname, StringComparison.OrdinalIgnoreCase)).ToArray();
16 //輪詢讀取
17 return Content(Newtonsoft.Json.JsonConvert.SerializeObject(dic[index++ % dic.Length].Value));
18 }
服務發現代碼
六、Consul集羣,做集羣測試
七、拓展點
上面的服務發現讀取上,當單個服務達到瓶頸了,這時候我們就要負載均衡來分擔服務器的壓力,那麼我們下一節來講Consul如何進行負載均衡