練習活動 - 將單體架構中的服務重構為微服務

已完成

現在 Fabrikam 已完成分析其應用程式,他們已準備好開始重構程式,將服務從整合型架構移出微服務。 讓我們修改應用程式,將封裝處理服務移至微服務。

無人機遞送應用程式資源的視覺效果。

重構應用程式

在部署更新的應用程式之前,讓我們來看看其更新方式。 整合型應用程式具有可處理套件的服務, PackageProcessor.cs。 分析應用程式效能之後,此服務會識別為效能瓶頸。 隨著客戶增加無人機交付的需求,這項服務在處理無人機交付的排程和物流時會變得負載繁重。 專用小組會完全管理這項服務,因此將其移至微服務有助於效能,並提供改良的開發靈活性。

讓我們進一步瞭解所做的變更。

無人機遞送之前

類別 PackageProcessor 會處理 PackageProcessor.cs 檔案中封裝處理的核心功能。 在此範例中,它會執行一些需要大量資源的工作。 實際案例可能包括計算傳遞時間和傳遞路由,以及使用這項資訊更新數據源。

public class PackageProcessor : IPackageProcessor
    {
        public Task<PackageGen> CreatePackageAsync(PackageInfo packageInfo)
        {
            //Uses common data store e.g. SQL Azure tables
            Utility.DoWork(100);
            return Task.FromResult(new PackageGen { Id = packageInfo.PackageId });
        }
    }

當此服務的要求增加時,資源使用率會增加,並限製為配置給整合型應用程式的實體資源。 如果此服務部署在 Azure App Service 上,我們可以相應增加和相應放大。在理想情況下,您希望此大量使用的資源獨立調整,以將效能和成本優化。 在此案例中,我們會使用 Azure Functions 來執行此動作。

無人機交付之後

讓我們先看看 DroneDelivery之後 的應用程式程式代碼,再進行部署。 您可以看到類別 PackageProcessor 已變更為 類別 PackageServiceCaller 。 它仍然會實作 IPackageProcessor 介面,但會改為對微服務進行 HTTP 呼叫。

public class PackageServiceCaller : IPackageProcessor
    {
        private readonly HttpClient httpClient;

        public static string FunctionCode { get; set; }

        public PackageServiceCaller(HttpClient httpClient)
        {
            this.httpClient = httpClient;
        }

        public async Task<PackageGen> CreatePackageAsync(PackageInfo packageInfo)
        {
            var result = await httpClient.PutAsJsonAsync($"{packageInfo.PackageId}?code={FunctionCode}", packageInfo);
            result.EnsureSuccessStatusCode();

            return new PackageGen { Id = packageInfo.PackageId };
        }
    }

微服務會部署在 Azure 函式上。 其程式代碼可在 PackageServiceFunction.cs 中找到,並包含下列程序代碼。

public static class PackageServiceFunction
    {
        [FunctionName("PackageServiceFunction")]
        public static Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "put", Route = "packages/{id}")] HttpRequest req,
            string id, ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            //Uses common data store e.g. SQL Azure tables
            Utility.DoWork(100);
            return Task.FromResult((IActionResult)new CreatedResult("http://example.com", null));
        }
    }

當您將此程式代碼放在 Azure Functions 上時,此服務可以在用戶負載增加時獨立調整。 您可以保留針對其餘應用程式優化之應用程式程式碼的服務。 隨著無人機交付的更多要求傳入系統,封裝服務會相應放大。

現在,讓我們重新部署應用程式。 首先,我們會在 Azure Functions 上部署重構的服務。 然後,我們會在App Service 上部署重構的應用程式,並將其指向函式。

部署函數應用程式

  1. 執行下列命令來設定指向我們的服務的環境變數。

    APPSERVICENAME="$(az webapp list \
                        --resource-group "<rgn>[sandbox resource group]</rgn>" \
                        --query '[].name' \
                        --output tsv)"
    FUNCTIONAPPNAME="$(az functionapp list \
                        --resource-group "<rgn>[sandbox resource group]</rgn>" \
                        --query '[].name' \
                        --output tsv)"
    
  2. 讓我們建置並壓縮函式應用程式的應用程式程序代碼。

    cd ~/mslearn-microservices-architecture/src/after
    dotnet build ./PackageService/PackageService.csproj -c Release
    cd PackageService/bin/Release/netcoreapp2.2
    zip -r PackageService.zip .
    
  3. 執行下列命令,將程式代碼推送至函式應用程式。

    az functionapp deployment source config-zip \
        --resource-group "<rgn>[sandbox resource group]</rgn>" \
        --name $FUNCTIONAPPNAME \
        --src PackageService.zip
    

部署更新的無人機遞送應用程式

既然我們的服務正在 Azure Functions 上執行,我們需要將無人機應用程式指向該函式應用程式。

  1. 我們必須先取得函式應用程式的存取碼,以便從應用程式成功呼叫它。 執行下列命令以擷取此程序代碼。 您會顯示函式應用程式名稱和程序代碼,以供後續步驟使用。

    RESOURCEGROUPID=$(az group show \
                        --resource-group "<rgn>[sandbox resource group]</rgn>" \
                        --query id \
                        --output tsv)
    FUNCTIONCODE=$(az rest \
                        --method post \
                        --query default \
                        --output tsv \
                        --uri "https://management.azure.com$RESOURCEGROUPID/providers/Microsoft.Web/sites/$FUNCTIONAPPNAME/functions/PackageServiceFunction/listKeys?api-version=2018-02-01")
    echo "FunctionName - $FUNCTIONAPPNAME"
    echo "FunctionCode - $FUNCTIONCODE"
    
  2. 在 Azure Cloud Shell 中,執行下列命令,在程式碼編輯器中開啟 appsettings.json

    cd ~/mslearn-microservices-architecture/src/after
    code ./DroneDelivery-after/appsettings.json
    
  3. 在程式代碼編輯器中,取代 值 PackageServiceUriPackageServiceFunctionCode。 在 中 PackageServiceUri,將 取代 <FunctionName> 為函式應用程式的名稱。

    PackageServiceFunctionCode中,將 取代 <FunctionCode> 為您擷取的函式程序代碼。 您的 appsettings.json 檔案看起來應該類似下列範例:

    {
        "Logging": {
        "LogLevel": {
            "Default": "Warning"
        }
        },
        "AllowedHosts": "*",
        "PackageServiceUri": "https://packageservicefunction-abc.azurewebsites.net/api/packages/",
        "PackageServiceFunctionCode": "SvrbiyhjXJUdTPXrkcUtY6bQaUf7OXQjWvnM0Gq63hFUhbH2vn6qYA=="
    }
    
  4. Ctrl+S 儲存盤案,然後按 Ctrl+Q 關閉程式代碼編輯器。

  5. 執行下列命令,將更新的應用程式部署至 App Service。

    zip -r DroneDelivery-after.zip . -x \*/obj/\* \*/bin/\*
    az webapp deploy \
        --resource-group "<rgn>[sandbox resource group]</rgn>" \
        --name $APPSERVICENAME \
        --src-path DroneDelivery-after.zip
    
  6. 重新部署網站后,重新整理您的頁面。 現在應該更新它。

    重新部署的無人機遞送網站的螢幕快照。

測試新架構的效能

既然資源限制服務已移至在 Azure Functions 上執行的微服務,讓我們看看這項變更如何影響應用程式效能。

  1. 在網站的首頁上,選取 [ 傳送要求]。 此動作會將來自整合型應用程式的要求提交至在 Azure 函式上執行的微服務。

  2. 第一次嘗試可能會提供與整合型應用程式類似的結果。 重新整理頁面,並在出現提示時重新提交要求。 執行此步驟數次,您應該會看到 1 秒內傳送的 100 則訊息

    移至微服務架構之後無人機遞送網站的效能螢幕快照。

啟動函式應用程式時,初始嘗試速度較慢。 啟動並執行之後,回應時間會比此程式代碼在整合型架構中執行時更好。

此架構現在幾乎可以無限地相應放大,同時仍提供相同的效能。 藉由將此應用程式程式代碼移至微服務,我們會將效能提升 5 到 10 倍。 由於 Fabrikam 有此服務的專用開發小組,因此也可以逐一查看此微服務,並實現提高靈活度和功能版本的優點。