Checklista för prestandaeffektivitet
Prestandaeffektivitet är möjligheten för din arbetsbelastning att skala för att uppfylla användarnas krav på ett effektivt sätt och är en av grundpelarna i Microsoft Azure Well-Architected Framework. Använd den här checklistan för att granska programarkitekturen ur prestandaeffektivitetssynpunkt.
Programdesign
Partitionera arbetsbelastningen. Utforma delar av processen så att de är diskreta och delbara. Minimera storleken på varje del samtidigt som du följer de vanliga reglerna för uppdelning av problem och principen om enskilt ansvar. Detta gör att komponentdelarna kan distribueras på ett sätt som maximerar användningen av varje beräkningsenhet (till exempel en roll eller databasserver). Det gör det också enklare att skala programmet genom att lägga till instanser av specifika resurser. Överväg att använda en mikrotjänstarkitektur för komplexa domäner.
Designa för skalning. Skalning gör att program kan reagera på varierande belastning genom att öka och minska antalet instanser av roller, köer och andra tjänster som de använder. Programmet måste dock utformas med detta i åtanke. Till exempel måste programmet och de tjänster som det använder vara tillståndslösa, så att begäranden kan dirigeras till valfri instans. Detta förhindrar också att tillägg eller borttagning av specifika instanser påverkar aktuella användare negativt. Du bör också implementera konfiguration eller automatisk identifiering av instanser när de läggs till och tas bort, så att koden i programmet kan utföra den nödvändiga routningen. Ett webbprogram kan till exempel använda en uppsättning köer i en resursallokeringsmetod för att dirigera begäranden till bakgrundstjänster som körs i arbetsroller. Webbprogrammet måste kunna identifiera ändringar i antalet köer för att kunna dirigera begäranden och balansera belastningen på programmet.
Skala som en enhet. Planera för ytterligare resurser för att hantera tillväxt. För varje resurs bör du känna till de övre skalningsgränserna och använda horisontell partitionering eller nedbrytning för att gå utanför dessa gränser. Fastställ skalningsenheterna för systemet i termer av väldefinierade uppsättningar av resurser. Detta gör det enklare att tillämpa utskalningsåtgärder och mindre känslig för negativ inverkan på programmet genom begränsningar som uppstår på grund av brist på resurser i någon del av det övergripande systemet. Att till exempel lägga till x antal webb- och arbetsroller kan kräva y antal ytterligare köer och z antal lagringskonton för att hantera den extra arbetsbelastning som genererats av rollerna. En skalningsenhet kan därför bestå av x webb- och arbetsroller, y-köer och z lagringskonton. Designa programmet så att det skalas enkelt genom att lägga till en eller flera skalningsenheter. Överväg att använda mönstret distributionsstämplar för att distribuera skalningsenheter.
Undvik klienttillhörighet. Om möjligt bör du se till att programmet inte kräver tillhörighet. Begäranden kan därför dirigeras till vilken instans som helst och antalet instanser är irrelevant. Detta undviker också kostnaderna för att lagra, hämta och underhålla tillståndsinformation för varje användare.
Dra nytta av funktionerna för automatisk skalning av plattformar. Om värdplattformen stöder en funktion för automatisk skalning, till exempel Automatisk skalning i Azure, bör du föredra det framför anpassade mekanismer eller mekanismer från tredje part om inte den inbyggda mekanismen inte kan uppfylla dina krav. Använd schemalagda skalningsregler där det är möjligt för att säkerställa att resurserna är tillgängliga utan startfördröjning, men lägg till reaktiv automatisk skalning i reglerna där det är lämpligt för att hantera oväntade förändringar i efterfrågan. Du kan använda autoskalningsåtgärder i den klassiska distributionsmodellen för att justera autoskalning och lägga till anpassade räknare i regler. Mer information finns i Vägledning för automatisk skalning.
Avlasta processorintensiva och I/O-intensiva uppgifter som bakgrundsaktiviteter. Om en begäran till en tjänst förväntas ta lång tid att köra eller absorbera stora resurser kan du avlasta bearbetningen för den här begäran till en separat uppgift. Använd arbetsroller eller bakgrundsjobb (beroende på värdplattformen) för att utföra dessa uppgifter. Den här strategin gör det möjligt för tjänsten att fortsätta ta emot ytterligare begäranden och fortsätta att svara. Mer information finns i Vägledning för bakgrundsjobb.
Distribuera arbetsbelastningen för bakgrundsaktiviteter. Om det finns många bakgrundsaktiviteter, eller uppgifter som kräver lång tid eller resurser, sprider du arbetet över flera beräkningsenheter (till exempel arbetsroller eller bakgrundsjobb). En möjlig lösning finns i mönstret Konkurrerande konsumenter.
Överväg att gå mot en "shared-nothing"-arkitektur. I en arkitektur med delat ingenting används oberoende, självförsörjande noder som inte har någon enskild punkt för contention (till exempel delade tjänster eller lagring). I teorin kan ett sådant system skalas nästan på obestämd tid. Även om en helt delad inget-metod vanligtvis inte är praktisk för de flesta program, kan det ge möjligheter att designa för bättre skalbarhet. Att till exempel undvika användning av sessionstillstånd på serversidan, klienttillhörighet och datapartitionering är bra exempel på att gå mot en arkitektur med delat ingenting.
Datahantering
Använd datapartitionering. Dela upp data över flera databaser och databasservrar, eller utforma programmet för att använda datalagringstjänster som kan tillhandahålla den här partitionering transparent (exempel är Azure SQL Database elastisk databas och Azure Table Storage). Den här metoden kan hjälpa till att maximera prestanda och underlätta skalning. Det finns olika partitioneringstekniker, till exempel vågräta, lodräta och funktionella. Du kan använda en kombination av dessa för att uppnå maximal nytta av ökad frågeprestanda, enklare skalbarhet, mer flexibel hantering, bättre tillgänglighet och för att matcha typen av lagring med de data som lagras. Överväg också att använda olika typer av datalager för olika typer av data och välja typer baserat på hur väl de är optimerade för den specifika typen av data. Detta kan omfatta användning av tabellagring, en dokumentdatabas eller ett kolumnfamiljedatalager, i stället för eller samt en relationsdatabas. Mer information finns i Vägledning för datapartitionering.
Utforma för slutlig konsekvens. Slutlig konsekvens förbättrar skalbarheten genom att minska eller ta bort den tid som krävs för att synkronisera relaterade data som partitionerats över flera lager. Kostnaden är att data inte alltid är konsekventa när de läses, och vissa skrivåtgärder kan orsaka konflikter. Slutlig konsekvens är perfekt för situationer där samma data läses ofta men skrivs sällan. Mer information finns i Introduktion till datakonsekvens.
Minska trafikknackande interaktioner mellan komponenter och tjänster. Undvik att utforma interaktioner där ett program krävs för att göra flera anrop till en tjänst (som var och en returnerar en liten mängd data), i stället för ett enda anrop som kan returnera alla data. Om möjligt kan du kombinera flera relaterade åtgärder till en enskild begäran när anropet är till en tjänst eller komponent som har märkbar svarstid. Detta gör det enklare att övervaka prestanda och optimera komplexa åtgärder. Du kan till exempel använda lagrade procedurer i databaser för att kapsla in komplex logik och minska antalet turer fram och tillbaka och resurslåsning.
Använd köer för att utjämna belastningen för data som skriver med hög hastighet. Ökningar i efterfrågan på en tjänst kan överbelasta den tjänsten och orsaka eskalerande fel. Överväg att implementera det köbaserade belastningsutjämningsmönstret för att förhindra detta. Använd en kö som fungerar som en buffert mellan en uppgift och en tjänst som den anropar. Detta kan jämna ut tillfälliga tunga belastningar som annars kan leda till att tjänsten misslyckas eller att aktiviteten får en time out.
Minimera belastningen på datalagret. Datalagret är ofta en flaskhals för bearbetning, en kostsam resurs och ofta inte lätt att skala ut. Ta om möjligt bort logik (till exempel bearbetning av XML-dokument eller JSON-objekt) från datalagret och utför bearbetning i programmet. I stället för att exempelvis skicka XML till databasen (förutom som en täckande sträng för lagring) serialiserar eller deserialiserar du XML-filen i programlagret och skickar den i ett formulär som är inbyggt i datalagret. Det är vanligtvis mycket enklare att skala ut programmet än datalagret, så du bör försöka göra så mycket av den beräkningsintensiva bearbetningen som möjligt i programmet.
Minimera mängden data som hämtas. Hämta endast de data du behöver genom att ange kolumner och använda kriterier för att välja rader. Använd tabellvärdeparametrar och lämplig isoleringsnivå. Använd mekanismer som entitetstaggar för att undvika att data hämtas i onödan.
Använd cachelagring aggressivt. Använd cachelagring där det är möjligt för att minska belastningen på resurser och tjänster som genererar eller levererar data. Cachelagring passar vanligtvis för data som är relativt statiska eller som kräver betydande bearbetning för att erhålla. Cachelagring bör ske på alla nivåer där det är lämpligt i varje lager i programmet, inklusive dataåtkomst och generering av användargränssnitt. Mer information finns i Vägledning om cachelagring.
Hantera datatillväxt och kvarhållning. Mängden data som lagras av ett program växer med tiden. Den här tillväxten ökar lagringskostnaderna och svarstiden vid åtkomst till data, vilket påverkar programmets dataflöde och prestanda. Det kan vara möjligt att regelbundet arkivera vissa gamla data som inte längre används, eller flytta data som sällan används till långsiktig lagring som är mer kostnadseffektivt, även om åtkomstfördröjningen är högre.
Optimera dataöverföringsobjekt (DTO: er) med ett effektivt binärt format. DTO:er skickas många gånger mellan lagren i ett program. Genom att minimera storleken minskar belastningen på resurser och nätverket. Balansera dock besparingarna med omkostnaderna för att konvertera data till det format som krävs på varje plats där de används. Använd ett format som har maximal samverkan för att möjliggöra enkel återanvändning av en komponent.
Ange cachekontroll. Utforma och konfigurera programmet till att använda cachelagring av utdata eller fragmentcachelagring där det är möjligt, för att minimera bearbetningsbelastningen.
Aktivera cachelagring på klientsidan. Webbprogram bör aktivera cacheinställningar för det innehåll som kan cachelagras. Detta är vanligtvis inaktiverat som standard. Konfigurera servern att leverera lämpliga cachekontrollhuvuden för att möjliggöra cachelagring av innehåll på proxyservrar och klienter.
Använd Azure Blob Storage och Azure Content Delivery Network för att minska belastningen på programmet. Överväg att lagra statiskt eller relativt statiskt offentligt innehåll, till exempel bilder, resurser, skript och formatmallar, i bloblagring. Den här metoden minskar belastningen som orsakas av att innehållet genereras dynamiskt för varje begäran. Överväg dessutom att använda Content Delivery Network för att cachelagra det här innehållet och leverera det till klienter. Användning av Content Delivery Network kan förbättra prestanda på klienten eftersom innehållet levereras från det geografiskt närmaste datacentret som innehåller en Content Delivery Network cache. Mer information finns i Content Delivery Network vägledning.
Optimera och finjustera SQL frågor och index. Vissa T-SQL-instruktioner eller konstruktioner kan ha en negativ inverkan på prestanda som kan minskas genom att optimera koden i en lagrad procedur. Undvik till exempel att konvertera datetime-typer till ett varchar innan du jämför med ett datetime-literalvärde. Använd jämförelsefunktioner för datum/tid i stället. Brist på lämpliga index kan också göra frågekörningen långsam. Om du använder ett objekt-/relationsmappningsramverk bör du förstå hur det fungerar och hur det kan påverka prestanda för dataåtkomstlagret. Mer information finns i Frågejustering.
Överväg att avmalisera data. Data normalisering hjälper till att undvika duplicering och inkonsekvens. Men att underhålla flera index, söka efter referensintegritet, utföra flera åtkomster till små data segment och koppla tabeller för att sätta ihop data på ett annat sätt medför ett merkostnader som kan påverka prestandan. Överväg om ytterligare lagringsvolym och duplicering är acceptabelt för att minska belastningen på datalagret. Överväg också om själva programmet (som vanligtvis är enklare att skala) kan användas för att ta över uppgifter som att hantera referensintegritet för att minska belastningen på datalagret. Mer information finns i Vägledning för datapartitionering.
Implementering
Granska prestanda antimönster. Se Prestanda antimönster för molnprogram för vanliga metoder som kan orsaka skalbarhetsproblem när ett program är under hög belastning.
Använd asynkrona anrop. Använd asynkron kod när det är möjligt vid åtkomst till resurser eller tjänster som kan begränsas av I/O eller nätverksbandbredd, eller som har en märkbar svarstid, för att undvika att låsa anropstråden.
Undvik att låsa resurser och använd en optimistisk metod i stället. Lås aldrig åtkomsten till resurser som lagring eller andra tjänster som har märkbar fördröjning, eftersom detta är en primär orsak till dåliga prestanda. Använd alltid optimistiska metoder för att hantera samtidiga åtgärder, till exempel skrivning till lagring. Använd funktioner i lagringslagret för att hantera konflikter. I distribuerade program kanske data bara blir konsekventa till slut.
Komprimera mycket komprimerbara data över nätverk med hög latens och låg bandbredd. I de flesta fall i en webbapp är den största mängden data som genereras av programmet och skickas via nätverket HTTP-svar på klientbegäranden. HTTP-komprimering kan minska detta avsevärt, särskilt för statiskt innehåll. Detta kan minska kostnaden och minska belastningen på nätverket, även om komprimering av dynamiskt innehåll innebär en mycket högre belastning på servern. I andra, mer generaliserade miljöer kan datakomprimering minska mängden data som överförs och minimera överföringstiden och kostnaderna, men komprimerings- och dekomprimeringsprocesserna medför kostnader. Därför bör komprimering endast användas när prestandan ökar på ett bevisbart sätt. Andra serialiseringsmetoder, till exempel JSON eller binär kodning, kan minska nyttolastens storlek och samtidigt ha mindre inverkan på prestanda, medan XML troligen kommer att öka den.
Minimera tiden som anslutningar och resurser används. Underhåll endast anslutningar och resurser så länge du behöver använda dem. Du kan till exempel öppna anslutningar så sent som möjligt och tillåta att de returneras till anslutningspoolen så snart som möjligt. Skaffa resurser så sent som möjligt och ta bort dem så snart som möjligt.
Minimera antalet anslutningar som krävs. Tjänstanslutningar absorberar resurser. Begränsa det antal som krävs och se till att befintliga anslutningar återanvänds när det är möjligt. När du har utfört autentiseringen kan du till exempel använda personifiering där det är lämpligt för att köra kod som en specifik identitet. Detta kan hjälpa dig att använda anslutningspoolen på bästa sätt genom att återanvända anslutningar.
Anteckning
API:er för vissa tjänster återanvänder anslutningar automatiskt, förutsatt att tjänstspecifika riktlinjer följs. Det är viktigt att du förstår de villkor som möjliggör återanvändning av anslutningar för varje tjänst som programmet använder.
Skicka begäranden i batchar för att optimera nätverksanvändningen. Du kan till exempel skicka och läsa meddelanden i batchar vid åtkomst till en kö och utföra flera läsningar eller skrivningar som en batch vid åtkomst till lagring eller ett cacheminne. Detta kan bidra till att maximera effektiviteten för tjänster och datalager genom att minska antalet anrop i nätverket.
Undvik krav på att lagra sessionstillstånd på serversidan där det är möjligt. Hantering av sessionstillstånd på serversidan kräver vanligtvis klienttillhörighet (dvs. routning av varje begäran till samma serverinstans), vilket påverkar systemets skalningsförmåga. Vi rekommenderar att du utformar klienterna så att de är tillståndslösa med avseende på de servrar som de använder. Men om programmet måste upprätthålla sessionstillstånd, lagra känsliga data eller stora mängder data per klient i en distribuerad cache på serversidan som alla instanser av programmet kan komma åt.
Optimera scheman för tabellagring. När du använder tabellarkiv som kräver att tabell- och kolumnnamn skickas och bearbetas med varje fråga, till exempel Azure Table Storage, bör du överväga att använda kortare namn för att minska det här arbetet. Dock ska du inte offra läsbarhet eller hanterbarhet genom att använda alltför kompakta namn.
Skapa resursberoenden under distributionen eller vid programstart. Undvik upprepade anrop till metoder som testar förekomsten av en resurs och skapa sedan resursen om den inte finns. Metoder som CloudTable.CreateIfNotExists och CloudQueue.CreateIfNotExists i Azure Storage Client Library följer det här mönstret. Dessa metoder kan medföra betydande omkostnader om de anropas före varje åtkomst till en lagringstabell eller lagringskö. Istället:
- Skapa de resurser som krävs när programmet distribueras eller när det först startar (ett enda anrop till CreateIfNotExists för varje resurs i startkoden för en webb- eller arbetsroll är acceptabelt). Se dock till att hantera undantag som kan uppstå om din kod försöker komma åt en resurs som inte finns. I sådana fall bör du logga undantaget och eventuellt varna en operatör om att en resurs saknas.
- I vissa fall kan det vara lämpligt att skapa den saknade resursen som en del av undantagshanteringskoden. Men du bör använda den här metoden med försiktighet eftersom förekomsten av resursen kan vara en indikation på ett programmeringsfel (till exempel ett felstavat resursnamn) eller något annat problem på infrastrukturnivå.
Använd lätta ramverk. Välj noggrant de API:er och ramverk som du använder för att minimera resursanvändning, körningstid och övergripande belastning på programmet. Att till exempel använda webb-API för att hantera tjänstbegäranden kan minska programmets fotavtryck och öka körningshastigheten, men det kanske inte är lämpligt för avancerade scenarier där ytterligare funktioner i Windows Communication Foundation krävs.
Överväg att minimera antalet tjänstkonton. Du kan till exempel använda ett specifikt konto för att få åtkomst till resurser eller tjänster som inför en gräns för anslutningar eller presterar bättre där färre anslutningar upprätthålls. Den här metoden är vanlig för tjänster som databaser, men den kan påverka möjligheten att granska åtgärder korrekt på grund av personifieringen av den ursprungliga användaren.
Utför prestandaprofilering och belastningstestning under utvecklingen, som en del av testrutinerna och före den slutliga versionen för att säkerställa att programmet fungerar och skalas efter behov. Den här testningen bör ske på samma typ av maskinvara som produktionsplattformen och med samma typer och kvantiteter av data och användarbelastning som den kommer att stöta på i produktion. Mer information finns i Testa prestanda för en molntjänst.