Tillfällig felhantering

Alla program som kommunicerar med fjärrtjänster och -resurser måste vara känsliga för tillfälliga fel. Detta gäller särskilt för program som körs i molnet, där den här typen av fel troligen kommer att uppstå oftare på grund av miljöns och anslutningens natur via Internet. Tillfälliga fel omfattar tillfällig förlust av nätverksanslutning till komponenter och tjänster, tillfällig otillgänglighet för en tjänst och tidsgränser som inträffar när en tjänst är upptagen. Dessa fel är ofta självkorrigering, så om åtgärden upprepas efter en lämplig fördröjning kommer den sannolikt att lyckas.

Den här artikeln innehåller allmänna riktlinjer för tillfällig felhantering. Information om hur du hanterar tillfälliga fel när du använder Azure-tjänster finns i Återförsöksvägledning för Azure-tjänster.

Varför uppstår tillfälliga fel i molnet?

Tillfälliga fel kan uppstå i alla miljöer, på alla plattformar eller operativsystem, samt i alla typer av program. För lösningar som körs på lokal infrastruktur underhålls vanligtvis programmets prestanda och tillgänglighet och dess komponenter via dyr och ofta underanvänd maskinvaruredundans, och komponenter och resurser finns nära varandra. Den här metoden gör fel mindre sannolika, men tillfälliga fel kan fortfarande inträffa, liksom avbrott som orsakas av oförutsedda händelser som extern strömförsörjning eller nätverksproblem eller andra katastrofscenarier.

Molnvärdtjänster, inklusive privata molnsystem, kan erbjuda högre övergripande tillgänglighet med hjälp av delade resurser, redundans, automatisk redundans och dynamisk resursallokering över många beräkningsnoder för råvaror. På grund av molnmiljöernas natur är det dock mer sannolikt att tillfälliga fel inträffar. Det finns flera orsaker till detta:

  • Många resurser i en molnmiljö delas och åtkomsten till dessa resurser begränsas för att skydda resurserna. Vissa tjänster nekar anslutningar när belastningen stiger till en viss nivå, eller när en maximal dataflödeshastighet nås, för att tillåta bearbetning av befintliga begäranden och för att upprätthålla tjänstens prestanda för alla användare. Begränsning hjälper till att upprätthålla tjänstens kvalitet för grannar och andra klienter som använder den delade resursen.

  • Molnmiljöer använder ett stort antal maskinvaruenheter för råvaror. De ger prestanda genom att dynamiskt distribuera belastning över flera beräkningsenheter och infrastrukturkomponenter. De ger tillförlitlighet genom att automatiskt återanvända eller ersätta misslyckade enheter. På grund av den här dynamiska karaktären kan tillfälliga fel och tillfälliga anslutningsfel ibland inträffa.

  • Det finns ofta fler maskinvarukomponenter, inklusive nätverksinfrastruktur som routrar och lastbalanserare, mellan programmet och de resurser och tjänster som används. Den här ytterligare infrastrukturen kan ibland medföra längre svarstid för anslutningar och tillfälliga anslutningsfel.

  • Nätverksvillkoren mellan klienten och servern kan vara varierande, särskilt när kommunikationen passerar internet. Även på lokala platser kan tung trafikbelastning sakta ned kommunikationen och orsaka tillfälliga anslutningsfel.

Utmaningar

Tillfälliga fel kan ha stor inverkan på den upplevda tillgängligheten för ett program, även om det har testats noggrant under alla förutsebara omständigheter. För att säkerställa att molnbaserade program fungerar tillförlitligt måste du se till att de kan svara på följande utmaningar:

  • Programmet måste kunna identifiera fel när de inträffar och avgöra om felen sannolikt är tillfälliga, är långvariga eller är terminalfel. Olika resurser returnerar sannolikt olika svar när ett fel inträffar, och dessa svar kan också variera beroende på åtgärdens kontext. Till exempel kan svaret på ett fel när programmet läser från lagring skilja sig från svaret på ett fel när det skrivs till lagring. Många resurser och tjänster har väldokumenterade avtal om tillfälliga fel. Men när sådan information inte är tillgänglig kan det vara svårt att identifiera felets art och om det är troligt att det är tillfälligt.

  • Programmet måste kunna försöka utföra åtgärden igen om det fastställer att felet sannolikt är tillfälligt. Den måste också hålla reda på hur många gånger åtgärden görs på nytt.

  • Programmet måste använda en lämplig strategi för återförsök. Strategin anger hur många gånger programmet ska försöka igen, fördröjningen mellan varje försök och de åtgärder som ska utföras efter ett misslyckat försök. Det lämpliga antalet försök och fördröjningen mellan var och en är ofta svåra att avgöra. Strategin varierar beroende på resurstyp och aktuella driftsvillkor för resursen och programmet.

Allmänna riktlinjer

Följande riktlinjer kan hjälpa dig att utforma lämpliga mekanismer för tillfällig felhantering för dina program.

Kontrollera om det finns en inbyggd mekanism för återförsök

  • Många tjänster tillhandahåller ett SDK eller klientbibliotek som innehåller en mekanism för hantering av tillfälliga fel. Återförsöksprincipen anpassas vanligtvis utifrån måltjänstens typ och krav. Alternativt kan REST-gränssnitt för tjänster returnera information som kan hjälpa dig att avgöra om ett nytt försök är lämpligt och hur lång tid det tar att vänta innan nästa återförsök.

  • Du bör använda den inbyggda mekanismen för återförsök när en är tillgänglig, såvida du inte har specifika och väl förstådda krav som gör ett annat återförsöksbeteende mer lämpligt.

Kontrollera om åtgärden är lämplig för att försöka igen

  • Utför endast återförsöksåtgärder när felen är tillfälliga (vilket vanligtvis anges av typen av fel) och när det finns åtminstone en viss sannolikhet för att åtgärden kommer att lyckas när den görs om. Det är ingen idé att försöka utföra åtgärder igen som försöker utföra en ogiltig åtgärd, till exempel en databasuppdatering av ett objekt som inte finns eller en begäran till en tjänst eller resurs som har drabbats av ett allvarligt fel.

  • I allmänhet implementerar du bara återförsök när du kan fastställa den fulla effekten av att göra det och när villkoren är väl förstådda och kan valideras. Annars kan anropande kod implementera återförsök. Kom ihåg att felen som returneras från resurser och tjänster utanför din kontroll kan utvecklas över tid, och du kan behöva gå tillbaka till logiken för övergående felidentifiering.

  • När du skapar tjänster eller komponenter bör du överväga att implementera felkoder och meddelanden som hjälper klienter att avgöra om de ska försöka utföra misslyckade åtgärder igen. Ange i synnerhet om klienten ska försöka utföra åtgärden igen (kanske genom att returnera ett isTransient-värde ) och föreslå en lämplig fördröjning före nästa återförsök. Om du skapar en webbtjänst kan du överväga att returnera anpassade fel som definieras i dina tjänstkontrakt. Även om generiska klienter kanske inte kan läsa dessa fel är de användbara när anpassade klienter skapas.

Fastställa ett lämpligt antal återförsök och intervall

  • Optimera antalet återförsök och intervallet till typen av användningsfall. Om du inte försöker igen tillräckligt många gånger kan programmet inte slutföra åtgärden och kommer förmodligen att misslyckas. Om du försöker igen för många gånger, eller med för kort intervall mellan försök, kan programmet innehålla resurser som trådar, anslutningar och minne under långa perioder, vilket påverkar programmets hälsa negativt.

  • Anpassa värden för tidsintervallet och antalet återförsök till typen av åtgärd. Om åtgärden till exempel är en del av en användarinteraktion bör intervallet vara kort och endast ett fåtal återförsök ska försökas. Med den här metoden kan du undvika att få användarna att vänta på ett svar som innehåller öppna anslutningar och kan minska tillgängligheten för andra användare. Om åtgärden ingår i ett långvarigt eller kritiskt arbetsflöde, där det är dyrt eller tidskrävande att avbryta och starta om processen, är det lämpligt att vänta längre mellan försöken och försöka igen fler gånger.

  • Tänk på att det är svårast att fastställa lämpliga intervall mellan återförsök för att utforma en lyckad strategi. Vanliga strategier använder följande typer av intervall för återförsök:

    • Exponentiell backoff. Programmet väntar en kort tid innan det första återförsöket och ökar sedan exponentiellt tiden mellan varje efterföljande återförsök. Den kan till exempel försöka utföra åtgärden igen efter 3 sekunder, 12 sekunder, 30 sekunder och så vidare.

    • Inkrementella intervall. Programmet väntar en kort tid innan det första återförsöket och ökar sedan inkrementellt tiden mellan varje efterföljande återförsök. Den kan till exempel försöka utföra åtgärden igen efter 3 sekunder, 7 sekunder, 13 sekunder och så vidare.

    • Regelbundna intervall. Programmet väntar samma tid mellan varje återförsök. Den kan till exempel försöka utföra åtgärden igen var 3:e sekund.

    • Omedelbart återförsök. Ibland är ett tillfälligt fel kort, vilket kan orsakas av en händelse som en kollision med nätverkspaket eller en topp i en maskinvarukomponent. I det här fallet är det lämpligt att försöka utföra åtgärden igen omedelbart eftersom det kan lyckas om felet rensas under den tid det tar för programmet att montera och skicka nästa begäran. Det får dock aldrig göras fler än ett omedelbart återförsök. Du bör växla till alternativa strategier, till exempel exponentiell säkerhetskopiering eller återställningsåtgärder, om det omedelbara återförsöket misslyckas.

    • Slumpmässighet. Någon av de återförsöksstrategier som anges tidigare kan innehålla en slumpmässighet för att förhindra att flera instanser av klienten skickar efterföljande återförsök samtidigt. En instans kan till exempel försöka utföra åtgärden igen efter 3 sekunder, 11 sekunder, 28 sekunder och så vidare, medan en annan instans kan försöka utföra åtgärden igen efter 4 sekunder, 12 sekunder, 26 sekunder och så vidare. Randomisering är en användbar teknik som kan kombineras med andra strategier.

  • Som en allmän riktlinje använder du en exponentiell back-off-strategi för bakgrundsåtgärder och använder omedelbara eller regelbundna återförsöksstrategier för intervall för interaktiva åtgärder. I båda fallen bör du välja fördröjning och antal försök så att den maximala svarstiden för alla antal återförsök ligger inom det obligatoriska svarstidskravet för slutpunkt till slutpunkt.

  • Ta hänsyn till kombinationen av alla faktorer som bidrar till den totala maximala tidsgränsen för en ny åtgärd. Dessa faktorer inkluderar den tid det tar för en misslyckad anslutning att generera ett svar (vanligtvis inställt med ett timeout-värde i klienten), fördröjningen mellan återförsök och det maximala antalet återförsök. Summan av alla dessa gånger kan resultera i långa totala åtgärdstider, särskilt när du använder en strategi för exponentiell fördröjning där intervallet mellan återförsök växer snabbt efter varje fel. Om en process måste uppfylla ett specifikt serviceavtal (SLA) måste den totala drifttiden, inklusive alla tidsgränser och fördröjningar, ligga inom de gränser som definieras i serviceavtalet.

  • Implementera inte alltför aggressiva återförsöksstrategier. Det här är strategier som har intervall som är för korta eller återförsök som är för frekventa. De kan ha en negativ effekt på målresursen eller -tjänsten. De här strategierna kan hindra resursen eller tjänsten från att återställas från dess överlagrade tillstånd, och den fortsätter att blockera eller avvisa begäranden. Det här scenariot resulterar i en ond cirkel, där fler och fler begäranden skickas till resursen eller tjänsten. Följaktligen minskar dess förmåga att återhämta sig ytterligare.

  • Ta hänsyn till tidsgränsen för åtgärderna när du väljer återförsöksintervall för att undvika att starta ett efterföljande försök omedelbart (till exempel om tidsgränsen liknar återförsöksintervallet). Fundera också på om du behöver behålla den totala möjliga perioden (tidsgränsen plus återförsöksintervallen) under en viss total tid. Om en åtgärd har en ovanligt kort eller lång tidsgräns kan tidsgränsen påverka hur lång tid det tar att vänta och hur ofta åtgärden ska utföras igen.

  • Använd typen av undantag och alla data som det innehåller, eller felkoderna och meddelandena som returneras från tjänsten, för att optimera antalet återförsök och intervallet mellan dem. Vissa undantag eller felkoder (till exempel HTTP-koden 503, Tjänsten är inte tillgänglig, med ett återförsökshuvud i svaret) kan till exempel indikera hur länge felet kan vara eller att tjänsten misslyckades och inte svarar på något efterföljande försök.

Undvik antimönster

  • I de flesta fall bör du undvika implementeringar som innehåller duplicerade lager med återförsökskod. Undvik design som omfattar sammanhängande mekanismer för återförsök eller som implementerar återförsök i varje steg i en åtgärd som omfattar en hierarki med begäranden, såvida du inte har specifika krav som kräver att du gör det. I dessa undantagsfall använder du principer som förhindrar överdrivna antal återförsök och fördröjningstider, och ser till att du förstår konsekvenserna. Anta till exempel att en komponent skickar en begäran till en annan, som sedan kommer åt måltjänsten. Om du implementerar återförsök med antalet tre för båda anropen görs totalt nio återförsök mot tjänsten. Många tjänster och resurser implementerar en inbyggd mekanism för återförsök. Du bör undersöka hur du kan inaktivera eller ändra dessa mekanismer om du behöver implementera återförsök på en högre nivå.

  • Implementera aldrig en oändlig mekanism för återförsök. Detta kommer sannolikt att hindra resursen eller tjänsten från att återställas från överbelastningssituationer och orsaka att begränsningar och nekade anslutningar fortsätter under en längre tid. Använd ett begränsat antal återförsök eller implementera ett mönster som Kretsbrytare så att tjänsten kan återställas.

  • Utför aldrig ett omedelbart återförsök mer än en gång.

  • Undvik att använda ett regelbundet återförsöksintervall när du får åtkomst till tjänster och resurser i Azure, särskilt när du har ett stort antal återförsök. Den bästa metoden i det här scenariot är en exponentiell back-off-strategi med en kretsbrytande funktion.

  • Förhindra att flera instanser av samma klient, eller flera instanser av olika klienter, skickar återförsök samtidigt. Om det här scenariot sannolikt inträffar introducerar du randomisering i återförsöksintervallen.

Testa din återförsöksstrategi och implementering

  • Testa omprövningsstrategin fullständigt under en så bred uppsättning omständigheter som möjligt, särskilt när både programmet och målresurserna eller tjänsterna som används är under extrem belastning. Om du vill kontrollera beteende under testningen kan du:

    • Mata in tillfälliga och icke-övergående fel i tjänsten. Skicka till exempel ogiltiga begäranden eller lägg till kod som identifierar testbegäranden och svarar med olika typer av fel. Exempel som använder TestApi finns i Felinmatningstestning med TestApi och Introduktion till TestApi – del 5: API:er för hanterad kodfelinmatning.

    • Skapa en modell av resursen eller tjänsten som returnerar ett antal fel som den verkliga tjänsten kan returnera. Ta upp alla typer av fel som din strategi för återförsök är utformad för att identifiera.

    • För anpassade tjänster som du skapar och distribuerar tvingar du tillfälliga fel att inträffa genom att tillfälligt inaktivera eller överbelasta tjänsten. (Försök inte överbelasta några delade resurser eller delade tjänster i Azure.)

    • För HTTP-baserade API:er bör du överväga att använda ett bibliotek i dina automatiserade tester för att ändra resultatet av HTTP-begäranden, antingen genom att lägga till extra tur och retur-tider eller genom att ändra svaret (t.ex. HTTP-statuskod, rubriker, brödtext eller andra faktorer). Detta möjliggör deterministisk testning av en delmängd av felvillkoren, för tillfälliga fel och andra typer av fel.

    • Utför hög belastningsfaktor och samtidiga tester för att säkerställa att återförsöksmekanismen och strategin fungerar korrekt under dessa förhållanden. Dessa tester hjälper också till att säkerställa att återförsöket inte har en negativ effekt på klientens drift eller orsakar korskontaminering mellan begäranden.

Hantera principkonfigurationer för återförsök

  • En återförsöksprincip är en kombination av alla element i din återförsöksstrategi. Den definierar identifieringsmekanismen som avgör om ett fel sannolikt kommer att vara tillfälligt, vilken typ av intervall som ska användas (till exempel vanlig, exponentiell back-off och slumpmässighet), faktiska intervallvärden och antalet gånger som återförsök ska göras.

  • Implementera återförsök på många platser, även i det enklaste programmet, och i varje lager av mer komplexa program. I stället för att hårdkoda elementen i varje princip på flera platser bör du överväga att använda en central punkt för att lagra alla principer. Du kan till exempel lagra värden som intervall och återförsök i programkonfigurationsfiler, läsa dem vid körning och programmatiskt skapa återförsöksprinciperna. Det gör det enklare att hantera inställningarna och ändra och finjustera värdena för att svara på ändrade krav och scenarier. Utforma dock systemet för att lagra värdena i stället för att läsa om en konfigurationsfil varje gång och använd lämpliga standardvärden om värdena inte kan hämtas från konfigurationen.

  • I ett Azure Cloud Services-program bör du överväga att lagra de värden som används för att skapa återförsöksprinciper vid körning i tjänstkonfigurationsfilen så att du kan ändra dem utan att behöva starta om programmet.

  • Dra nytta av inbyggda eller standardmässiga återförsöksstrategier som är tillgängliga i de klient-API:er som du använder, men bara när de är lämpliga för ditt scenario. Dessa strategier är vanligtvis allmänna. I vissa scenarier kan de vara allt du behöver, men i andra scenarier erbjuder de inte alla alternativ som passar dina specifika krav. För att fastställa de lämpligaste värdena måste du utföra tester för att förstå hur inställningarna påverkar ditt program.

Logga och spåra tillfälliga och icke-övergående fel

  • Som en del av din strategi för återförsök kan du inkludera undantagshantering och annan instrumentering som loggar återförsök. Ett tillfälligt tillfälligt fel och återförsök förväntas och tyder inte på något problem. Regelbundna och ökande antal återförsök är dock ofta en indikator på ett problem som kan orsaka ett fel eller som försämrar programmets prestanda och tillgänglighet.

  • Logga tillfälliga fel som varningsposter i stället för som felposter så att övervakningssystemen inte identifierar dem som programfel som kan utlösa falska aviseringar.

  • Överväg att lagra ett värde i dina loggposter som anger om återförsök orsakas av begränsning i tjänsten eller av andra typer av fel, till exempel anslutningsfel, så att du kan särskilja dem vid analys av data. En ökning av antalet begränsningsfel är ofta ett tecken på ett utformningsfel i programmet eller på ett behov av att byta till en premiumtjänst som erbjuder dedikerad maskinvara.

  • Överväg att mäta och logga de övergripande förflutna tiderna för åtgärder som innehåller en återförsöksmekanism. Det här måttet är en bra indikator på den övergripande effekten av tillfälliga fel på användarens svarstider, processfördröjning och effektiviteten i programanvändningsfall. Logga också antalet återförsök som inträffar så att du kan förstå de faktorer som bidrar till svarstiden.

  • Överväg att implementera ett telemetri- och övervakningssystem som kan generera aviseringar när antalet och felfrekvensen, det genomsnittliga antalet återförsök eller de totala tiderna som förflutit innan åtgärderna lyckas ökar.

Hantera åtgärder som kontinuerligt misslyckas

  • Överväg hur du hanterar åtgärder som fortsätter att misslyckas vid varje försök. Situationer som denna är oundvikliga.

    • Även om en återförsöksstrategi definierar det maximala antalet gånger som en åtgärd ska utföras igen, hindrar den inte programmet från att upprepa åtgärden igen med samma antal återförsök. Om en orderbearbetningstjänst till exempel misslyckas med ett allvarligt fel som gör att den inte fungerar permanent kan återförsöksstrategin identifiera en tidsgräns för anslutningen och betrakta den som ett tillfälligt fel. Koden försöker utföra åtgärden igen ett angivet antal gånger och ger sedan upp. Men när en annan kund lägger en beställning görs åtgärden igen, även om den misslyckas varje gång.

    • För att förhindra kontinuerliga återförsök för åtgärder som kontinuerligt misslyckas bör du överväga att implementera kretsbrytarmönstret. När du använder det här mönstret, om antalet fel inom ett angivet tidsfönster överskrider ett tröskelvärde, återgår begäranden till anroparen omedelbart som fel och det görs inga försök att komma åt den misslyckade resursen eller tjänsten.

    • Programmet kan regelbundet testa tjänsten, tillfälligt och med långa intervall mellan begäranden, för att identifiera när den blir tillgänglig. Ett lämpligt intervall beror på faktorer som åtgärdens allvarlighetsgrad och tjänstens art. Det kan vara något mellan några minuter och flera timmar. När testet lyckas kan programmet återuppta normala åtgärder och skicka begäranden till den nyligen återställda tjänsten.

    • Under tiden kanske du kan återgå till en annan instans av tjänsten (kanske i ett annat datacenter eller program), använda en liknande tjänst som erbjuder kompatibla (kanske enklare) funktioner eller utföra några alternativa åtgärder baserat på förhoppningen att tjänsten snart kommer att vara tillgänglig. Det kan till exempel vara lämpligt att lagra begäranden för tjänsten i en kö eller ett datalager och försöka igen senare. Eller så kanske du kan omdirigera användaren till en alternativ instans av programmet, försämra programmets prestanda men ändå erbjuda godtagbara funktioner eller bara returnera ett meddelande till användaren för att ange att programmet inte är tillgängligt för närvarande.

Övriga beaktanden

  • När du bestämmer dig för värdena för antalet återförsök och återförsöksintervallen för en princip bör du överväga om åtgärden på tjänsten eller resursen är en del av en långvarig åtgärd eller flera steg. Det kan vara svårt eller dyrt att kompensera alla andra operativa steg som redan har slutförts när en misslyckas. I det här fallet kan ett mycket långt intervall och ett stort antal återförsök vara godtagbara så länge strategin inte blockerar andra åtgärder genom att hålla eller låsa knappa resurser.

  • Fundera på om ett nytt försök med samma åtgärd kan orsaka inkonsekvenser i data. Om vissa delar av en process med flera steg upprepas och åtgärderna inte är idempotenter kan inkonsekvenser uppstå. Om till exempel en åtgärd som ökar ett värde upprepas ger den ett ogiltigt resultat. Att upprepa en åtgärd som skickar ett meddelande till en kö kan orsaka inkonsekvens i meddelandekonsumenten om konsumenten inte kan identifiera duplicerade meddelanden. Du kan förhindra dessa scenarier genom att utforma varje steg som en idempotent åtgärd. Mer information finns i Idempotensmönster.

  • Överväg omfånget för åtgärder som görs om. Det kan till exempel vara enklare att implementera återförsökskod på en nivå som omfattar flera åtgärder och försöka igen om en misslyckas. Detta kan dock leda till problem med idempotens eller onödiga återställningsåtgärder.

  • Om du väljer ett omfång för återförsök som omfattar flera åtgärder ska du ta hänsyn till den totala svarstiden för alla när du fastställer återförsöksintervall, när du övervakar de förflutna tiderna för åtgärden och innan du skapar aviseringar om fel.

  • Fundera på hur din strategi för återförsök kan påverka grannar och andra klienter i ett delat program och när du använder delade resurser och tjänster. Aggressiva principer för återförsök kan orsaka att ett större antal tillfälliga fel inträffar för dessa andra användare och för program som delar resurserna och tjänsterna. På samma sätt kan ditt program påverkas av de återförsöksprinciper som implementeras av andra användare av resurserna och tjänsterna. För affärskritiska program kanske du vill använda premiumtjänster som inte delas. På så sätt får du mer kontroll över belastningen och den efterföljande begränsningen av dessa resurser och tjänster, vilket kan bidra till att motivera den extra kostnaden.