.NET Core + Consul:服務(wù)注冊與發(fā)現(xiàn)

Consul 介紹

在分布式架構(gòu)中,服務(wù)治理是必須面對(duì)的問題,如果缺乏簡單有效治理方案,各服務(wù)之間只能通過人肉配置的方式進(jìn)行服務(wù)關(guān)系管理,當(dāng)遇到服務(wù)關(guān)系變化時(shí),就會(huì)變得極其麻煩且容易出錯(cuò)。

Consul 是一個(gè)用來實(shí)現(xiàn)分布式系統(tǒng)服務(wù)發(fā)現(xiàn)與配置的開源工具。它內(nèi)置了服務(wù)注冊與發(fā)現(xiàn)框架、分布一致性協(xié)議實(shí)現(xiàn)、健康檢查、Key/Value存儲(chǔ)、多數(shù)據(jù)中心方案,不再需要依賴其他工具(比如 ZooKeeper 等),使用起來也較為簡單。

Consul 架構(gòu)

Consul 集群支持多數(shù)據(jù)中心,在上圖中有兩個(gè) DataCenter,他們通過 Internet 互聯(lián),為了提高通信效率,只有 Server 節(jié)點(diǎn)才加入跨數(shù)據(jù)中心的通信。在單個(gè)數(shù)據(jù)中心中,Consul 分為 Client 和 Server 兩種節(jié)點(diǎn)(所有的節(jié)點(diǎn)也被稱為 Agent),Server 節(jié)點(diǎn)保存數(shù)據(jù),Client 負(fù)責(zé)健康檢查及轉(zhuǎn)發(fā)數(shù)據(jù)請求到 Server,本身不保存注冊信息;Server 節(jié)點(diǎn)有一個(gè) Leader 和多個(gè) Follower,Leader 節(jié)點(diǎn)會(huì)將數(shù)據(jù)同步到 Follower,Server 節(jié)點(diǎn)的數(shù)量推薦是3個(gè)或者5個(gè),在 Leader 掛掉的時(shí)候會(huì)啟動(dòng)選舉機(jī)制產(chǎn)生一個(gè)新 Leader。

Consul 集群搭建

這里使用 Docker 搭建 3個(gè) Server 節(jié)點(diǎn) + 1 個(gè) Client 節(jié)點(diǎn),API 服務(wù)通過 Client 節(jié)點(diǎn)進(jìn)行服務(wù)注冊和發(fā)現(xiàn)。

從 Docker Hub 拉取 Consul 鏡像

docker pull consul

啟動(dòng) 3個(gè) Server 節(jié)點(diǎn) + 1 個(gè) Client 節(jié)點(diǎn)

docker-compose.yaml 如下:

version: '3'

services:
  cs1: 
    image: consul
    command: agent -server -client=0.0.0.0 -bootstrap-expect=3 -node=cs1 -data-dir=/data
    volumes:
      - /usr/local/docker/consul/data/cs1:/data
  cs2:
    image: consul
    command: agent -server -client=0.0.0.0 -retry-join=cs1 -node=cs2 -data-dir=/data
    volumes:
      - /usr/local/docker/consul/data/cs2:/data
    depends_on:
      - cs1
  cs3:
    image: consul
    command: agent -server -client=0.0.0.0 -retry-join=cs1 -node=cs3 -data-dir=/data
    volumes:
      - /usr/local/docker/consul/data/cs3:/data
    depends_on:
      - cs1
  cc1:
    image: consul
    command: agent -client=0.0.0.0 -retry-join=cs1 -ui -node=cc1 -data-dir=/data  
    ports:
      - 8500:8500
    volumes:
      - /usr/local/docker/consul/data/cc1:/data
    depends_on:
      - cs2
      - cs3

主要參數(shù)說明:

參數(shù)名 解釋
-server 設(shè)置為 Server 類型節(jié)點(diǎn),不加則為 Client 類型節(jié)點(diǎn)
-client 注冊或者查詢等一系列客戶端對(duì)它操作的IP,默認(rèn)是127.0.0.1
-bootstrap-expect 集群期望的 Server 節(jié)點(diǎn)數(shù),只有達(dá)到這個(gè)值才會(huì)選舉 Leader
-node 指定節(jié)點(diǎn)名稱
-data-dir 數(shù)據(jù)存放位置
-retry-join 指定要加入的節(jié)點(diǎn)地址(組建集群)
-ui 啟用 UI 界面

集群狀態(tài)

e002ca62ac24 為容器名稱,可通過 docker ps | grep consul 查看,選擇任意一個(gè)即可

查看節(jié)點(diǎn)狀態(tài)和類型
docker exec -t e002ca62ac24 consul members

當(dāng)前為3 個(gè) Server 類型節(jié)點(diǎn) ,1 個(gè) Client 類型節(jié)點(diǎn)。

查看 Server 節(jié)點(diǎn)類型
docker exec -t e002ca62ac24 consul operator raft list-peers

當(dāng)前為 cs1 為 leader,可以測試將 cs1 stop 觀察 leader 的重新選舉。

通過 http://192.168.124.9:8500 UI 界面查看 Consul 節(jié)點(diǎn)狀態(tài)如下:(192.168.124.9 是 consul 容器外部訪問 IP)

.NET Core 接入 Consul

  1. 創(chuàng)建 .NET Core WebAPI(3.1) 服務(wù) ServiceA(2個(gè)實(shí)例) 和 ServiceB

  2. NuGet 安裝 Consul

  3. 注冊到 Consul 的核心代碼如下(源碼下載):

    public static class ConsulBuilderExtensions
    {
      public static IApplicationBuilder RegisterConsul(this IApplicationBuilder app, IHostApplicationLifetime lifetime, ConsulOption consulOption)
      {
        var consulClient = new ConsulClient(x =>
        {
          x.Address = new Uri(consulOption.Address);
        });
    
        var registration = new AgentServiceRegistration()
        {
          ID = Guid.NewGuid().ToString(),
          Name = consulOption.ServiceName,// 服務(wù)名
          Address = consulOption.ServiceIP, // 服務(wù)綁定IP
          Port = consulOption.ServicePort, // 服務(wù)綁定端口
          Check = new AgentServiceCheck()
          {
            DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服務(wù)啟動(dòng)多久后注冊
            Interval = TimeSpan.FromSeconds(10),//健康檢查時(shí)間間隔
            HTTP = consulOption.ServiceHealthCheck,//健康檢查地址
            Timeout = TimeSpan.FromSeconds(5)
          }
        };
    
        // 服務(wù)注冊
        consulClient.Agent.ServiceRegister(registration).Wait();
    
        // 應(yīng)用程序終止時(shí),服務(wù)取消注冊
        lifetime.ApplicationStopping.Register(() =>
        {
          consulClient.Agent.ServiceDeregister(registration.ID).Wait();
        });
        return app;
      }
    }
    
  4. 添加配置如下:

    "Consul": {
      "ServiceName": "service-a",
      "ServiceIP": "192.168.124.11",   // 當(dāng)前服務(wù)訪問 IP
      "ServicePort": 8000,
      "ServiceHealthCheck": "http://192.168.124.11:8000/healthCheck",
      "Address": "http://192.168.124.9:8500"
    }
    
  5. 注冊成功結(jié)果如下:

  6. ServiceB 調(diào)用 ServiceA 接口

    ServiceB 通過 ConsulClient 進(jìn)行服務(wù)發(fā)現(xiàn),獲取到 ServiceA 的地址,然后隨機(jī)請求請求任意一個(gè)實(shí)例,關(guān)鍵代碼如下:

    using (var consulClient = new ConsulClient(a => a.Address = new Uri(_consulOption.Address)))
    {
      var services = consulClient.Catalog.Service("service-a").Result.Response;
      if (services != null && services.Any())
      {
        // 模擬隨機(jī)一臺(tái)進(jìn)行請求,這里只是測試,可以選擇合適的負(fù)載均衡框架
        var service = services.ElementAt(new Random().Next(services.Count()));
    
        var client = _httpClientFactory.CreateClient();
        var response = await client.GetAsync($"http://{service.ServiceAddress}:{service.ServicePort}/test/get");
        var result = await response.Content.ReadAsStringAsync();
        return result;
      }
    }
    
  7. 多次調(diào)用結(jié)果如下:

參考鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容