任務關鍵性工作負載的應用程式設計考慮
基準 任務關鍵性參考架構 會使用簡單的在線類別目錄應用程序來說明高度可靠的工作負載。 用戶可以瀏覽專案目錄、檢閱專案詳細數據,以及張貼項目的評等和批注。 本文著重於任務關鍵性應用程式的可靠性與復原層面,例如異步要求處理,以及如何在解決方案內達到高輸送量。
重要
生產等級參考實作,示範本文中指引 Azure 支援 任務關鍵性應用程式開發。 您可以在進入生產階段的第一個步驟中,使用此實作作為進一步解決方案開發的基礎。
應用程式組合
針對大規模的任務關鍵性應用程式,您必須將架構優化,以達到端對端延展性和復原能力。 您可以將元件分成可獨立運作的功能單位。 在應用程式堆疊上套用此分隔,讓系統的每個部分都能獨立調整,並符合需求變更。 實作示範此方法。
應用程式會使用無狀態 API 端點,透過訊息代理程式以異步方式分離長時間執行的寫入要求。 工作負載的組成可讓您隨時在戳記中刪除和重新建立整個 Azure Kubernetes Service (AKS) 叢集和其他相依性。 應用程式的主要元件包括:
使用者介面 (UI):使用者可以存取的單頁 Web 應用程式。 UI 裝載於 Azure 儲存體 帳戶的靜態網站裝載中。
API (
CatalogService
):由 UI 應用程式呼叫但仍可供其他潛在用戶端應用程式使用的 REST API。背景工作角色 (
BackgroundProcessor
):接聽訊息總線上新事件的背景背景工作角色,並處理對資料庫的寫入要求。 此元件不會公開任何 API。健康情況服務 API (
HealthService
):藉由檢查關鍵元件是否正常運作來報告應用程式的 API,例如資料庫或傳訊總線。
工作負載是由 API、背景工作角色和健康情況檢查應用程式所組成。 稱為 workload
的專用 AKS 命名空間會將工作負載裝載為容器。 Pod 之間不會發生直接通訊。 Pod 是無狀態的,而且可以獨立調整。
在叢集中執行的其他支援元件包括:
NGINX 輸入控制器:將連入要求路由傳送至工作負載,並在 Pod 之間進行負載平衡。 NGINX 輸入控制器是透過具有公用IP位址的 Azure Load Balancer 公開,但只能透過 Azure Front Door 存取。
憑證管理員:Jetstack 的
cert-manager
自動布建傳輸層安全性 (TLS) 憑證,方法是針對輸入規則使用 Let's Encrypt。秘密存放區 CSI 驅動程式:適用於秘密存放區 CSI 驅動程式的 Azure 金鑰保存庫 提供者會安全地讀取秘密,例如 金鑰保存庫 連接字串。
監視代理程式:會調整預設 OMSAgentForLinux 設定,以減少傳送至 Azure 監視器記錄工作區的監視數據量。
資料庫連線
由於部署戳記的暫時本質,請盡可能避免在戳記內保存狀態。 您應該在外部化資料存放區中保存狀態。 若要支援可靠性服務等級目標 (SLO),請建立復原的數據存放區。 我們建議您使用受控或平臺即服務(PaaS)解決方案,搭配原生 SDK 連結庫自動處理逾時、中斷連線和其他失敗狀態。
在參考實作中,Azure Cosmos DB 可作為應用程式的主要數據存放區。 Azure Cosmos DB 提供多區域寫入。 每個戳記都可以寫入相同區域中的 Azure Cosmos DB 複本,而 Azure Cosmos DB 會在內部處理區域之間的數據復寫和同步處理。 適用於 NoSQL 的 Azure Cosmos DB 支援資料庫引擎的所有功能。
如需更多資訊,請參閱關鍵任務工作負載的資料平台。
注意
針對新的應用程式使用適用於 NoSQL 的 Azure Cosmos DB。 針對使用其他 NoSQL 通訊協定的舊版應用程式,請評估 Azure Cosmos DB 的移轉路徑。
對於優先順序超過效能的任務關鍵性應用程式,我們建議使用強式一致性層級的單一區域寫入和多重區域讀取。
此架構會使用記憶體暫時將狀態儲存在戳記中,以便 Azure 事件中樞 檢查點。
所有工作負載元件都會使用 Azure Cosmos DB .NET Core SDK 與資料庫通訊。 SDK 包含健全的邏輯,可維護資料庫連線並處理失敗。 主要組態設定包括:
直接連線模式:此設定是 .NET SDK v3 的預設值,因為它可提供更佳的效能。 相較於使用 HTTP 的閘道模式,直接連線模式的網路躍點較少。
在寫入時傳回內容回應:已停用此方法,讓 Azure Cosmos DB 用戶端無法從建立、更新插入和修補和取代作業傳回檔,進而減少網路流量。 用戶端上的進一步處理不需要此設定。
自定義串行化:此程式會將 JSON 屬性命名原則設定為將
JsonNamingPolicy.CamelCase
.NET 屬性轉譯為標準 JSON 屬性。 它也可以將 JSON 屬性轉譯為 .NET 屬性。 默認忽略條件會忽略具有 Null 值的屬性,例如JsonIgnoreCondition.WhenWritingNull
在串行化期間。ApplicationRegion:此屬性會設定為戳記的區域,讓 SDK 能夠尋找最接近的連線端點。 端點最好位於相同的區域中。
下列程式代碼區塊會出現在參考實作中:
//
// /src/app/AlwaysOn.Shared/Services/CosmosDbService.cs
//
CosmosClientBuilder clientBuilder = new CosmosClientBuilder(sysConfig.CosmosEndpointUri, sysConfig.CosmosApiKey)
.WithConnectionModeDirect()
.WithContentResponseOnWrite(false)
.WithRequestTimeout(TimeSpan.FromSeconds(sysConfig.ComsosRequestTimeoutSeconds))
.WithThrottlingRetryOptions(TimeSpan.FromSeconds(sysConfig.ComsosRetryWaitSeconds), sysConfig.ComsosMaxRetryCount)
.WithCustomSerializer(new CosmosNetSerializer(Globals.JsonSerializerOptions));
if (sysConfig.AzureRegion != "unknown")
{
clientBuilder = clientBuilder.WithApplicationRegion(sysConfig.AzureRegion);
}
_dbClient = clientBuilder.Build();
異步傳訊
當您實作鬆散結合時,服務不會與其他服務有相依性。 鬆散層面可讓服務獨立運作。 結合層面可透過定義完善的介面啟用服務間通訊。 對於任務關鍵性應用程式,鬆散結合可防止下游失敗串連至前端或其他部署戳記,以提供高可用性。
異步傳訊的主要特性包括:
服務不需要使用相同的計算平臺、程式設計語言或操作系統。
服務會獨立調整。
下游失敗不會影響用戶端交易。
交易完整性難以維護,因為數據建立和持續性發生在不同的服務中。 交易完整性是傳訊和持續性服務的挑戰。 如需詳細資訊,請參閱 等冪訊息處理。
端對端追蹤需要複雜的協調流程。
建議您使用已知的設計模式,例如 佇列型負載撫平模式 和 競爭取用者模式。 這些模式會將來自產生者的負載散發給取用者,並讓取用者啟用異步處理。 例如,背景工作角色可讓 API 接受要求並快速返回呼叫端,而背景工作角色會個別處理資料庫寫入作業。
事件中樞會代理 API 與背景工作角色之間的訊息。
重要
不要長時間使用訊息代理程式做為持續性數據存放區。 事件中樞服務支援擷 取功能。 擷取功能可讓事件中樞自動將訊息複本寫入連結的記憶體帳戶。 此程式會控制使用方式,並做為備份訊息的機制。
寫入作業實作詳細數據
寫入作業,例如貼文評等和貼文批注,會以異步方式處理。 API 會先將包含所有相關信息的訊息,例如動作類型和批註數據傳送至消息佇列,並立即傳Location
回HTTP 202 (Accepted)
將建立之 對象的標頭。
BackgroundProcessor
實例會處理佇列中的訊息,並處理寫入作業的實際資料庫通訊。 BackgroundProcessor
根據佇列訊息磁碟區來相應縮小和相應放大。 處理器實例的向外延展限制是由 事件中樞分割的最大數目所定義,而基本層和標準層為 32 個,進階層為 100,專用層為 1,024。
中的 BackgroundProcessor
Azure 事件中樞 處理器連結庫會使用 Azure Blob 儲存體 來管理分割區擁有權、不同背景工作實例之間的負載平衡,以及使用檢查點來追蹤進度。 檢查點不會在每個事件之後寫入 Blob 記憶體,因為它會為每個訊息增加昂貴的延遲。 相反地,檢查點會在定時器迴圈上寫入,而您可以設定持續時間。 默認設定為10秒。
下列程式代碼區塊會出現在參考實作中:
while (!stoppingToken.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromSeconds(_sysConfig.BackendCheckpointLoopSeconds), stoppingToken);
if (!stoppingToken.IsCancellationRequested && !checkpointEvents.IsEmpty)
{
string lastPartition = null;
try
{
foreach (var partition in checkpointEvents.Keys)
{
lastPartition = partition;
if (checkpointEvents.TryRemove(partition, out ProcessEventArgs lastProcessEventArgs))
{
if (lastProcessEventArgs.HasEvent)
{
_logger.LogDebug("Scheduled checkpointing for partition {partition}. Offset={offset}", partition, lastProcessEventArgs.Data.Offset);
await lastProcessEventArgs.UpdateCheckpointAsync();
}
}
}
}
catch (Exception e)
{
_logger.LogError(e, "Exception during checkpointing loop for partition={lastPartition}", lastPartition);
}
}
}
如果處理器應用程式發生錯誤或已停止,才能處理訊息:
另一個實例會挑選訊息以進行重新處理,因為它在記憶體中未正確檢查點。
如果先前的背景工作角色在背景工作角色失敗之前保存資料庫中的檔,就會發生衝突。 之所以發生此錯誤,是因為使用相同的標識碼和數據分割索引鍵。 處理器可以安全地忽略訊息,因為檔已經保存。
如果先前的背景工作角色在寫入資料庫之前終止,新的實例會重複這些步驟,並完成持續性。
讀取作業實作詳細數據
API 會直接處理讀取作業,並立即將數據傳回給使用者。
如果作業順利完成,則不會建立後端通道方法,以與客戶端通訊。 用戶端應用程式必須主動輪詢 API,以取得 HTTP 標頭中所 Location
指定專案的相關更新。
延展性
個別工作負載元件應該獨立相應放大,因為每個元件都有不同的負載模式。 調整需求取決於服務的功能。 某些服務直接影響使用者,而且必須積極相應放大,以確保快速回應和正面的用戶體驗。
實作會將服務封裝為容器映像,並使用 Helm 圖表將服務部署到每個戳記。 這些服務會設定為具有預期的 Kubernetes 要求和限制,以及預先設定的自動調整規則。 和 CatalogService
BackgroundProcessor
工作負載元件可以個別相應縮小和相應放大,因為這兩個服務都是無狀態的。
使用者直接與 CatalogService
互動,因此工作負載的這個部分必須在任何負載下回應。 每個叢集至少有三個實例可分散到 Azure 區域中的三個可用性區域。 AKS 中的水準 Pod 自動調整程式 (HPA) 會視需要自動新增更多 Pod。 Azure Cosmos DB 自動調整功能可以動態增加和減少集合可用的要求單位(RU)。 CatalogService
和 Azure Cosmos DB 結合在戳記內形成縮放單位。
HPA 會使用 Helm 圖表來部署,其可設定的最大數目和最小復本數目。 負載測試判斷每個實例每秒可以使用標準使用模式來處理大約250個要求。
此 BackgroundProcessor
服務有不同的需求,並被視為對用戶體驗有有限影響的背景背景工作角色。 因此 BackgroundProcessor
,與 相比 CatalogService
,它有不同的自動調整組態,而且它可以調整 2 到 32 個實例。 根據您在事件中樞中使用的分割區數目來判斷此限制。 您不需要比分割區更多的背景工作角色。
元件 | minReplicas |
maxReplicas |
---|---|---|
CatalogService | 3 | 20 |
BackgroundProcessor | 2 | 32 |
包含相依性之工作負載的每個元件,如 ingress-nginx
已 設定Pod中斷預算 (PDB) 設定,以確保叢集變更時,最少的實例數目仍可供使用。
下列程式代碼區塊會出現在參考實作中:
#
# /src/app/charts/healthservice/templates/pdb.yaml
# Example pod distribution budget configuration.
#
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: {{ .Chart.Name }}-pdb
spec:
minAvailable: 1
selector:
matchLabels:
app: {{ .Chart.Name }}
注意
透過負載測試,判斷每個元件的實際最小數目和 Pod 數目上限。 每個工作負載的 Pod 數目可能會有所不同。
檢測
使用檢測來評估工作負載元件可以引入系統的效能瓶頸和健康問題。 為了協助您量化決策,每個元件都應該透過計量和追蹤記錄發出足夠的資訊。 當您檢測應用程式時,請考慮下列重要考慮:
- 將記錄、計量和其他遙測傳送至戳記的記錄系統。
- 使用結構化記錄,而不是純文本,以便查詢資訊。
- 實作事件相互關聯以取得端對端交易檢視。 在參考實作中,每個 API 回應都會包含作業識別碼做為 HTTP 標頭以供追蹤。
- 不要只 依賴 stdout 記錄或控制台記錄。 但是您可以使用這些記錄來立即針對失敗的 Pod 進行疑難解答。
此架構會使用Application Insights和 Azure 監視器記錄工作區來實作分散式追蹤,以取得應用程式監視數據。 針對工作負載和基礎結構元件的記錄和計量使用 Azure 監視器記錄。 此架構會實作來自 API、透過事件中樞,然後移至 Azure Cosmos DB 的完整端對端追蹤要求。
重要
將戳記監視資源部署到個別的監視資源群組。 資源具有與戳記本身不同的生命週期。 如需詳細資訊,請參閱 監視戳記資源的數據。
應用程式監視實作詳細數據
元件 BackgroundProcessor
會 Microsoft.ApplicationInsights.WorkerService
使用 NuGet 套件從應用程式取得現用的檢測。 Serilog 也用於應用程式內的所有記錄。 除了主控台接收之外,Application Insights 也會設定為接收。 TelemetryClient
只有在追蹤其他計量時,才會直接使用Application Insights的實例。
下列程式代碼區塊會出現在參考實作中:
//
// /src/app/AlwaysOn.BackgroundProcessor/Program.cs
//
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(hostContext.Configuration)
.Enrich.FromLogContext()
.WriteTo.Console(outputTemplate: "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}")
.WriteTo.ApplicationInsights(hostContext.Configuration[SysConfiguration.ApplicationInsightsConnStringKeyName], TelemetryConverter.Traces)
.CreateLogger();
}
為了示範實際的要求可追蹤性,每個成功且不成功的 API 要求都會將相互關聯標識符標頭傳回給呼叫端。 應用程式支援小組可以使用此標識符來搜尋 Application Insights,並取得完整交易的詳細檢視,如下圖所示。
下列程式代碼區塊會出現在參考實作中:
//
// /src/app/AlwaysOn.CatalogService/Startup.cs
//
app.Use(async (context, next) =>
{
context.Response.OnStarting(o =>
{
if (o is HttpContext ctx)
{
// ... code omitted for brevity
context.Response.Headers.Add("Server-Location", sysConfig.AzureRegion);
context.Response.Headers.Add("Correlation-ID", Activity.Current?.RootId);
context.Response.Headers.Add("Requested-Api-Version", ctx.GetRequestedApiVersion()?.ToString());
}
return Task.CompletedTask;
}, context);
await next();
});
注意
預設會在 Application Insights SDK 中啟用調適型取樣。 自適性取樣表示並非每個要求都會傳送至雲端,而且可依標識符進行搜尋。 任務關鍵性應用程式小組需要可靠地追蹤每個要求,這就是為什麼參考實作在生產環境中停用調適性取樣的原因。
Kubernetes 監視實作詳細數據
您可以使用診斷設定將 AKS 記錄和計量傳送至 Azure 監視器記錄。 您也可以搭配 AKS 使用容器深入解析功能。 啟用容器深入解析,透過 AKS 叢集中每個節點上的 Kubernetes DaemonSet 部署 OMSAgentForLinux。 OMSAgentForLinux 可以從 Kubernetes 叢集中收集更多記錄和計量,並將其傳送至其對應的 Azure 監視器記錄工作區。 此工作區包含有關 Pod、部署、服務和叢集整體健康情況的細微數據。
廣泛的記錄可能會對成本造成負面影響,而且不會帶來好處。 因此, 容器深入解析組態中的工作負載 Pod 會停用 stdout 記錄收集與 Prometheus 擷取,因為所有追蹤都已經透過 Application Insights 擷取,這會產生重複的記錄。
下列程式代碼區塊會出現在參考實作中:
#
# /src/config/monitoring/container-azm-ms-agentconfig.yaml
# This is just a snippet showing the relevant part.
#
[log_collection_settings]
[log_collection_settings.stdout]
enabled = false
exclude_namespaces = ["kube-system"]
如需詳細資訊,請參閱 完整的組態檔。
應用程式健康情況監視
您可以使用應用程式監視和可觀察性,快速識別系統問題,並通知 健康情況模型 目前的應用程式狀態。 您可以透過 健康情況端點呈現健康情況監視。 健康情況探查會 使用健康情況監視數據來提供資訊。 主要負載平衡器會使用該資訊立即將狀況不良的元件從輪替中取出。
此架構會在下列層級套用健康情況監視:
在 AKS 上執行的工作負載 Pod。 這些 Pod 具有健康情況和活躍度探查,因此 AKS 可以管理其生命週期。
健全狀況服務,這是叢集上的專用元件。 Azure Front Door 已設定為探查每個戳記中的 健全狀況服務,並從自動負載平衡中移除狀況不良的戳記。
健全狀況服務 實作詳細數據
HealthService
是在計算叢集上與其他元件一起執行的工作負載元件,例如 CatalogService
和 BackgroundProcessor
。 HealthService
提供 REST API,Azure Front Door 健康情況檢查會呼叫 以判斷戳記的可用性。 與基本活躍度探查不同,健全狀況服務 是一個更複雜的元件,除了它自己的狀態之外,還提供相依性的狀態。
如果 AKS 叢集關閉,健全狀況服務 不會回應,這會使工作負載狀況不良。 當服務執行時,它會針對解決方案的重要元件執行定期檢查。 所有檢查都會以異步方式和平行方式完成。 如果任何檢查失敗,則無法使用整個戳記。
警告
Azure Front Door 健康情況探查可能會對 健全狀況服務 造成大量負載,因為要求來自多個存在點 (PoP) 位置。 若要防止多載下游元件,請實作有效的快取。
健全狀況服務 也用於使用每個戳記的 Application Insights 資源明確設定的 URL Ping 測試。
如需實作HealthService
的詳細資訊,請參閱應用程式 健全狀況服務。