Överväganden för programdesign för verksamhetskritiska arbetsbelastningar
Referensarkitekturen för verksamhetskritisk baslinje använder ett enkelt onlinekatalogprogram för att illustrera en mycket tillförlitlig arbetsbelastning. Användare kan bläddra igenom en katalog med objekt, granska objektinformation och publicera klassificeringar och kommentarer för objekt. Den här artikeln fokuserar på tillförlitlighets- och återhämtningsaspekterna i ett verksamhetskritiskt program, till exempel asynkron bearbetning av begäranden och hur du uppnår högt dataflöde i en lösning.
Viktigt!
En referensimplementering i produktionsklass som visar verksamhetskritisk programutveckling på Azure Support vägledningen i den här artikeln. Du kan använda den här implementeringen som grund för ytterligare lösningsutveckling i ditt första steg mot produktion.
Programmets sammansättning
För storskaliga verksamhetskritiska program måste du optimera arkitekturen för skalbarhet och motståndskraft från slutpunkt till slutpunkt. Du kan dela upp komponenter i funktionella enheter som kan användas oberoende av varandra. Tillämpa den här separationen på alla nivåer i programstacken så att varje del av systemet kan skalas separat och möta förändringar i efterfrågan. Implementeringen visar den här metoden.
Programmet använder tillståndslösa API-slutpunkter som frikopplar långvariga skrivbegäranden asynkront via en meddelandekö. Med arbetsbelastningens sammansättning kan du ta bort och återskapa hela AKS-kluster (Azure Kubernetes Service) och andra beroenden i stämpeln när som helst. De viktigaste komponenterna i programmet är:
Användargränssnitt (UI): Ett ensideswebbprogram som användarna kan komma åt. Användargränssnittet finns på ett Azure Storage-kontos statiska webbplatsvärd.
API (
CatalogService
): Ett REST-API som anropas av UI-programmet men fortfarande är tillgängligt för andra potentiella klientprogram.Arbetare (
BackgroundProcessor
): En bakgrundsarbetare som lyssnar på nya händelser i meddelandebussen och bearbetar skrivbegäranden till databasen. Den här komponenten exponerar inga API:er.Hälsotjänst-API (
HealthService
): Ett API som rapporterar hälsotillståndet för programmet genom att kontrollera om kritiska komponenter fungerar, till exempel databasen eller meddelandebussen.
Arbetsbelastningen består av PROGRAM för API, arbetare och hälsokontroll. Ett dedikerat AKS-namnområde med namnet workload
är värd för arbetsbelastningen som containrar. Ingen direkt kommunikation sker mellan poddarna. Poddarna är tillståndslösa och kan skalas separat.
Andra stödkomponenter som körs i klustret är:
En NGINX-ingresskontrollant: Dirigerar inkommande begäranden till arbetsbelastningen och lastbalanser mellan poddar. NGINX-ingresskontrollanten exponeras via Azure Load Balancer med en offentlig IP-adress men kan bara nås via Azure Front Door.
Cert manager: Jetstacks
cert-manager
TLS-certifikat (Autoprovisions Transport Layer Security) med hjälp av Let's Encrypt för ingressreglerna.CSI-drivrutin för Secrets Store: Azure Key Vault-providern för Secrets Store CSI-drivrutinen läser säkert hemligheter, till exempel anslutningssträng från Key Vault.
Övervakningsagent: Standardkonfigurationen för OMSAgentForLinux justeras för att minska mängden övervakningsdata som skickas till Arbetsytan För Azure Monitor-loggar.
Databasanslutning
På grund av distributionsstämplarnas tillfälliga karaktär bör du undvika att bevara tillståndet inom stämpeln så mycket som möjligt. Du bör bevara tillståndet i ett externaliserat datalager. Skapa ett motståndskraftigt datalager för att stödja servicenivåmålet (SLO) för tillförlitlighet. Vi rekommenderar att du använder hanterade eller plattform som en tjänst (PaaS), lösningar i kombination med interna SDK-bibliotek som automatiskt hanterar timeouter, frånkopplingar och andra feltillstånd.
I referensimplementeringen fungerar Azure Cosmos DB som huvuddatalager för programmet. Azure Cosmos DB tillhandahåller skrivningar i flera regioner. Varje stämpel kan skriva till Azure Cosmos DB-repliken i samma region och Azure Cosmos DB hanterar internt datareplikering och synkronisering mellan regioner. Azure Cosmos DB for NoSQL stöder alla funktioner i databasmotorn.
Mer information finns i Dataplattform för verksamhetskritiska arbetsbelastningar.
Kommentar
Använd Azure Cosmos DB för NoSQL för nya program. För äldre program som använder ett annat NoSQL-protokoll utvärderar du migreringssökvägen till Azure Cosmos DB.
För verksamhetskritiska program som prioriterar tillgänglighet framför prestanda rekommenderar vi skrivåtgärder för en region och läsning i flera regioner med en stark konsekvensnivå .
Den här arkitekturen använder Storage för att tillfälligt lagra tillstånd i stämpeln för Azure Event Hubs-kontrollpunkter.
Alla arbetsbelastningskomponenter använder Azure Cosmos DB .NET Core SDK för att kommunicera med databasen. SDK:n innehåller robust logik för att underhålla databasanslutningar och hantera fel. Viktiga konfigurationsinställningar är:
Direktanslutningsläge: Den här inställningen är standard för .NET SDK v3 eftersom den ger bättre prestanda. Direktanslutningsläget har färre nätverkshopp jämfört med gatewayläge, som använder HTTP.
Returnera innehållssvar vid skrivning: Den här metoden är inaktiverad så att Azure Cosmos DB-klienten inte kan returnera dokumentet från åtgärderna create, upsert och patch and replace, vilket minskar nätverkstrafiken. Ytterligare bearbetning på klienten kräver inte den här inställningen.
Anpassad serialisering: Den här processen anger namngivningsprincipen för JSON-egenskapen till
JsonNamingPolicy.CamelCase
för att översätta .NET-egenskaper till JSON-standardegenskaper. Den kan också översätta JSON-egenskaper till .NET-egenskaper. Standardvillkoret Ignorera ignorerar egenskaper med null-värden, till exempelJsonIgnoreCondition.WhenWritingNull
, under serialiseringen.ApplicationRegion: Den här egenskapen är inställd på stämpelns region, vilket gör att SDK:et kan hitta den närmaste anslutningsslutpunkten. Slutpunkten bör helst finnas i samma region.
Följande kodblock visas i referensimplementeringen:
//
// /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();
Asynkrona meddelanden
När du implementerar lös koppling har tjänsterna inte beroenden för andra tjänster. Den lösa aspekten gör att en tjänst kan fungera oberoende av varandra. Kopplingsaspekten möjliggör kommunikation mellan tjänster via väldefinierade gränssnitt. För ett verksamhetskritiskt program förhindrar lös koppling nedströmsfel från att kaskad till klientdelar eller andra distributionsstämplar, vilket ger hög tillgänglighet.
De viktigaste egenskaperna för asynkrona meddelanden är:
Tjänsterna behöver inte använda samma beräkningsplattform, programmeringsspråk eller operativsystem.
Tjänster skalas oberoende av varandra.
Nedströmsfel påverkar inte klienttransaktioner.
Transaktionsintegriteten är svår att underhålla eftersom dataskapande och beständighet sker i separata tjänster. Transaktionsintegritet är en utmaning för meddelande- och beständighetstjänster. Mer information finns i Idempotent meddelandebearbetning.
Slutpunkt till slutpunkt-spårning kräver komplex orkestrering.
Vi rekommenderar att du använder välkända designmönster, till exempel mönster för köbaserad belastningsutjämning och konkurrerande konsumenter. Dessa mönster distribuerar belastningen från producenten till konsumenterna och aktiverar asynkron bearbetning av konsumenter. Till exempel låter arbetaren API:et acceptera begäran och snabbt återgå till anroparen, och arbetaren bearbetar en databasskrivningsåtgärd separat.
Event Hubs förmedlar meddelanden mellan API:et och arbetaren.
Viktigt!
Använd inte meddelandekoordinatorn som ett beständigt datalager under långa tidsperioder. Event Hubs-tjänsten stöder avbildningsfunktionen. Med avbildningsfunktionen kan en händelsehubb automatiskt skriva en kopia av meddelandena till ett länkat Lagringskonto. Den här processen styr användningen och fungerar som en mekanism för att säkerhetskopiera meddelanden.
Information om implementering av skrivåtgärder
Skrivåtgärder, till exempel postklassificering och inläggskommentare, bearbetas asynkront. API:et skickar först ett meddelande med all relevant information, till exempel typen av åtgärd och kommentarsdata, till meddelandekön och returneras HTTP 202 (Accepted)
omedelbart med Location
rubriken för det objekt som ska skapas.
BackgroundProcessor
instanser bearbetar meddelanden i kön och hanterar den faktiska databaskommunikationen för skrivåtgärder. BackgroundProcessor
skalar in och skalas ut dynamiskt baserat på kömeddelandevolymen. Utskalningsgränsen för processorinstanser definieras av det maximala antalet Event Hubs-partitioner, vilket är 32 för Basic-nivåer och Standard-nivåer, 100 för Premium-nivån och 1 024 för den dedikerade nivån.
Azure Event Hubs-processorbiblioteket i BackgroundProcessor
använder Azure Blob Storage för att hantera partitionsägarskap, belastningsutjämning mellan olika arbetsinstanser och använda kontrollpunkter för att spåra förloppet. Kontrollpunkterna skrivs inte till bloblagring efter varje händelse eftersom det lägger till en dyr fördröjning för varje meddelande. I stället skrivs kontrollpunkterna i en timerloop och du kan konfigurera varaktigheten. Standardinställningen är 10 sekunder.
Följande kodblock visas i referensimplementeringen:
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);
}
}
}
Om processorprogrammet får ett fel eller stoppas innan det kan bearbeta meddelandet:
En annan instans hämtar meddelandet för ombearbetning eftersom det inte var korrekt kontrollpunkt i Storage.
En konflikt uppstår om den tidigare arbetaren bevarade dokumentet i databasen innan arbetaren misslyckades. Det här felet beror på att samma ID och partitionsnyckel används. Processorn kan ignorera meddelandet på ett säkert sätt eftersom dokumentet redan är sparat.
En ny instans upprepar stegen och slutför beständighet om den tidigare arbetaren avslutades innan den skrev till databasen.
Läs information om driftimplementering
API:et bearbetar läsåtgärder direkt och returnerar omedelbart data tillbaka till användaren.
En back-channel-metod upprättas inte för att kommunicera med klienten om åtgärden har slutförts. Klientprogrammet måste proaktivt avsöka API:et efter uppdateringar om objektet som anges i Location
HTTP-huvudet.
Skalbarhet
Enskilda arbetsbelastningskomponenter ska skalas ut separat eftersom varje komponent har olika belastningsmönster. Skalningskraven beror på tjänstens funktioner. Vissa tjänster påverkar användarna direkt och måste skalas ut aggressivt för att säkerställa snabba svar och en positiv användarupplevelse.
Implementeringen paketar tjänsterna som containeravbildningar och använder Helm-diagram för att distribuera tjänsterna till varje stämpel. Tjänsterna är konfigurerade för att ha de förväntade Kubernetes-begärandena och gränserna och en förkonfigurerad regel för automatisk skalning på plats. Komponenterna CatalogService
och arbetsbelastningen BackgroundProcessor
kan skalas in och skalas ut individuellt eftersom båda tjänsterna är tillståndslösa.
Användarna interagerar direkt med CatalogService
, så den här delen av arbetsbelastningen måste svara under all belastning. Det finns minst tre instanser för varje kluster som ska spridas över tre tillgänglighetszoner i en Azure-region. Den vågräta podd-autoskalningen (HPA) i AKS lägger automatiskt till fler poddar efter behov. Autoskalningsfunktionen i Azure Cosmos DB kan dynamiskt öka och minska antalet enheter för begäranden som är tillgängliga för samlingen. CatalogService
Och Azure Cosmos DB kombineras för att bilda en skalningsenhet inom en stämpel.
HPA distribueras med ett Helm-diagram som har ett konfigurerbart maximalt antal och minsta antal repliker. Belastningstestet fastställde att varje instans kan hantera cirka 250 begäranden per sekund med ett standardanvändningsmönster.
Tjänsten BackgroundProcessor
har olika krav och anses vara en bakgrundsarbetare som har en begränsad effekt på användarupplevelsen. Så BackgroundProcessor
har en annan konfiguration för automatisk skalning jämfört CatalogService
med , och den kan skalas mellan 2 och 32 instanser. Fastställ den här gränsen baserat på antalet partitioner som du använder i händelsehubbarna. Du behöver inte fler arbetare än partitioner.
Komponent | minReplicas |
maxReplicas |
---|---|---|
CatalogService | 3 | 20 |
BackgroundProcessor | 2 | 32 |
Varje komponent i arbetsbelastningen som innehåller beroenden som ingress-nginx
har inställningen för poddavbrottsbudgetar (PDB) konfigurerad för att säkerställa att ett minsta antal instanser förblir tillgängliga när kluster ändras.
Följande kodblock visas i referensimplementeringen:
#
# /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 }}
Kommentar
Fastställa det faktiska minsta antalet och det maximala antalet poddar för varje komponent genom belastningstestning. Antalet poddar kan variera för varje arbetsbelastning.
Instrumentation
Använd instrumentation för att utvärdera prestanda flaskhalsar och hälsoproblem som arbetsbelastningskomponenter kan introducera i systemet. För att hjälpa dig att kvantifiera beslut bör varje komponent generera tillräckligt med information via mått och spårningsloggar. Tänk på följande viktiga överväganden när du instrumentera ditt program:
- Skicka loggar, mått och annan telemetri till stämpelns loggsystem.
- Använd strukturerad loggning i stället för oformaterad text så att du kan fråga efter information.
- Implementera händelsekorrelation för att få en transaktionsvy från slutpunkt till slutpunkt. I referensimplementeringen innehåller varje API-svar ett åtgärds-ID som ett HTTP-huvud för spårning.
- Förlita dig inte bara på stdout-loggning eller konsolloggning. Men du kan använda dessa loggar för att omedelbart felsöka en podd som inte fungerar.
Den här arkitekturen implementerar distribuerad spårning med Application Insights och en Azure Monitor Logs-arbetsyta för programövervakningsdata. Använd Azure Monitor-loggar för loggar och mått för arbetsbelastnings- och infrastrukturkomponenter. Den här arkitekturen implementerar fullständig spårning från slutpunkt till slutpunkt av begäranden som kommer från API:et, går via Event Hubs och sedan till Azure Cosmos DB.
Viktigt!
Distribuera stämpelövervakningsresurser till en separat övervakningsresursgrupp. Resurserna har en annan livscykel än själva stämpeln. Mer information finns i Övervakningsdata för stämpelresurser.
Information om implementering av programövervakning
Komponenten BackgroundProcessor
använder Microsoft.ApplicationInsights.WorkerService
NuGet-paketet för att hämta färdiga instrumentation från programmet. Serilog används också för all loggning i programmet. Application Insights konfigureras som en mottagare utöver konsolmottagaren. En TelemetryClient
instans av Application Insights används endast direkt när det är nödvändigt att spåra andra mått.
Följande kodblock visas i referensimplementeringen:
//
// /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();
}
För att demonstrera praktisk spårning av begäran returnerar varje lyckad och misslyckad API-begäran korrelations-ID-huvudet till anroparen. Programsupportteamet kan söka i Application Insights med den här identifieraren och få en detaljerad vy över den fullständiga transaktionen, vilket visas i föregående diagram.
Följande kodblock visas i referensimplementeringen:
//
// /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();
});
Kommentar
Anpassningsbar sampling är aktiverat som standard i Application Insights SDK. Anpassningsbar sampling innebär att inte alla begäranden skickas till molnet och kan sökas efter ID. Verksamhetskritiska programteam måste på ett tillförlitligt sätt spåra varje begäran, varför referensimplementeringen har anpassningsbar sampling inaktiverad i produktionsmiljön.
Information om kubernetes-övervakningsimplementering
Du kan använda diagnostikinställningar för att skicka AKS-loggar och -mått till Azure Monitor-loggar. Du kan också använda containerinsiktsfunktionen med AKS. Aktivera containerinsikter för att distribuera OMSAgentForLinux via en Kubernetes DaemonSet på var och en av noderna i AKS-kluster. OMSAgentForLinux kan samla in fler loggar och mått inifrån Kubernetes-klustret och skicka dem till motsvarande Arbetsyta för Azure Monitor-loggar. Den här arbetsytan innehåller detaljerade data om poddar, distributioner, tjänster och klustrets övergripande hälsa.
Omfattande loggning kan påverka kostnaderna negativt och ger inte några fördelar. Därför inaktiveras stdout-loggsamlingen och Prometheus-skrapningen för arbetsbelastningspoddar i containerinsiktskonfigurationen eftersom alla spårningar redan samlas in via Application Insights, vilket genererar dubbletter av poster.
Följande kodblock visas i referensimplementeringen:
#
# /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"]
Mer information finns i den fullständiga konfigurationsfilen.
Övervakning av programhälsa
Du kan använda programövervakning och observerbarhet för att snabbt identifiera systemproblem och informera hälsomodellen om det aktuella programtillståndet. Du kan övervaka hälsotillståndet via hälsoslutpunkter. Hälsoavsökningar använder hälsoövervakningsdata för att tillhandahålla information. Huvudlastbalanseraren använder den informationen för att omedelbart ta bort den felaktiga komponenten från rotationen.
Den här arkitekturen tillämpar hälsoövervakning på följande nivåer:
Arbetsbelastningspoddar som körs på AKS. Dessa poddar har hälso- och liveness-avsökningar, så AKS kan hantera sin livscykel.
Hälsotjänst, som är en dedikerad komponent i klustret. Azure Front Door har konfigurerats för att avsöka Hälsotjänst i varje stämpel och ta bort felstämplar från automatisk belastningsutjämning.
Hälsotjänst implementeringsinformation
HealthService
är en arbetsbelastningskomponent som körs tillsammans med andra komponenter, till exempel CatalogService
och BackgroundProcessor
, i beräkningsklustret. HealthService
tillhandahåller ett REST-API som Azure Front Door-hälsokontroll anropar för att fastställa tillgängligheten för en stämpel. Till skillnad från grundläggande liveness-avsökningar är Hälsotjänst en mer komplex komponent som ger beroendens tillstånd utöver sitt eget tillstånd.
Hälsotjänst svarar inte om AKS-klustret är nere, vilket gör arbetsbelastningen inte felfri. När tjänsten körs utför den regelbundna kontroller mot kritiska komponenter i lösningen. Alla kontroller görs asynkront och parallellt. Om någon av kontrollerna misslyckas är hela stämpeln inte tillgänglig.
Varning
Azure Front Door-hälsoavsökningar kan medföra betydande belastning på Hälsotjänst eftersom begäranden kommer från flera platser (PoP). Om du vill förhindra överlagring av underordnade komponenter implementerar du effektiv cachelagring.
Hälsotjänst används också för explicit konfigurerade URL-pingtester med varje stämpels Application Insights-resurs.
Mer information om implementeringen finns i HealthService
Program Hälsotjänst.