一行代碼讓你的項目輕鬆使用 Dapr

介紹

Dapr 簡化了雲原生開發,讓開發可以把焦點放在應用的業務邏輯上,從而讓代碼簡單、可移植,那作爲一個. Net 開發者,我們也希望項目可以快速用上 dapr,那究竟應該如何做呢?

Dapr 提出了 Sidecar(邊車) 的概念,在啓動項目時再額外啓動一個 Sidecar, 通過 Sidecar 可以解決進程間通信,爲此官方提供了兩種部署方式:

  1. 自託管方式下運行 Dapr

  2. 在 Kubernetes 模式中部署和運行 Dapr

其中 Kubernetes 模式部署是通過 Kubernetes 來完成的,在開發中我們更多的是通過自託管模式使用 Dapr,那自託管模式是怎麼做的呢?

使用命令行工具,在項目根目錄輸入:

dapr run --app-id assignment-server --app-port 5038 dotnet run

詳細文檔參考:手把手教你學 Dapr - 3. 使用 Dapr 運行第一個. Net 程序

參考以上詳細文檔操作後,我們就可以在命令行工具中執行dapr invoke --app-id assignment-server --method hello或者 Http 請求來調用對應的應用的方法

看似好像也不是很複雜,但如果你需要調試 dotnet 項目呢?再複雜一點的需要啓動多個項目進行調試呢?端口一多起來的確會顯得很麻煩。

有沒有什麼辦法可以解決呢?有,docker-compose。

但我還不想用這麼重的東西,我想像平時開發項目一樣直接在 windows 上運行可不可以?

Masa.Utils.Development.Dapr.AspNetCore 它來了

協助管理 dapr 進程,用於開發時減少對 docker compose 的依賴

瞌睡了就有人送枕頭,一句話讓我們瞭解到了它的作用,正好解決了我們需要通過命令行來啓動 dapr 的問題,那下面我們看看這個怎麼用:

入門

本着絕對不多寫一行代碼的心態,我們準備出發了……

  1. 從大佬 doddgu 的博客的鏈接中發現一份源碼地址,爲防止後期文檔調整,先 fork 一份到自己倉庫

    git clone https://github.com/zhenlei520/dapr-study-room.git
  2. 使用命令行工具打開目錄 dapr-study-room\Assignment03,然後執行命令

    dotnet add package Masa.Utils.Development.Dapr.AspNetCore --version 0.4.0-preview.3
    

    或使用 Visual Studio 打開解決方案 Assignment03,選中 Assignment.Server 並安裝 Masa.Utils.Development.Dapr.AspNetCore

  3. 打開Program.cs,並添加 DaprStarter(注意看有註釋的那一行)

    using Masa.Utils.Development.Dapr.AspNetCore;
        
    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddDaprStarter();//添加DaprStarter即可
    var app = builder.Build();
        
    app.Map("/hello", () => Console.WriteLine("Hello World!"));
        
    app.Run();
  4. 使用命令行工具執行命令驗證 dapr 是否啓動成功

    dapr invoke --app-id Assignment-Server-00D861D0C0B7 --method hello

此時會有小夥伴問了,爲什麼 app-id 是 Assignment-Server-00D861D0C0B7?

查看文檔後發現Masa.Utils.Development.Dapr.AspNetCore的 app-id 生成規則爲:AppId + AppIdDelimiter + AppIdSuffix,其中

由於我們的項目名爲 Assignment.Server,當前電腦的網卡地址是 00D861D0C0B7,所以 dapr 最終的 appid 爲 Assignment-Server-00D861D0C0B7,到這裏,Masa.Utils.Development.Dapr.AspNetCore 的使用講解已經完成了

冷知識,爲什麼 . 要換成 - ?

因爲 Dapr 的 AppId 採用 FQDN:(Fully Qualified Domain Name) 全限定域名:同時帶有主機名和域名的名稱。(通過符號 “.”)

爲什麼要加網卡地址作爲後綴?

因爲目前自託管默認採用 mDNS,會導致局域網內用戶的 AppId 互相污染。你的同事和你一起在開發,都啓動了 A 應用,你倆就自動負載了,那後果自然就是請求也到處跑了。

進階

如果我希望自己指定 AppId 而不是使用默認的規則怎麼辦呢?目前支持三種寫法:

配置默認裝配(也是上面介紹的一行代碼的方式)

修改Program.cs文件

// 省略上述代碼
builder.Services.AddDaprStarter();

根據規則 + 代碼指定(配置自定義裝配)

修改Program.cs文件

// 省略上述代碼
builder.Services.AddDaprStarter(opt =>
{
    opt.AppId = "masa-dapr-test";
    opt.AppPort = 5001;
    opt.AppIdSuffix = "";
    opt.DaprHttpPort = 8080;
    opt.DaprGrpcPort = 8081;
});

基於默認裝配的升級版,在默認裝配基礎上通過指定特殊參數完成特殊需求,未配置的參數將使用默認值

根據 IConfiguration 配置生成

  1. 修改appsettings.json
{
  "DaprOptions": {
    "AppId": "masa-dapr-test",
    "AppPort": 5001,
    "AppIdSuffix": "",
    "DaprHttpPort": 8080,
    "DaprGrpcPort": 8081
  }
}
  1. 修改Program.cs
builder.Services.AddDaprStarter(builder.Configuration.GetSection("DaprOptions"));

優勢:更改 appsettings.json 配置後,dapr sidecar 會自動更新,項目無需重啓

Masa.Utils.Development.Dapr.AspNetCore 的設計思路

設計思路基於兩個方面,其一本機自動啓動 dapr sidecar 還可以正常調試. Net 項目,其二簡化配置

技術選型

我們有兩種啓動 dapr sidecar 的方式:

  1. dapr run

  2. daprd

兩者之間的差別如下所示:

完整的對比可查看:https://docs.dapr.io/reference/arguments-annotations-overview/

通過對比我們發現,我們的目標使用 daprd 與 Dapr CLI 都可以實現,那爲什麼 Masa.Utils.Development.Dapr 選擇的是 Dapr CLI,而不是 daprd 呢?

核心的原因是 dapr 可以通過 dapr list 命令很簡單的就獲取到當前運行的所有 dapr 程序,而 daprd 無法獲取。如果使用 daprd,那我們就需要使用 C# 代碼通過操作 dll 獲取具體執行的 dapr 命令,且多平臺支持不好,所以暫時用了 Dapr CLI

更優秀的 Dapr 管理需要做到什麼?

爲了能更方便的使用,我們做了以下約定:

  1. 針對 dapr 的非必填項,默認關閉不啓用,手動配置參數後開啓

  2. 針對 dapr 的必填項: app-id、app-port、dapr-http-port、dapr-grpc-port 自動生成並配置

app-id 生成規則

其中 dapr 的 app-id 默認生成規則爲:AppId + AppIdDelimiter + AppIdSuffix,其中

當 AppIdSuffix 賦值爲空字符串,dapr 的 AppId 的生成規則爲:AppId

app-port 獲取

private ushort GetAppPort(DaprOptions options)
{
  var server = _serviceProvider.GetRequiredService<IServer>();
  var addresses = server.Features.Get<IServerAddressesFeature>()?.Addresses;
  if (addresses is { IsReadOnly: false, Count: 0 })
      throw new Exception("Failed to get the startup port, please specify the port manually");

  return addresses!
      .Select(address => new Uri(address))
      .Where(address
          => (options.EnableSsl is true && address.Scheme.Equals(Uri.UriSchemeHttps, StringComparison.OrdinalIgnoreCase))
          || address.Scheme.Equals(Uri.UriSchemeHttp, StringComparison.OrdinalIgnoreCase))
      .Select(address => (ushort)address.Port).FirstOrDefault();
}

爲了防止啓動過程中修改端口,過早的獲取到被棄用的端口。因此我們使用後臺任務啓動 dapr sidecar

dapr-http-port、dapr-grpc-port 獲取

因爲支持用戶配置,所以我們遵循下面的順序

  1. 如果指定端口,被佔用則自動 kill port 所在進程,保證可以 sidecar 可以正常啓動

    爲什麼端口占用就要先 kill,複用不行嗎?

    因爲 sidecar 有初始化配置,程序調整的代碼影響到 sidecar 配置變更我們無法檢測,所以啓動時保證是最新的是比較合適的選擇

  2. 如果未指定端口,則交還給 dapr,通過 Dapr CLI 的規則生成對應的 http-port 或 grpc-port

Dapr 保活

爲了保證 dapr 進程是活躍的,我們在庫中建立了一個心跳檢查任務用來檢測當前的 dapr 進程是否是活躍的,當 dapr 進程意外停止後會被重啓,且配置信息與上一次成功的 dapr 配置保持不變

如果不需要保活機制的話可以將 EnableHeartBeat 改爲 false,則不啓用 dapr 保活機制

配置支持動態更新

我們通過 IOptionsMonitor 的 OnChange 方法來監聽配置的變更,當配置變更後我們會通過 IDaprProcess 提供的 Refresh 方法來重啓 dapr 進程,並重新調整環境變量信息

本章源碼

Assignment03

https://github.com/zhenlei520/dapr-study-room

開源地址

MASA.BuildingBlocks:https://github.com/masastack/MASA.BuildingBlocks

MASA.Contrib:https://github.com/masastack/MASA.Contrib

MASA.Utils:https://github.com/masastack/MASA.Utils

MASA.EShop:https://github.com/masalabs/MASA.EShop

MASA.Blazor:https://github.com/BlazorComponent/MASA.Blazor

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/rX5jCY_r__W_VgB12nr_Dw