练习 - 实现应用程序复原能力

已完成

eShop 项目有两个服务,这些服务使用 HTTP 请求相互通信。 Store 服务调用 Product 服务以获得当前可供购买的所有产品列表。

应用的当前版本没有复原处理。 Product如果服务不可用,该服务Store会向客户返回错误,并要求他们稍后重试。 此行为不是良好的用户体验。

你的经理要求你向应用添加复原能力,以便在 Store 服务失败时重试后端服务调用。

在本练习中,你将向现有云原生应用添加复原能力并测试修补程序。

开放开发环境

可以选择使用托管练习的 GitHub codespace,或者在 Visual Studio Code 中本地完成练习。

要使用 codespace,请使用此 Codespace 创建链接创建预配置的 GitHub Codespace

GitHub 需要几分钟才能创建和配置 codespace。 该过程完成后,你将看到练习的代码文件。 用于本模块其余部分的代码位于 /dotnet-resiliency 目录中。

要使用 Visual Studio Code,请将 https://github.com/MicrosoftDocs/mslearn-dotnet-cloudnative 存储库克隆到本地计算机。 然后:

  1. 安装任何 系统要求 以在 Visual Studio Code 中运行开发容器。
  2. 确保 Docker 正在运行。
  3. 在新的 Visual Studio Code 窗口中,打开克隆存储库的文件夹
  4. Ctrl+Shift+P 打开命令面板。
  5. 搜索:>开发容器:在容器中重新生成和重新打开
  6. 从下拉列表中选择 eShopLite - dotnet-resiliency 。 Visual Studio Code 将在本地创建你的开发容器。

生成并运行应用

  1. 在底部面板中,选择“ 终端 ”选项卡并运行以下命令,转到代码根目录:

    cd dotnet-resiliency
    
  2. 运行以下命令以生成 eShop 应用映像:

    dotnet publish /p:PublishProfile=DefaultContainer
    
  3. 生成完成后,运行以下命令以启动应用:

    docker compose up
    
  4. 在底部面板中,选择“端口”选项卡,然后在表的“转发地址”列中,选择前端(32000)端口的“在浏览器中打开”图标。

    如果在本地运行应用,请打开浏览器窗口以查看 http://localhost:32000/products

  5. eShop 应用应正在运行。 选择 “产品 ”菜单项,应会看到产品列表。

    显示浏览器中运行的 eShop 应用的屏幕截图。

测试当前复原能力

停止产品服务,以了解应用会发生什么情况。

  1. 返回到代码空间,然后在“ 终端 ”选项卡中选择 + 打开新的 bash 终端。

  2. 运行以下 docker 命令列出正在运行的容器:

    docker ps
    

    应会看到当前正在运行的容器的列表,例如:

    CONTAINER ID   IMAGE                                                                            COMMAND                  CREATED          STATUS          PORTS                                                        NAMES
    c08285e8aaa4   storeimage                                                                       "dotnet Store.dll"       8 minutes ago    Up 8 minutes    80/tcp, 443/tcp, 0.0.0.0:5902->8080/tcp, :::5902->8080/tcp   eshoplite-frontend-1
    6ba80f3c7ab0   productservice                                                                   "dotnet Products.dll"    8 minutes ago    Up 8 minutes    80/tcp, 443/tcp, 0.0.0.0:5200->8080/tcp, :::5200->8080/tcp   eshoplite-backend-1
    cd0c822a5222   vsc-eshoplite-958868d22c9851dd911b2423199bfc782861d1a8f7afac48e5096a1b7516082f   "/bin/sh -c 'echo Co…"   27 minutes ago   Up 27 minutes     
    
  3. 查找 productservice 容器的 ID。 在上面的示例中,ID 为 6ba80f3c7ab0

  4. 使用此 docker 命令停止产品服务:

    docker stop <CONTAINER ID>
    

    其中 <CONTAINER ID> 是您在上一步中找到的 ID。 例如:

    docker stop 6ba80f3c7ab0
    
  5. 返回到运行应用的浏览器选项卡并刷新页面。 应会看到一条错误消息:

    加载产品时出现问题。 请稍后重试。”

  6. 返回到代码空间,在 终端 中选择 docker 终端,然后按 Ctrl+C 停止应用。 应会看到:

    Gracefully stopping... (press Ctrl+C again to force)
    Aborting on container exit...
    [+] Stopping 2/1
     ✔ Container eshoplite-frontend-1  Stopped                                                                      0.3s 
     ✔ Container eshoplite-backend-1   Stopped                                                                      0.0s 
    canceled
    

向应用添加复原能力

使应用更具弹性的第一步是将 Microsoft.Extensions.Http.Resilience NuGet 包添加到项目。 然后,可以在 Program.cs使用它。

添加 Microsoft.Extensions.Http.Resilience 包

  1. 在 codespace 的 “终端 ”选项卡上,导航到 “应用商店 ”项目文件夹:

    cd Store
    
  2. 运行以下命令以添加复原 NuGet 包:

    dotnet add package Microsoft.Extensions.Http.Resilience
    

    从应用项目文件夹中的终端运行此命令会将包引用添加到 Store.csproj 项目文件。

  3. EXPLORER 边栏中,选择 Program.cs

  4. 在该文件的顶部,添加以下 using 语句:

    using Microsoft.Extensions.Http.Resilience;
    

添加标准复原策略

  1. 行 13 之前添加以下代码:

    .AddStandardResilienceHandler()
    

    代码应如下所示:

    builder.Services.AddHttpClient<ProductService>(c =>
    {
        var url = builder.Configuration["ProductEndpoint"] ?? throw new InvalidOperationException("ProductEndpoint is not set");
    
        c.BaseAddress = new(url);
    }).AddStandardResilienceHandler();
    

    上述代码将标准复原处理程序添加到 HTTPClient。 处理程序使用标准复原策略的所有默认设置。

    应用不需要其他代码更改。 让我们运行应用并测试复原能力。

  2. 运行以下命令以重新生成 eShop 应用:

    cd ..
    dotnet publish /p:PublishProfile=DefaultContainer
    
  3. 生成完成后,运行以下命令以启动应用:

    docker compose up
    
  4. 返回到运行应用的浏览器选项卡并刷新产品页面。 你应该能够看到产品列表。

  5. 返回到代码空间,然后在 “终端 ”选项卡中选择第二个 bash 终端。 复制 productservice 容器的容器 ID。

  6. 重新运行 docker stop 命令:

    docker stop <CONTAINER ID>
    
  7. 返回到运行应用的浏览器选项卡并刷新产品页面。 这一次,看到应用错误消息可能需要更长的时间。

    加载产品时遇到问题。 请稍后重试。”

    让我们检查日志,看看复原策略是否正常工作。

  8. 返回到代码空间,然后在 “终端 ”选项卡中选择 docker 终端。

  9. 在终端中,按 Ctrl+C 停止应用运行。

  10. 在日志消息中,向上滚动,直到找到对 Polly 的引用。

    eshoplite-frontend-1  | warn: Polly[3]
    eshoplite-frontend-1  |       Execution attempt. Source: 'ProductService-standard//Standard-Retry', Operation Key: '', Result: 'Name or service not known (backend:8080)', Handled: 'True', Attempt: '2', Execution Time: '27.2703'
    

    你应会看到许多与此类似的消息;其中每个消息都是一次重试尝试。 上述消息显示第二次尝试,以及执行所花费的时间。

配置复原策略

向应用添加复原能力时,需要快速响应用户,并且无需重载任何后端服务。 只有你可以决定默认选项是否满足你的业务需求。

在此示例中,你希望商店服务等待更长的时间,以便为商店服务提供恢复的机会。

  1. 在Program.cs的代码窗口中,将第 13 行的代码更改为:

    .AddStandardResilienceHandler(options =>
    {
        options.Retry.MaxRetryAttempts = 7;
    });
    

    上述代码将重试策略默认值更改为最大停用次数 7。 请记住,该策略是指数退避,因此总时间约为 5 分钟。

  2. 使用 Ctrl+C 停止 docker up 命令。 然后运行以下命令以重新生成 eShop 应用:

    dotnet publish /p:PublishProfile=DefaultContainer
    
  3. 生成完成后,运行以下命令以启动应用:

    docker compose up
    

    停止 bash 终端中的后端服务容器并刷新 eShop。 请注意,看到错误消息需要更长的时间。 不过,如果检查日志,可以看到重试策略只重试了五次。 Polly 的最后一条消息是:

    Polly.Timeout.TimeoutRejectedException: The operation didn't complete within the allowed timeout of '00:00:30'.
    

    上述消息表示总请求超时阻止达到最大重试次数。 可以通过增加请求总超时来解决此问题。

  4. 在终端中,按 Ctrl+C 停止应用。

  5. 在Program.cs的代码窗口中,将第 13 行的代码更改为:

    .AddStandardResilienceHandler(options =>
    {
        options.Retry.RetryCount = 7;
        options.TotalRequestTimeout = new HttpTimeoutStrategyOptions
        {
            Timeout = TimeSpan.FromMinutes(5)
        };
    });
    

    上述代码将请求总超时更改为 260 秒,现在比重试策略长。

    通过这些更改,你应该有足够的时间来运行应用、停止产品服务、检查终端日志以重试尝试、刷新 eShop 以查看加载消息,最后重启产品服务,以成功查看产品列表。

  6. 运行以下命令以重新生成 eShop 应用:

    dotnet publish /p:PublishProfile=DefaultContainer
    
  7. 生成完成后,运行以下命令以启动应用:

    docker compose up
    

测试新的复原选项

若要帮助测试容器中的应用,请使用 Docker 扩展。 该扩展提供一个 GUI 来查看和控制容器的状态。

  1. 在左侧菜单中,选择 Docker 图标。

    Docker 扩展的屏幕截图,其中显示了如何停止产品服务。

  2. DOCKER 面板中的 “容器”下,右键单击 产品 容器,然后选择“ 停止”。

  3. 返回到运行应用的浏览器选项卡并刷新产品页面。 应会看到 “正在加载...” 消息。

  4. 返回到代码空间,然后在 “终端 ”选项卡中,选择 docker 终端。 复原策略正在工作。

  5. DOCKER 面板中的 “容器”下,右键单击 产品 容器,然后选择“ 开始”。

  6. 返回到运行应用的浏览器选项卡。 等待,应用应恢复,显示产品列表。

  7. 在终端中,使用 Ctrl+C 停止 docker。