Dapr 與 .NET Aspire 結合使用獲得無與倫比的本地開發體驗

张善友發表於2024-05-17

Dapr 提供了一組構建塊,用於抽象分散式系統中常用的概念。這包括服務、快取、工作流、復原能力、機密管理等之間的安全同步和非同步通訊。不必自己實現這些功能,可以消除樣板降低複雜性,並允許您專注於開發業務功能。

在您的時間有限並且您只想進行實驗的情況下,在Dapr初始設定上花費大量時間可能會令人沮喪。更不用說你尚未確定對本地開發體驗(故障排除、除錯、載入等)的影響。也許你的一些同事最初會不情願,並認為你正在讓他們的工作比現在更復雜。

本文將向你展示如何將 Dapr 與 .NET Aspire 結合使用,以獲得無與倫比的本地開發體驗。我們將建立一些 ASP.NET 核心和Node.js服務,這些服務將利用服務呼叫狀態管理和釋出/訂閱。好處是:

  • 透過編譯時常量、可測試程式碼表示分散式系統。
  • 集中式 OpenTelemetry Web 儀表板,用於瀏覽跟蹤、日誌和指標。
  • 一種將 Dapr sidecar 附加到應用程式的簡單方法。
  • 很少或沒有 YAML 配置檔案。

使用 .NET Aspire for Dapr 將減少開發人員的入門時間。他們可以專注於使用 Dapr 進行功能開發,並花更少的時間設定本地環境。由於與 OpenTelemetry 的整合,可以更輕鬆地在本地對多個應用程式之間的互動進行故障排除,這通常是在部署程式碼後在雲環境中才能獲得的。


具有 .NET Aspire 的 Dapr 分散式系統示例

image

使用 .NET Aspire 進行 Dapr 實驗的目標是建立三個服務和 .NET Aspire 主機專案,後者充當業務流程協調程式:

  1. Alice,一個 ASP.NET 核心服務,它使用 Dapr 的服務呼叫從另一個服務檢索天氣資料,並使用狀態儲存對其進行快取。
  2. Bob 是一個 ASP.NET Core 服務,它返回虛假的天氣資料,然後使用 pub/sub 釋出“請求天氣預報”事件。
  3. Carol,一個 Node.js Express Web 應用程式,訂閱“請求天氣預報”事件。

可在此 GitHub 儲存庫找到可以使用的完整程式碼 .自述檔案將指導您安裝必備元件並啟動服務。下面的程式碼是 .NET Aspire 主機專案,我們在其中宣告這些服務、Dapr 元件及其關係,不涉及 YAML:

using Aspire.Hosting.Dapr;
using Microsoft.Extensions.Hosting;

var builder = DistributedApplication.CreateBuilder(args);

var stateStore = builder.AddDaprStateStore("statestore");
var pubSub = builder.AddDaprPubSub("pubsub");

builder.AddProject<Projects.AspireDaprDemo_AliceService>("alice")
.WithDaprSidecar(new DaprSidecarOptions
{
// Loads the resiliency policy for service invocation from alice to bob
ResourcesPaths = [Path.Combine("..", "resources")],
})
.WithReference(stateStore)
.WithReference(pubSub);

builder.AddProject<Projects.AspireDaprDemo_BobService>("bob")
.WithDaprSidecar()
.WithReference(stateStore)
.WithReference(pubSub);

builder.AddNpmApp("carol", Path.Combine("..", "AspireDaprDemo.CarolService"), "watch")
.WithHttpEndpoint(port: 3000, env: "PORT")
.WithEnvironment("NODE_TLS_REJECT_UNAUTHORIZED", builder.Environment.IsDevelopment() ? "0" : "1")
.WithDaprSidecar()
.WithReference(stateStore)
.WithReference(pubSub);

builder.Build().Run();

啟動後,Aspire 會啟動所有服務,並在儀表板中提供分散式系統的完整檢視

image

在此示例中,Alice 服務公開觸發上述互動的終結點。呼叫此終結點時,OpenTelemetry 跟蹤如下所示:/weatherforecast

image

加入開發團隊的開發人員可以快速瞭解分散式系統的不同元件如何相互互動。在此螢幕截圖中,我們可以看到 flky Bob 服務返回錯誤,並且 Dapr 自動重試該操作。與 Dapr 提供的預設 Zipkin 例項相比,.NET Aspire 提供了一種更好的方法來視覺化 OpenTelemetry 跟蹤,因為跟蹤不僅在視覺上更清晰,而且儀表板還包括日誌和指標。

image

帶有 .NET Aspire 的 Dapr 無需配置且易於使用

通常,要配置 Dapr,您需要建立 YAML 配置檔案來描述應用程式、sidecar 和網路詳細資訊(如 TCP 埠)。對於 .NET Aspire,這不是必需的。

Alice 和 Bob 之間的通訊(他們的名字是在 Aspire 主機專案中宣告的)非常簡單,這要歸功於 Dapr SDK。

// Otherwise, get a fresh weather forecast from the flaky service "bob" and cache it
var forecasts = await client.InvokeMethodAsync<WeatherForecast[]>(HttpMethod.Get, "bob", "weatherforecast");

未在appsettings.json和環境變數中配置 URL。使用服務名稱bob是唯一必需的常量。Dapr 負責將請求路由到正確的服務。

狀態儲存和 pub/sub 也是如此。只有 Dapr sidecar 知道連線詳細資訊,因此應用程式無需擔心它們。這避免了繁瑣的配置檔案管理。想象一下,在分散式系統中有 10 個服務,以及 4 個環境:本地環境、dev 環境、stg 環境和 prod。這可能表示要維護的 40 個潛在配置檔案,以及數十個 URL 和連線字串。多虧了 Dapr,您再也不用擔心這個問題了。

使用狀態儲存和 pub/sub 同樣簡單:

// Retrieve the weather forecast from the state store "statestore" declared in the Aspire host
var cachedForecasts = await client.GetStateAsync<CachedWeatherForecast>("statestore", "cache");

// [...]
// Save the weather forecast in the state store under the key "cache"
await client.SaveStateAsync("statestore", "cache", new CachedWeatherForecast(forecasts, DateTimeOffset.UtcNow));

// Publish an event "WeatherForecastMessage" to the pub/sub "pubsub" declared in the Aspire host, with the topic "weather"
await client.PublishEventAsync("pubsub", "weather", new WeatherForecastMessage("Weather forecast requested!"));


這是訂閱“天氣”主題的 Carol 服務的片段。請記住,.NET Aspire 和 Dapr 都與語言無關:

// Events are received through HTTP POST requests (push delivery model)
app.post("/subscriptions/weather", (req, res) => {
console.log("Weather forecast message received:", req.body.data);
res.sendStatus(200);
});

.NET Aspire 如何與 Dapr 配合使用?

.NET Aspire 在資源上使用WithDaprSidecardapr,該方法指示 啟動可執行檔案的例項。

// [...]
.WithDaprSidecar()
.WithReference(stateStore)
.WithReference(pubSub);

Dapr傳遞的引數取決於服務引用的元件數以及在呼叫上述方法期間可能傳遞的選項。

這裡要記住兩個關鍵點:

  • .NET Aspire 中內建元件(如狀態儲存和 pub/sub)的 YAML 程式碼在臨時資料夾中自動生成。
  • 預設情況下,會分配隨機埠,因此您不必記住它們或擔心可能的衝突。

如果您想了解詳細資訊,可以在 .NET Aspire 原始碼中的 DaprDistributedApplicationLifecycleHook 類中看它是如何實現的。隨後,編排的應用程式被傳遞環境變數,允許 Dapr SDK 與 sidecar 進行通訊。這可以從 Aspire 儀表板上的資源詳細資訊中看出:

image

處理更復雜的 Dapr 場景

在此實驗中,我們使用了 .NET Aspire 本機支援的兩個 Dapr 元件。但是,可以使用以下方法AddDaprComponent 宣告其他型別的元件:

var stateStore = builder.AddDaprStateStore("statestore");
var pubSub = builder.AddDaprPubSub("pubsub");

還可以宣告資源,例如彈性策略,並將它們分配給 sidecar:

builder.AddProject<Projects.AspireDaprDemo_AliceService>("alice")
.WithDaprSidecar(new DaprSidecarOptions
{
// Loads the resiliency policy for service invocation from alice to bob
ResourcesPaths = [Path.Combine("..", "resources")],
})
.WithReference(stateStore)
.WithReference(pubSub);

builder.AddProject<Projects.AspireDaprDemo_BobService>("bob")
.WithDaprSidecar()
.WithReference(stateStore)
.WithReference(pubSub);

builder.AddNpmApp("carol", Path.Combine("..", "AspireDaprDemo.CarolService"), "watch")
.WithHttpEndpoint(port: 3000, env: "PORT")
.WithEnvironment("NODE_TLS_REJECT_UNAUTHORIZED", builder.Environment.IsDevelopment() ? "0" : "1")
.WithDaprSidecar()
.WithReference(stateStore)
.WithReference(pubSub);


相關連結

  • 此部落格文章的完整程式碼示例
  • 此部落格文章的英文原文
  • .NET Aspire 文件
  • Dapr 文件
  • .NET Aspire 程式碼示例
  • Dapr 快速入門程式碼示例

相關文章