本文說明如何實作新式 Web 應用程式模式。 新式 Web 應用程式模式會定義如何在雲端中將 Web 應用程式現代化,並引進服務導向架構。 新式 Web 應用程式模式提供規範架構、程式代碼和組態指引,以符合 Azure 妥善架構架構的原則,並以 Reliable Web 應用程式模式為基礎建置。
為什麼要使用新式 Web 應用程式模式?
新式 Web 應用程式模式可協助優化 Web 應用程式的高需求區域。 它提供詳細的指引來分離這些區域,以獨立調整成本優化。 此方法可讓您將專用資源配置給重要元件,以提高整體效能。 分離可分離的服務可以藉由防止應用程式中某個部分的變慢影響其他人,來改善可靠性。 分離也會獨立啟用個別應用程式元件的版本控制。
如何實作新式 Web 應用程式模式
本文包含實作新式 Web 應用程式模式的架構、程式代碼和設定指引。 使用下列連結瀏覽至您需要的指引:
- 架構指引:瞭解如何將 Web 應用程式元件模組化,並選取適當的平臺即服務 (PaaS) 解決方案。
- 程序代碼指引:實作四種設計模式來優化分離元件:Strangler Fig、佇列型負載撫平、競爭取用者和健康情況端點監視模式。
- 設定指引:設定分離元件的驗證、授權、自動調整和容器化。
提示
新式 Web 應用程式模式有參考 實 作(範例應用程式)。 它代表新式 Web 應用程式實作的結束狀態。 這是生產等級的 Web 應用程式,其中包含本文所討論的所有程式代碼、架構和組態更新。 部署並使用參考實作來引導您實作新式 Web 應用程式模式。
架構指導
新式 Web 應用程式模式是以可靠的 Web 應用程式模式為基礎。 它需要一些額外的架構元件才能實作。 您需要消息佇列、容器平臺、分離的服務數據存放區和容器登錄(請參閱圖 1)。
針對較高的服務等級目標 (SLO),您可以將第二個區域新增至 Web 應用程式架構。 第二個區域會要求您設定負載平衡器,以將流量路由傳送至第二個區域,以支援主動-主動或主動-被動設定。 使用中樞和輪輻網路拓撲來集中和共用資源,例如網路防火牆。 透過中樞虛擬網路存取容器存放庫。 如果您有虛擬機,請將防禦主機新增至中樞虛擬網路,以安全地管理它們(請參閱圖 2)。
圖 2.具有第二個區域和中樞和輪輻網路拓撲的新式Web應用程式模式架構。
分離架構
若要實作新式 Web 應用程式模式,您需要將現有的 Web 應用程式架構分離。 將架構分離牽涉到將整合型應用程式分解成較小的獨立服務,每個服務都負責特定特性或功能。 此程式需要評估目前的 Web 應用程式、修改架構,最後將 Web 應用程式程式代碼擷取至容器平臺。 目標是要有系統地識別和擷取受益於分離的應用程式服務。 若要分離您的架構,請遵循下列建議:
識別服務界限。 套用網域驅動設計原則,以識別整合型應用程式內的限定內容。 每個限定內容都代表邏輯界限,而且可以是個別服務的候選專案。 代表不同商務功能且相依性較少的服務是分離的良好候選專案。
評估服務優點。 專注於受益於獨立調整的服務。 將這些服務分離,並將處理工作從同步轉換成異步操作,可讓資源管理更有效率、支持獨立部署,並降低在更新或變更期間影響應用程式其他部分的風險。 例如,您可以將訂單結帳與訂單處理區隔開。
評估技術可行性。 檢查目前的架構,以識別可能影響分離程序的技術條件約束和相依性。 規劃如何跨服務管理及共享數據。 分離的服務應該管理自己的數據,並將跨服務界限的直接數據庫存取降到最低。
部署 Azure 服務。 選取並部署您需要的 Azure 服務,以支援您想要擷取的 Web 應用程式服務。 使用下列 選取正確的 Azure 服務 一節來取得指引。
分離 Web 應用程式服務。 為新擷取的 Web 應用程式服務定義清楚的介面和 API,以與系統的其他部分互動。 設計數據管理策略,讓每個服務都能管理自己的數據,同時確保一致性和完整性。 如需在此擷取程式期間使用的特定實作策略和設計模式,請參閱程式 代碼指引 一節。
針對分離的服務使用獨立記憶體。 每個分離的服務都應該有自己的隔離數據存放區,以利獨立版本控制、部署、延展性及維護數據完整性。 例如,參考實作會分隔票證轉譯服務與Web API,並不需要服務存取API的資料庫。 相反地,服務會透過 Azure 服務匯流排 訊息,將票證影像產生回 Web API 的 URL,而 API 會保存其資料庫的路徑。
為每個分離的服務實作個別的部署管線。 個別的部署管線可讓每個服務以自己的步調更新。 如果公司內的不同小組或組織擁有不同的服務,則擁有個別的部署管線可讓每個小組控制自己的部署。 使用 Jenkins、GitHub Actions 或 Azure Pipelines 等持續整合和持續傳遞 (CI/CD) 工具來設定這些管線。
修訂安全性控制。 請確定您的安全性控制已更新,以考慮新的架構,包括防火牆規則和訪問控制。
選取正確的 Azure 服務
如需架構中的每個 Azure 服務,請參閱架構完善的架構中的相關 Azure 服務指南 。 針對新式 Web 應用程式模式,您需要傳訊系統來支援異步傳訊、支援容器化的應用程式平臺,以及容器映射存放庫。
選擇消息佇列。 消息佇列是服務導向架構的重要部分。 它會分離訊息傳送者和接收者,以啟用 異步傳訊。 使用選擇 Azure 傳訊服務的 指引,挑選支援您設計需求的 Azure 傳訊系統。 Azure 有三個傳訊服務:Azure 事件方格、Azure 事件中樞 和 服務匯流排。 從 服務匯流排 開始做為預設選項,如果 服務匯流排 不符合您的需求,請使用其他兩個選項。
服務 使用案例 服務匯流排 選擇 服務匯流排,以取得企業應用程式中高價值訊息可靠、已排序且可能的交易式傳遞。 Event Grid 當您需要有效率地處理大量離散事件時,請選擇 [事件方格]。 事件方格可調整為事件驅動應用程式,其中許多小型獨立事件(例如資源狀態變更)必須在低延遲、發佈-訂閱模型中路由傳送給訂閱者。 事件中樞 選擇事件中樞來擷取大量、高輸送量的數據擷取,例如遙測、記錄或即時分析。 事件中樞已針對需要持續內嵌和處理大量數據的串流案例進行優化。 實作容器服務。 針對您想要容器化的應用程式部分,您需要支援容器的應用程式平臺。 使用選擇 Azure 容器服務 指引來協助您做出決策。 Azure 有三個主要容器服務:Azure Container Apps、Azure Kubernetes Service (AKS)和 Azure App 服務。 從 Container Apps 作為預設選項開始,如果 Container Apps 不符合您的需求,請使用其他兩個選項。
服務 使用案例 容器應用程式 如果您需要自動調整和管理事件驅動應用程式中容器的無伺服器平臺,請選擇 [容器應用程式]。 AKS 如果您需要對 Kubernetes 設定和進階功能進行詳細控制,以調整、網路和安全性,請選擇 AKS。 適用於容器的 Web Apps 選擇 App Service 上適用於容器的 Web 應用程式,以取得最簡單的 PaaS 體驗。 實作容器存放庫。 使用任何容器型計算服務時,必須有存放庫來儲存容器映像。 您可以使用公用容器登錄,例如 Docker Hub 或 Azure Container Registry 之類的受控登錄。 使用 Azure 指引中的容器登錄簡介,協助您做出決策。
程序代碼指引
若要成功分離並擷取獨立服務,您必須使用下列設計模式來更新 Web 應用程式程式代碼:Strangler Fig 模式、佇列型負載撫平模式、競爭取用者模式、健康情況端點監視模式和重試模式。
Strangler Fig 模式:Strangler Fig 模式會以累加方式將功能從整合型應用程式移轉至分離服務。 在主要 Web 應用程式中實作此模式,藉由根據端點引導流量,逐漸將功能移轉至獨立服務。
佇列型負載撫平模式:佇列型負載撫平模式會使用佇列作為緩衝區來管理產生者和取用者之間的訊息流程。 在分離服務的產生者部分實作此模式,以異步方式使用佇列管理訊息流程。
競爭取用者模式:競爭取用者模式可讓分離服務的多個實例獨立讀取相同的消息佇列,並競爭處理訊息。 在分離服務中實作此模式,以將工作分散到多個實例。
健康情況端點監視模式:健康情況端點監視模式會公開端點,以監視 Web 應用程式不同部分的狀態和健康情況。 (4a) 在主要 Web 應用程式中實作此模式。 (4b) 也在分離服務中加以實作,以追蹤端點的健康情況。
重試模式:重試模式會重試間歇性失敗的作業來處理暫時性失敗。 (5a) 在主要 Web 應用程式中對其他 Azure 服務的所有輸出呼叫上實作此模式,例如對消息佇列和私人端點的呼叫。 (5b) 在分離服務中也實作此模式,以處理私人端點呼叫中的暫時性失敗。
每個設計模式都提供符合良好架構架構一或多個支柱的優點(請參閱下表)。
設計模式 | 實作位置 | 可靠性 (RE) | 安全性 (SE) | 成本優化 (CO) | 卓越營運(OE) | 效能效率(PE) | 支持架構完善的架構原則 |
---|---|---|---|---|---|---|---|
Strangler Fig 圖樣 | 主要 Web 應用程式 | ✔ | ✔ | ✔ | RE:08 CO:07 CO:08 OE:06 OE:11 |
||
基於佇列的負載調節模式 | 分離服務的產生者 | ✔ | ✔ | ✔ | RE:06 RE:07 CO:12 PE:05 |
||
競爭取用者模式 | 分離服務 | ✔ | ✔ | ✔ | RE:05 RE:07 CO:05 CO:07 PE:05 PE:07 |
||
健全狀況端點監視模式 | 主要 Web 應用程式與分離服務 | ✔ | ✔ | ✔ | RE:07 RE:10 OE:07 PE:05 |
||
重試模式 | 主要 Web 應用程式與分離服務 | ✔ | RE:07 |
實作 Strangler Fig 模式
使用 Strangler Fig 模式,逐漸將功能從整合型程式代碼基底移轉至新的獨立服務。 從現有的整合型程式代碼基底擷取新的服務,並緩慢地將Web應用程式的重要部分現代化。 若要實作 Strangler Fig 模式,請遵循下列建議:
設定路由層。 在整合型 Web 應用程式程式代碼基底中,實作路由層,以根據端點導向流量。 視需要使用自定義路由邏輯來處理特定商務規則來引導流量。 例如,如果您的整合型應用程式中有
/users
端點,且您已將該功能移至分離的服務,路由層會將所有要求/users
導向至新的服務。管理功能推出。 使用 .NET 功能管理連結庫來 實作功能旗標 和 分段推出 ,以逐步推出分離的服務。 現有的整合型應用程式路由應該控制分離服務收到的要求數目。 從一小部分的要求開始,並隨著時間增加使用量,因為您對它的穩定性和效能充滿信心。 例如,參考實作會將票證轉譯功能擷取到獨立服務中,這可以逐漸導入以處理票證轉譯要求的較大部分。 當新服務證明其可靠性和效能時,它最終可以從整合型接管整個票證轉譯功能,完成轉換。
使用外觀服務(如有必要)。 當單一要求需要與多個服務互動,或想要從客戶端隱藏基礎系統的複雜性時,外觀服務就很有用。 不過,如果分離服務沒有任何公開的 API,則可能不需要外觀服務。 在整合型 Web 應用程式程式代碼基底中,實作外觀服務,將要求路由傳送至適當的後端(整合型或微服務)。 在新的分離服務中,確保新的服務可以在透過外觀存取時獨立處理要求。
實作佇列型負載撫平模式
在 分離服務的產生者部分實作佇列型負載撫平模式 ,以異步方式處理不需要立即回應的工作。 此模式使用佇列來管理工作負載散發,藉此增強整體系統回應性和延展性。 它可讓分離的服務以一致的速率處理要求。 若要有效地實作此模式,請遵循下列建議:
使用非封鎖消息佇列。 請確定將訊息傳送至佇列的進程不會在等候分離服務處理佇列中的訊息時封鎖其他進程。 如果進程需要分離服務作業的結果,請有替代方式來處理等候佇列作業完成時的情況。 例如,參考實作會使用 服務匯流排 和
await
關鍵詞messageSender.PublishAsync()
,以異步方式將訊息發佈至佇列,而不會封鎖執行此程式碼的線程:// Asynchronously publish a message without blocking the calling thread await messageSender.PublishAsync(new TicketRenderRequestMessage(Guid.NewGuid(), ticket, null, DateTime.Now), CancellationToken.None);
此方法可確保主要應用程式保持回應,而且可以同時處理其他工作,而分離的服務則會以可管理的速度處理佇列要求。
實作訊息重試和移除。 實作機制,以重試無法成功處理的佇列訊息處理。 如果失敗持續發生,則應該從佇列中移除這些訊息。 例如,服務匯流排 具有內建的重試和寄不出的信件佇列功能。
設定等冪訊息處理。 處理來自佇列訊息的邏輯必須是等冪的,才能處理訊息可能多次處理的情況。 例如,參考實作使用
ServiceBusClient.CreateProcessor
和AutoCompleteMessages = true
ReceiveMode = ServiceBusReceiveMode.PeekLock
,以確保訊息只會處理一次,而且可以在失敗時重新處理(請參閱下列程序代碼)。// Create a processor for idempotent message processing var processor = serviceBusClient.CreateProcessor(path, new ServiceBusProcessorOptions { // Allow the messages to be auto-completed // if processing finishes without failure. AutoCompleteMessages = true, // PeekLock mode provides reliability in that unsettled messages // will be redelivered on failure. ReceiveMode = ServiceBusReceiveMode.PeekLock, // Containerized processors can scale at the container level // and need not scale via the processor options. MaxConcurrentCalls = 1, PrefetchCount = 0 });
管理體驗的變更。 異步處理可能會導致工作未立即完成。 用戶應該在工作仍在處理時知道,以設定正確的預期並避免混淆。 使用視覺提示或訊息來指出工作正在進行中。 提供使用者在工作完成時接收通知的選項,例如電子郵件或推播通知。
實作競爭取用者模式
在分離的服務中實作競爭取用者模式,以管理來自消息佇列的連入工作。 此模式牽涉到將工作分散到多個分離服務實例。 這些服務會處理來自佇列的訊息、增強負載平衡,以及提升系統處理同時要求的容量。 競爭取用者模式在下列情況下有效:
- 訊息處理的順序並不重要。
- 佇列不會受到格式不正確的訊息影響。
- 處理作業具有等冪性,這表示可以多次套用,而不需變更初始應用程式以外的結果。
若要實作競爭取用者模式,請遵循下列建議:
處理並行訊息。 從佇列接收訊息時,請確定系統的設計目的是要同時處理多個訊息。 將並行呼叫上限設定為 1,讓個別取用者處理每個訊息。
停用預先擷取。 停用訊息預先擷取訊息,讓取用者只有在訊息就緒時才擷取訊息。
使用可靠的訊息處理模式。 使用可靠的處理模式,例如 PeekLock(或其對等專案),自動重試處理失敗的訊息。 此模式可增強刪除優先方法的可靠性。 如果某個背景工作角色無法處理訊息,則即使訊息已處理多次,另一個背景工作角色也必須能夠處理該訊息,而不會發生錯誤。
實作錯誤處理。 將格式不正確或無法處理的訊息路由傳送至個別的寄不出的信件佇列。 此設計可防止重複處理。 例如,您可以在訊息處理期間攔截例外狀況,並將有問題的訊息移至不同的佇列。
處理順序錯誤的訊息。 設計取用者來處理依序抵達的訊息。 多個平行取用者表示它們可能會依序處理訊息。
根據佇列長度進行調整。 從佇列取用訊息的服務應該根據佇列長度自動調整。 調整型自動調整可讓您有效率地處理傳入訊息的尖峰。
使用訊息回復佇列。 如果系統需要訊息後置處理的通知,請設定專用的回復或回應佇列。 此設定會將操作傳訊與通知程式分開。
使用無狀態服務。 請考慮使用無狀態服務來處理來自佇列的要求。 它可讓您輕鬆調整資源,並有效率地使用資源。
設定記錄。 在訊息處理工作流程中整合記錄和特定例外狀況處理。 專注於擷取串行化錯誤,並將這些有問題的訊息導向死信機制。 這些記錄提供寶貴的深入解析以進行疑難解答。
例如,參考實作會在 Container Apps 中執行的無狀態服務上使用競爭取用者模式來處理來自 服務匯流排 佇列的票證轉譯要求。 它會使用下列項目來設定佇列處理器:
- AutoCompleteMessages:在未失敗的情況下處理時自動完成訊息。
- ReceiveMode:如果未解決,則會使用 PeekLock 模式和重新傳遞訊息。
- MaxConcurrentCalls:設定為 1,一次處理一則訊息。
- PrefetchCount:設定為 0 以避免預先擷取訊息。
處理器會記錄訊息處理詳細數據,以協助進行疑難解答和監視。 它會擷取還原串行化錯誤,並將無效的訊息路由傳送至寄不出的信件佇列,以防止重複處理錯誤的訊息。 服務會在容器層級進行調整,允許根據佇列長度有效率地處理訊息尖峰。
// Create a processor for the given queue that will process
// incoming messages.
var processor = serviceBusClient.CreateProcessor(path, new ServiceBusProcessorOptions
{
// Allow the messages to be auto-completed
// if processing finishes without failure.
AutoCompleteMessages = true,
// PeekLock mode provides reliability in that unsettled messages
// are redelivered on failure.
ReceiveMode = ServiceBusReceiveMode.PeekLock,
// Containerized processors can scale at the container level
// and need not scale via the processor options.
MaxConcurrentCalls = 1,
PrefetchCount = 0
});
// Called for each message received by the processor.
processor.ProcessMessageAsync += async args =>
{
logger.LogInformation("Processing message {MessageId} from {ServiceBusNamespace}/{Path}", args.Message.MessageId, args.FullyQualifiedNamespace, args.EntityPath);
// Unhandled exceptions in the handler will be caught by
// the processor and result in abandoning and dead-lettering the message.
try
{
var message = args.Message.Body.ToObjectFromJson<T>();
await messageHandler(message, args.CancellationToken);
logger.LogInformation("Successfully processed message {MessageId} from {ServiceBusNamespace}/{Path}",args.Message.MessageId, args.FullyQualifiedNamespace, args.EntityPath);
}
catch (JsonException)
{
logger.LogError("Invalid message body; could not be deserialized to {Type}", typeof(T));
await args.DeadLetterMessageAsync(args.Message, $"Invalid message body; could not be deserialized to {typeof(T)}",cancellationToken: args.CancellationToken);
}
};
實作健全狀況端點監視模式
在 主要應用程式程式代碼和分離的服務程式代碼中實作健全狀況端點監視模式 ,以追蹤應用程式端點的健康情況。 AKS 或 Container Apps 等協調器可以輪詢這些端點,以確認服務健康情況並重新啟動狀況不良的實例。 ASP.NET Core 應用程式可以新增專用 健康情況檢查中間件 ,以有效率地提供端點健康情況數據和密鑰相依性。 若要實作健全狀況端點監視模式,請遵循下列建議:
實作健康情況檢查。 使用 ASP.NET 核心健康情況檢查中間件 來提供健康情況檢查端點。
驗證相依性。 請確定您的健康情況檢查會驗證密鑰相依性的可用性,例如資料庫、記憶體和傳訊系統。 非Microsoft套件 AspNetCore.Diagnostics.HealthChecks 可以針對許多常見的應用程式相依性實作健康情況檢查相依性檢查。
例如,參考實作會使用 ASP.NET Core 健康狀態檢查中間件來公開健康情況檢查端點,方法是使用
AddHealthChecks()
物件上的builder.Services
方法。 程序代碼會使用AddAzureBlobStorage()
和 方法來驗證密鑰相依性、Azure Blob 儲存體 和 服務匯流排 佇列的可用性,這些和AddAzureServiceBusQueue()
方法是封裝的AspNetCore.Diagnostics.HealthChecks
一部分。 Container Apps 允許設定受監視的健康 情況探查 ,以測量應用程式是否狀況良好或需要回收。// Add health checks, including health checks for Azure services // that are used by this service. // The Blob Storage and Service Bus health checks are provided by // AspNetCore.Diagnostics.HealthChecks // (a popular open source project) rather than by Microsoft. // https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks builder.Services.AddHealthChecks() .AddAzureBlobStorage(options => { // AddAzureBlobStorage will use the BlobServiceClient registered in DI // We just need to specify the container name options.ContainerName = builder.Configuration.GetRequiredConfigurationValue("App:StorageAccount:Container"); }) .AddAzureServiceBusQueue( builder.Configuration.GetRequiredConfigurationValue("App:ServiceBus:Host"), builder.Configuration.GetRequiredConfigurationValue("App:ServiceBus:RenderRequestQueueName"), azureCredentials); // Further app configuration omitted for brevity app.MapHealthChecks("/health");
設定 Azure 資源。 設定 Azure 資源,以使用應用程式的健全狀況檢查 URL 來確認即時性和整備程度。 例如,參考實作會使用 Bicep 來設定健康情況檢查 URL,以確認 Azure 資源的活躍度和整備程度。 在初始延遲為 2 秒之後每隔 10 秒叫用
/health
端點的活躍度探查。probes: [ { type: 'liveness' httpGet: { path: '/health' port: 8080 } initialDelaySeconds: 2 periodSeconds: 10 } ]
實作重試模式
重試 模式 可讓應用程式從暫時性錯誤復原。 重試模式是 Reliable Web 應用程式模式的核心,因此您的 Web 應用程式應該已經使用重試模式。 將重試模式套用至您從 Web 應用程式擷取的分離服務所發出的訊息系統和要求。 若要實作重試模式,請遵循下列建議:
設定重試選項。 與消息佇列整合時,請務必使用適當的重試設定來設定負責與佇列互動的用戶端。 指定參數,例如重試次數上限、重試之間的延遲,以及最大延遲。
使用指數輪詢。 針對重試嘗試實作指數輪詢策略。 這表示以指數方式增加每次重試之間的時間,這有助於在高失敗率期間減少系統上的負載。
使用 SDK 重試功能。 對於具有特殊 SDK 的服務,例如 服務匯流排 或 Blob 記憶體,請使用內建的重試機制。 內建的重試機制已針對服務的一般使用案例進行優化,而且可以更有效率地處理重試,且部分所需的設定較少。 例如,參考實作會使用 服務匯流排 SDK (
ServiceBusClient
和ServiceBusRetryOptions
) 的內建重試功能。 物件ServiceBusRetryOptions
會從MessageBusOptions
擷取設定,以設定重試設定,例如 MaxRetries、Delay、MaxDelay 和 TryTimeout。// ServiceBusClient is thread-safe and can be reused for the lifetime // of the application. services.AddSingleton(sp => { var options = sp.GetRequiredService<IOptions<MessageBusOptions>>().Value; var clientOptions = new ServiceBusClientOptions { RetryOptions = new ServiceBusRetryOptions { Mode = ServiceBusRetryMode.Exponential, MaxRetries = options.MaxRetries, Delay = TimeSpan.FromSeconds(options.BaseDelaySecondsBetweenRetries), MaxDelay = TimeSpan.FromSeconds(options.MaxDelaySeconds), TryTimeout = TimeSpan.FromSeconds(options.TryTimeoutSeconds) } }; return new ServiceBusClient(options.Host, azureCredential ?? new DefaultAzureCredential(), clientOptions); });
採用 HTTP 用戶端的標準復原連結庫。 針對 HTTP 通訊,請整合標準復原連結庫,例如 Polly 或
Microsoft.Extensions.Http.Resilience
。 這些連結庫提供完整的重試機制,對於管理與外部 Web 服務的通訊至關重要。處理訊息鎖定。 針對訊息型系統,實作支援在不遺失數據的情況下重試的訊息處理策略,例如使用可用的「查看鎖定」模式。 請確定失敗的訊息會有效重試,並在重複失敗後移至寄不出的信件佇列。
實作分散式追蹤
當應用程式變得更服務導向且其元件分離時,監視服務之間的執行流程非常重要。 新式 Web 應用程式模式會使用 Application Insights 和 Azure 監視器,透過支援分散式追蹤的 OpenTelemetry API 來查看應用程式健康情況和效能。
分散式追蹤會在用戶周遊多個服務時追蹤使用者要求。 收到要求時,會以追蹤標識符標記,該標識符會透過 HTTP 標頭傳遞至其他元件,並在相依性調用期間 服務匯流排 屬性。 追蹤和記錄接著會同時包含追蹤標識碼和活動標識碼(或範圍標識符),其對應至特定元件及其父活動。 Application Insights 之類的監視工具會用它來顯示不同服務的活動和記錄樹狀結構,對於監視分散式應用程式至關重要。
安裝 OpenTelemetry 連結庫。 使用檢測連結庫從一般元件啟用追蹤和計量。 視需要使用
System.Diagnostics.ActivitySource
和System.Diagnostics.Activity
新增自定義檢測。 使用導出工具連結庫來接聽 OpenTelemetry 診斷,並將其記錄在持續性存放區中。 利用現有的匯出工具,或使用 建立您自己的System.Diagnostics.ActivityListener
。設定 OpenTelemetry。 使用 OpenTelemetry 的 Azure 監視器散發套件 (
Azure.Monitor.OpenTelemetry.AspNetCore
)。 請確定它會將診斷匯出至 Application Insights,並包含 .NET 運行時間的內建檢測,以及 .NET 運行時間的追蹤、記錄和例外狀況,以及 ASP.NET Core。 包含 SQL、Redis 和 Azure SDK 用戶端的其他 OpenTelemetry 檢測套件。監視和分析。 設定之後,請確定會擷取記錄、追蹤、計量和例外狀況,並將其傳送至 Application Insights。 確認包含追蹤、活動和父活動標識碼,讓 Application Insights 能夠跨 HTTP 和 服務匯流排 界限提供端對端追蹤可見性。 使用此設定可有效地監視和分析應用程式跨服務的活動。
新式 Web 應用程式範例會使用 OpenTelemetry (Azure.Monitor.OpenTelemetry.AspNetCore
) 的 Azure 監視器散發。 SQL、Redis 和 Azure SDK 用戶端會使用更多檢測套件。 OpenTelemetry 是在新式 Web 應用程式範例票證轉譯服務中設定,如下所示:
builder.Logging.AddOpenTelemetry(o =>
{
o.IncludeFormattedMessage = true;
o.IncludeScopes = true;
});
builder.Services.AddOpenTelemetry()
.UseAzureMonitor(o => o.ConnectionString = appInsightsConnectionString)
.WithMetrics(metrics =>
{
metrics.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddRuntimeInstrumentation();
})
.WithTracing(tracing =>
{
tracing.AddAspNetCoreInstrumentation()
.AddHttpClientInstrumentation()
.AddSource("Azure.*");
});
方法會 builder.Logging.AddOpenTelemetry
透過OpenTelemetry路由傳送所有記錄,以確保整個應用程式的一致追蹤和記錄。 藉由向 builder.Services.AddOpenTelemetry
註冊 OpenTelemetry 服務,應用程式會設定為收集和匯出診斷,然後透過 UseAzureMonitor
傳送至 Application Insights。 此外,服務匯流排 和 HTTP 用戶端等元件的用戶端檢測會透過 WithMetrics
和WithTracing
進行設定,啟用自動計量和追蹤收集,而不需要變更現有的用戶端使用量,而只需要更新組態。
設定指引
下列各節提供實作組態更新的指引。 每個區段都與一或多個「架構良好架構」的支柱對齊。
組態 | 可靠性 (RE) | 安全性 (SE) | 成本優化 (CO) | 卓越營運(OE) | 效能效率(PE) | 支持架構完善的架構原則 |
---|---|---|---|---|---|---|
設定驗證和授權 | ✔ | ✔ | SE:05 OE:10 |
|||
實作獨立的自動調整 | ✔ | ✔ | ✔ | RE:06 CO:12 PE:05 |
||
容器化服務部署 | ✔ | ✔ | CO:13 PE:09 PE:03 |
設定驗證和授權
若要在新增至 Web 應用程式的任何新 Azure 服務(工作負載身分識別)上設定驗證和授權,請遵循下列建議:
針對每個新服務使用受控識別。 每個獨立服務都應該有自己的身分識別,並使用受控識別進行服務對服務驗證。 受控識別不需要管理程式碼中的認證,並降低認證外泄的風險。 它們可協助您避免將敏感性資訊,例如 連接字串 放在程式代碼或組態檔中。
將最低許可權授與每個新服務。 僅將必要許可權指派給每個新的服務身分識別。 例如,如果身分識別只需要推送至容器登錄,請勿授與提取許可權。 請定期檢閱這些許可權,並視需要進行調整。 針對不同的角色使用不同的身分識別,例如部署和應用程式。 如果一個身分識別遭到入侵,這會限制潛在的損害。
採用基礎結構即程式代碼 (IaC)。 使用 Bicep 或類似的 IaC 工具來定義和管理您的雲端資源。 IaC 可確保在部署中一致地套用安全性設定,並可讓您對基礎結構設定進行版本控制。
若要設定使用者(使用者身分識別)的驗證和授權,請遵循下列建議:
將最低許可權授與使用者。 就像使用服務一樣,請確定用戶只獲得執行其工作所需的許可權。 定期檢閱並調整這些許可權。
定期進行安全性稽核。 定期檢閱和稽核您的安全性設定。 尋找任何設定錯誤或不必要的許可權,並立即加以修正。
參考實作會使用 IaC 將受控識別指派給每個身分識別新增服務和特定角色。 它會定義部署的角色和許可權存取權 (containerRegistryPushRoleId
)、應用程式擁有者 (containerRegistryPushRoleId
) 和 Container Apps 應用程式 () (containerRegistryPullRoleId
請參閱下列程式碼)。
roleAssignments: \[
{
principalId: deploymentSettings.principalId
principalType: deploymentSettings.principalType
roleDefinitionIdOrName: containerRegistryPushRoleId
}
{
principalId: ownerManagedIdentity.outputs.principal_id
principalType: 'ServicePrincipal'
roleDefinitionIdOrName: containerRegistryPushRoleId
}
{
principalId: appManagedIdentity.outputs.principal_id
principalType: 'ServicePrincipal'
roleDefinitionIdOrName: containerRegistryPullRoleId
}
\]
參考實作會在部署時將受控識別指派為新的 Container Apps 身分識別(請參閱下列程式代碼)。
module renderingServiceContainerApp 'br/public:avm/res/app/container-app:0.1.0' = {
name: 'application-rendering-service-container-app'
scope: resourceGroup()
params: {
// Other parameters omitted for brevity
managedIdentities: {
userAssignedResourceIds: [
managedIdentity.id
]
}
}
}
設定獨立的自動調整
新式 Web 應用程式模式會開始分解整合型架構,並引進服務分離。 當您分離 Web 應用程式架構時,您可以獨立調整分離的服務。 調整 Azure 服務以支援獨立的 Web 應用程式服務,而不是整個 Web 應用程式,將調整成本優化,同時符合需求。 若要自動調整容器,請遵循下列建議:
使用無狀態服務。 請確定您的服務是無狀態的。 如果您的 .NET 應用程式包含進程內會話狀態,請將它外部化為 Redis 之類的分散式快取,或 SQL Server 之類的資料庫。
設定自動調整規則。 使用自動調整組態,為您的服務提供最符合成本效益的控制。 針對容器化服務,事件型調整,例如 Kubernetes 事件驅動自動調整程式 (KEDA),通常會提供細微的控制,讓您根據事件計量進行調整。 容器應用程式和 AKS 支援 KEDA。 對於不支援 KEDA 的服務,例如 App Service,請使用平臺本身所提供的自動調整功能。 這些功能通常包括根據計量型規則或 HTTP 流量進行調整。
設定最小復本。 若要防止冷啟動,請設定自動調整設定,以維持至少一個複本。 冷啟動是當您從停止狀態初始化服務時,通常會建立延遲的回應。 如果將成本降至最低是優先順序,而且您可以容忍冷啟動延遲,請在設定自動調整時,將復本計數下限設定為 0。
設定冷卻期間。 套用適當的冷卻期間,以在調整事件之間引入延遲。 目標是 防止暫時負載尖峰觸發的過度調整 活動。
設定佇列型調整。 如果您的應用程式使用訊息佇列,例如 服務匯流排,請設定自動調整設定,以根據具有要求訊息的佇列長度進行調整。 調整程式的目標是針對佇列中每個 N 個訊息維護一個服務複本(四捨五入)。
例如,參考實作會使用 服務匯流排 KEDA 縮放程式,根據佇列長度調整容器應用程式。 會service-bus-queue-length-rule
根據指定的 服務匯流排 佇列長度來調整服務。 參數 messageCount
會設定為 10,因此擴展器針對佇列中每 10 則訊息都有一個服務複本。 scaleMaxReplicas
和 scaleMinReplicas
參數會設定服務的複本數目上限和最小值。 秘密queue-connection-string
,其中包含 服務匯流排 佇列的 連接字串,是從 Azure 金鑰保存庫 擷取。 此秘密可用來向 服務匯流排 驗證縮放程式。
scaleRules: [
{
name: 'service-bus-queue-length-rule'
custom: {
type: 'azure-servicebus'
metadata: {
messageCount: '10'
namespace: renderRequestServiceBusNamespace
queueName: renderRequestServiceBusQueueName
}
auth: [
{
secretRef: 'render-request-queue-connection-string'
triggerParameter: 'connection'
}
]
}
}
]
scaleMaxReplicas: 5
scaleMinReplicas: 0
容器化服務部署
容器化表示應用程式運作的所有相依性都會封裝在可可靠地部署到各種主機的輕量型映像中。 若要容器化部署,請遵循下列建議:
識別網域界限。 從識別整合型應用程式內的網域界限開始。 這有助於判斷您可以擷取至個別服務的應用程式部分。
建立 Docker 映像。 為 .NET 服務建立 Docker 映射時,請使用 切碎的基底映射。 這些映射只包含執行 .NET 所需的最小套件集,可將套件大小和受攻擊介面區降到最低。
使用多階段 Dockerfiles。 實作多階段 Dockerfiles,將建置時間資產與運行時間容器映射分開。 這有助於保持生產映像的小型且安全。
以非根使用者身分執行。 以非根使用者身分執行 .NET 容器(透過用戶名稱或 UID,$APP_UID),以符合最低許可權原則。 它會限制遭入侵容器的潛在影響。
接聽埠 8080。 以非根使用者身分執行時,請將您的應用程式設定為接聽埠 8080。 這是非根使用者的共同慣例。
封裝相依性。 確定應用程式要運作的所有相依性都會封裝在 Docker 容器映射中。 封裝可讓應用程式可靠地部署到各種主機。
選擇正確的基底映像。 您選擇的基底映像取決於您的部署環境。 例如,如果您要部署至 Container Apps,則需要使用 Linux Docker 映射。
例如,參考實作會使用 多階段 建置程式。 初始階段會使用完整的 SDK 映像編譯和建置應用程式。mcr.microsoft.com/dotnet/sdk:8.0-jammy
最後一個運行時間映像是從 chiseled
基底映射建立,這會排除 SDK 和建置成品。 服務會以非根使用者 (USER $APP_UID
) 的形式執行,並公開埠 8080。 應用程式操作所需的相依性會包含在 Docker 映像中,如複製專案檔和還原套件的命令所辨識。 使用以Linux為基礎的映像 (mcr.microsoft.com/dotnet/aspnet:8.0-jammy-chiseled
) 可確保與 Container Apps 相容,這需要Linux容器以進行部署。
# Build in a separate stage to avoid copying the SDK into the final image
FROM mcr.microsoft.com/dotnet/sdk:8.0-jammy AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
# Restore packages
COPY ["Relecloud.TicketRenderer/Relecloud.TicketRenderer.csproj", "Relecloud.TicketRenderer/"]
COPY ["Relecloud.Messaging/Relecloud.Messaging.csproj", "Relecloud.Messaging/"]
COPY ["Relecloud.Models/Relecloud.Models.csproj", "Relecloud.Models/"]
RUN dotnet restore "./Relecloud.TicketRenderer/Relecloud.TicketRenderer.csproj"
# Build and publish
COPY . .
WORKDIR "/src/Relecloud.TicketRenderer"
RUN dotnet publish "./Relecloud.TicketRenderer.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
# Chiseled images contain only the minimal set of packages needed for .NET 8.0
FROM mcr.microsoft.com/dotnet/aspnet:8.0-jammy-chiseled AS final
WORKDIR /app
EXPOSE 8080
# Copy the published app from the build stage
COPY --from=build /app/publish .
# Run as non-root user
USER $APP_UID
ENTRYPOINT ["dotnet", "./Relecloud.TicketRenderer.dll"]
部署參考實作
部署適用於 .NET 的新式 Web 應用程式模式參考實作。 存放庫中有開發和生產部署的指示。 部署之後,您可以模擬並觀察設計模式。
圖 3.參考實作的架構。 下載此架構的 Visio 檔案 。