《ASP.NET Core 微服務實戰》-- 讀書筆記(第8章)

第 8 章 服務發現

面對大量服務,爲了簡化配置和管理工做,咱們須要瞭解」服務發現「概念git

回顧雲原生特性

配置外置

將 URL 和登陸憑證移到配置文件和 C# 代碼以外,放到環境變量中github

這樣能讓代碼運行所需的配置參數更明確,而把提供這些配置的責任交給運行環境spring

後端服務

無論程序須要的是二進制存儲、數據庫、另外一個服務、隊列服務,仍是其餘類型的依賴,這些設施都應該鬆耦合,並能從環境變量中配置docker

把資源綁定爲後端服務有兩種方式:靜態綁定和動態綁定數據庫

靜態綁定指的是,不管是由自動化工具仍是由 DevOps 工程師來分配,服務與資源之間的綁定過程發生在應用啓動期間,並且一經綁定,即再也不變化json

動態綁定指資源的綁定過程發生在運行期間,具體來講,綁定關係並不固定,並能在應用收到的多個請求期間發生變化後端

另外,爲避免給應用開發人員增長額外的複雜性,它也要支持鬆耦合api

Netflix Eureka 簡介

GitHub連接:https://github.com/Netflix/eureka服務器

要實現運行時的服務發現,須要用到」服務註冊表「設施--一種集中式的服務目錄app

Netflix 基礎設施主要運行在 Amazon 雲服務上

Netflix 自行開發了用於管理服務註冊的產品 Eureka,它提供故障轉移和負載均衡能力

從一名開發人員的角度看,微服務與 Eureka 服務器的交互方式就是在啓動時註冊

若是須要發現並消費其餘後端服務,可從 Eureka 服務器查找服務目錄

微服務還會向 Eureka 服務以必定的時間間隔發送心跳

若是服務在必定時間裏沒有發送心跳,就會從服務註冊表中移除

在服務註冊和發現領域, Eureka 也不是惟一的選擇

從純粹的服務註冊工具到具備完整註冊、發現和容錯功能的產品,有不少其餘公司和產品可供選用

  • etcd:一個底層的分佈式鍵值存儲,提供 HTTP 訪問
  • Consul:一個功能完備的服務發現工具,也提供用於支持配置功能的鍵值存儲
  • Marathon:Mesos 和 DC/OS 上一個至關成熟的容器編排系統
  • ZooKeeper:源自 Hadoop 項目,是這一體系中最悠久的產品

若是想體驗 Eureka,但不想從源代碼編譯,也不想把它完整地安裝到服務器上,你能夠直接使用 docker hub 鏡像來運行它,命令行以下:

$ docker run -p 8080:8080 --name eureka \
-d netflixoss/eureka:1.3.1

發現和廣播 ASP.NET Core 服務

如今分析一些與 Eureka 服務交互的示例代碼

在下面的虛構示例中,將開發一套用於支持電子商務的服務

最終的服務將公開一個產品目錄,這個目錄提供標準的 API 端點,用於訪問產品列表和詳細信息

此外,有一個庫存服務,負責提供物理庫存的實時狀態

當須要展現產品詳細信息時,產品服務將須要調用庫存服務獲取數據,用於組裝最終的完整數據

服務註冊

咱們示例項目的第一部分是庫存服務,它須要在運行期間動態地被其餘服務發現,以提供實時庫存狀態

GitHub連接:https://github.com/microservices-aspnetcore/ecommerce-inventory

使用 .NET Core 配置系統向 Steeltoe 類庫提供一些配置信息

appsettings.json

{
    "spring": {
        "application": {
            "name": "inventory"
        }
    },
    "eureka": {
        "client": {
            "serviceUrl": "http://localhost:8080/eureka/",
            "shouldRegisterWithEureka": true,
            "shouldFetchRegistry": false,
            "validate_certificates": false
        },
        "instance": {
            "port": 5000
        }
    },
}

咱們用慣常的方式裝配好配置,確保加載了保存着服務發現客戶端配置信息的 appsettings.json 文件

var builder = new ConfigurationBuilder()
    .SetBasePath(System.IO.Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);

Configuration = builder.Build();

在 Startup 類的 ConfigureService 方法裏調用 Steeltoe 的 AddDiscoveryClient 擴展方法

services.AddDiscoveryClient(Configuration);

最後,只須要在 Configure 方法中添加對 UseDiscoveryClient 方法的調用

app.UseDiscoveryClient();
發現並消費服務

有一個可供發現的服務以後,咱們把注意力轉到要開發的下一個服務上:目錄服務

這個服務提供產品的目錄,並經過查詢庫存服務來補充產品的詳細信息

這一服務與咱們開發過的其餘服務之間最重要的區別是,它會在運行期間動態地發現庫存服務

GitHub連接:https://github.com/microservices-aspnetcore/ecommerce-catalog

用與配置庫存服務時幾乎同樣的方式配置客戶端

appsettings.json

{
 "spring": {
    "application": {
      "name": "catalog"
    }
  },    
  "eureka":{  
    "client":{  
      "serviceUrl":"http://localhost:8080/eureka/",
      "shouldRegisterWithEureka":false
    }
  }
}

區別在於目錄服務不須要被註冊(由於它不須要被其餘服務發現),只有獲取註冊表才能發現庫存服務

請看 HttpInventoryClient 類的代碼,它負責消費庫存服務

using StatlerWaldorfCorp.EcommerceCatalog.Models;
using Steeltoe.Discovery.Client;
using System.Threading.Tasks;
using System.Net.Http;
using Newtonsoft.Json;

namespace StatlerWaldorfCorp.EcommerceCatalog.InventoryClient
{
    public class HttpInventoryClient : IInventoryClient
    {
        private DiscoveryHttpClientHandler handler;
        private const string STOCKSERVICE_URL_BASE = "http://inventory/api/skustatus/";

        public HttpInventoryClient(IDiscoveryClient client)
        {
            this.handler = new DiscoveryHttpClientHandler(client);
        }


        private HttpClient CreateHttpClient()
        {
            return new HttpClient(this.handler, false);
        }

        public async Task<StockStatus> GetStockStatusAsync(int sku)
        {
            StockStatus stockStatus = null;

            using (HttpClient client = this.CreateHttpClient())
            {
                var result = await client.GetStringAsync(STOCKSERVICE_URL_BASE + sku.ToString());
                stockStatus = JsonConvert.DeserializeObject<StockStatus>(result);
            }

            return stockStatus;
        }
    }
}

.NET Core 的 HttpClient 類的構造函數有一個重載,容許傳入一個自定義的 HttpHandler 實例

由 Steeltoe 提供的 DiscoveryHttpClientHandler 負責把 URL 中的服務名稱替換成在運行期間發現的 URL

執行以下步驟,可在電腦上同時運行庫存服務、目錄服務和 Eureka

首先,啓動 Eureka 服務

$ docker run -p 8080:8080 -d --name eureka \
-d netflixoss/eureka:1.3.1

而後在 5001 端口運行庫存服務

$ cd <inventory service>
$ dotnet run --service.urls=http://0.0.0.0:5001

要在 Docker 中運行服務,請使用下面的 docker run 命令:

$ docker run -p 5001:5001 -e PORT=5001 \
-e EURKEA__CLIENT__SERVICEURL=http://192.168.0.33:8080/eureka/ \
dotnetcoreservices/ecommerce-inventory

若是要在這裏覆蓋配置的值,請確保使用本機的地址

在 Docker 鏡像中運行時,指向 localhost 就會有問題

最後,在 5002 端口啓動目錄服務

$ cd <目錄服務>
$ dotnet run --service.urls=http://0.0.0.0:5002

如今,能夠向產品目錄服務 API 發送一些請求,獲取產品的列表和詳情

GET http://localhost:5002/api/products
GET http://localhost:5002/api/products/{id}

獲取產品詳情信息,期間將調用庫存服務,它的 URL 是經過 Eureka 動態發現的

DNS 以及由平臺支持的服務發現

在我看來,服務發現、註冊,以及失敗檢測都應該是非功能需求

也就是說,應用代碼的任何部分都不該該緊耦合特定服務發現的實現

顯然,仍是要優先考慮現實情況,務實地作出決策,並且最終決定還要由你本身來作

<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="知識共享許可協議" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a>

本做品採用<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議</a>進行許可。

歡迎轉載、使用、從新發布,但務必保留文章署名 鄭子銘 (包含連接: http://www.cnblogs.com/MingsonZheng/ ),不得用於商業目的,基於本文修改後的做品務必以相同的許可發佈。

若有任何疑問,請與我聯繫 (MingsonZheng@outlook.com) 。

相關文章
相關標籤/搜索