När du använder en så småningom konsekvent åtgärd som består av en serie steg kan mönstret Kompenserande transaktion vara användbart. Om ett eller flera av stegen misslyckas kan du använda mönstret Kompenserande transaktion för att ångra det arbete som stegen utförde. Vanligtvis hittar du åtgärder som följer den slutliga konsekvensmodellen i molnbaserade program som implementerar komplexa affärsprocesser och arbetsflöden.
Kontext och problem
Program som körs i molnet ändrar ofta data. Dessa data sprids ibland över olika datakällor på olika geografiska platser. För att undvika konkurrens och förbättra prestanda i en distribuerad miljö, bör stark transaktionskonsekvens undvikas av ett program. I stället bör eventuell konsekvens implementeras av programmet. I den slutliga konsekvensmodellen består en typisk affärsåtgärd av en serie separata steg. Även om åtgärden utför de här stegen kan den övergripande vyn av systemtillståndet vara inkonsekvent. Men när åtgärden är klar och alla steg har körts bör systemet bli konsekvent igen.
Primer för datakonsekvens innehåller information om varför distribuerade transaktioner inte skalar bra. Den här resursen visar också principer för den slutliga konsekvensmodellen.
En utmaning i den slutliga konsekvensmodellen är hur du hanterar ett steg som misslyckas. Efter ett fel kan du behöva ångra allt arbete som tidigare steg i åtgärden slutfördes. Du kan dock inte alltid återställa data eftersom andra samtidiga instanser av programmet kan ha ändrat dem. Även om samtidiga instanser inte har ändrat data kan det vara mer komplext att ångra ett steg än att återställa det ursprungliga tillståndet. Det kan vara nödvändigt att tillämpa olika affärsspecifika regler. Ett exempel finns på resewebbplatsen som beskrivs senare i den här artikeln i avsnittet Exempel .
Om en åtgärd som implementerar eventuell konsekvens sträcker sig över flera heterogena datalager måste du i tur och ordning gå till varje datalager för att ångra stegen i åtgärden. För att förhindra att systemet förblir inkonsekvent måste du på ett tillförlitligt sätt ångra det arbete som du utförde i varje datalager.
De data som påverkas av en åtgärd som implementerar eventuell konsekvens lagras inte alltid i en databas. Tänk dig till exempel en tjänstorienterad arkitekturmiljö (SOA). En SOA-åtgärd kan anropa en åtgärd i en tjänst och orsaka en ändring i tillståndet som innehas av den tjänsten. Om du vill ångra åtgärden måste du också ångra den här tillståndsändringen. Den här processen kan innebära att du anropar tjänsten igen och utför en annan åtgärd som upphäver effekterna av den första.
Lösning
Lösningen är att implementera en kompenserande transaktion. Stegen i en kompenserande transaktion ångrar effekterna av stegen i den ursprungliga åtgärden. En intuitiv metod är att ersätta det aktuella tillståndet med det tillstånd som systemet befann sig i i början av åtgärden. Men en kompenserande transaktion kan inte alltid använda den metoden eftersom den kan skriva över ändringar som andra samtidiga instanser av ett program har gjort. I stället måste en kompenserande transaktion vara en intelligent process som tar hänsyn till allt arbete som samtidiga instanser utför. Den här processen är vanligtvis programspecifik och drivs av det arbete som den ursprungliga åtgärden utför.
En vanlig metod är att använda ett arbetsflöde för att implementera en eventuell konsekvens-åtgärd som kräver kompensation. När den ursprungliga åtgärden fortsätter registrerar systemet information om varje steg, inklusive hur du ångrar det arbete som steget utför. Om åtgärden misslyckas någon gång spolas arbetsflödet tillbaka genom de steg som har slutförts. I varje steg utför arbetsflödet det arbete som vänder det steget.
Två viktiga punkter är:
- En kompenserande transaktion kanske inte behöver ångra arbetet i den exakta omvända ordningen för den ursprungliga åtgärden.
- Det kan vara möjligt att utföra några av ångra-stegen parallellt.
Den här metoden liknar Sagas-strategin som beskrivs i Clemens Vasters blogg.
En kompenserande transaktion är en så småningom konsekvent åtgärd, så den kan också misslyckas. Systemet bör kunna återuppta den kompenserande transaktionen där felet inträffade och fortsätta. Det kan vara nödvändigt att upprepa ett steg som misslyckas, så du bör definiera stegen i en kompenserande transaktion som idempotent-kommandon. Mer information finns i Idempotensmönster på Jonathan Olivers blogg.
I vissa fall kan manuella åtgärder vara det enda sättet att återställa från ett steg som har misslyckats. I dessa situationer bör systemet skapa en avisering och tillhandahålla så mycket information som möjligt om orsaken till felet.
Problem och överväganden
Tänk på följande när du bestämmer dig för hur du implementerar det här mönstret:
Det är kanske inte lätt att avgöra när ett steg i en åtgärd som implementerar eventuell konsekvens misslyckas. Ett steg kanske inte misslyckas omedelbart. I stället kan den blockeras. Du kan behöva implementera en timeout-mekanism.
Det är inte lätt att generalisera kompensationslogik. En kompenserande transaktion är programspecifik. Den är beroende av att programmet innehåller tillräckligt med information för att kunna ångra effekterna av varje steg i en misslyckad åtgärd.
Kompenserande transaktioner fungerar inte alltid. Stegen i en kompenserande transaktion ska definieras som idempotenta kommandon. Om du gör det kan stegen upprepas om själva kompenserande transaktionen misslyckas.
Infrastrukturen som hanterar stegen måste uppfylla följande kriterier:
- Den är elastisk i den ursprungliga åtgärden och i den kompenserande transaktionen.
- Den förlorar inte den information som krävs för att kompensera för ett felsteg.
- Den övervakar på ett tillförlitligt sätt förloppet för kompensationslogik.
En kompenserande transaktion returnerar inte nödvändigtvis systemdata till dess tillstånd i början av den ursprungliga åtgärden. I stället kompenserar transaktionen för det arbete som åtgärden slutförde innan den misslyckades.
Stegens ordning i den kompenserande transaktionen är inte nödvändigtvis raka motsatsen till stegen i den ursprungliga åtgärden. Till exempel kan ett datalager vara mer känsligt för inkonsekvenser än ett annat. Stegen i den kompenserande transaktionen som ångrar ändringarna i det här arkivet bör utföras först.
Vissa mått kan öka sannolikheten för att den övergripande aktiviteten lyckas. Mer specifikt kan du placera ett kortsiktigt timeout-baserat lås på varje resurs som krävs för att slutföra en åtgärd. Du kan också hämta dessa resurser i förväg. Utför sedan arbetet först när du har hämtat alla resurser. Slutför alla åtgärder innan låsen upphör att gälla.
Om du försöker använda logik som är mer förlåtande än vanligt kan du minimera fel som utlöser en kompenserande transaktion. Om ett steg i en åtgärd som implementerar eventuell konsekvens misslyckas kan du prova att hantera felet som ett tillfälligt undantag och upprepa steget. Stoppa åtgärden och initiera endast en kompenserande transaktion om ett steg misslyckas upprepade gånger eller inte kan återställas.
När du implementerar en kompenserande transaktion står du inför många av de utmaningar som du står inför när du implementerar eventuell konsekvens. Mer information finns i avsnittet "Överväganden för att implementera eventuell konsekvens" i Datakonsekvensprimeringen.
När du ska använda det här mönstret
Det här mönstret ska bara användas för åtgärder som måste ångras om de misslyckas. Om det är möjligt ska lösningar utformas för att slippa ta till komplexa kompenserande transaktioner.
Design av arbetsbelastning
En arkitekt bör utvärdera hur mönstret Kompenserande transaktion kan användas i arbetsbelastningens design för att uppfylla de mål och principer som beskrivs i grundpelarna i Azure Well-Architected Framework. Till exempel:
Grundpelare | Så här stöder det här mönstret pelarmål |
---|---|
Beslut om tillförlitlighetsdesign hjälper din arbetsbelastning att bli motståndskraftig mot fel och se till att den återställs till ett fullt fungerande tillstånd när ett fel inträffar. | Kompensationsåtgärder åtgärdar fel i kritiska arbetsbelastningsvägar genom att använda processer som att direkt återställa dataändringar, bryta transaktionslås eller till och med köra internt systembeteende för att vända effekten. - RE:02 Kritiska flöden - RE:09 Haveriberedskap |
Som med alla designbeslut bör du överväga eventuella kompromisser mot målen för de andra pelarna som kan införas med det här mönstret.
Exempel
Kunder använder en resewebbplats för att boka resplaner. En enda resplan kan bestå av en rad flygningar och hotell. En kund som reser från Seattle till London och sedan vidare till Paris kan utföra följande steg när du skapar en resplan:
- Boka en plats på flighten F1 från Seattle till London.
- Boka en plats på flighten F2 från London till Paris.
- Boka en plats på flighten F3 från Paris till Seattle.
- Boka ett rum på hotellet H1 i London.
- Boka ett rum på hotellet H2 i Paris.
De här stegen utgör en eventuell konsekvens-åtgärd, samtidigt som varje steg är en separat åtgärd. Förutom att utföra de här stegen måste systemet även registrera räknaråtgärderna för att ångra varje steg. Den här informationen behövs om kunden avbryter resplanen. De steg som krävs för att utföra räknaråtgärderna kan sedan köras som en kompenserande transaktion.
Stegen i den kompenserande transaktionen kanske inte är raka motsatsen till de ursprungliga stegen. Dessutom måste logiken i varje steg i den kompenserande transaktionen ta hänsyn till affärsspecifika regler. Om du till exempel avbryter en flygreservation kanske det inte ger kunden rätt till fullständig återbetalning.
Följande bild visar stegen i en tidskrävande transaktion för att boka en resplan. Du kan också se de kompenserande transaktionsstegen som ångrar transaktionen.
Kommentar
Du kanske kan utföra stegen i den kompenserande transaktionen parallellt, beroende på hur du utformar den kompenserande logiken för varje steg.
I många affärslösningar kräver fel i ett enda steg inte alltid att systemet återställs med hjälp av en kompenserande transaktion. Tänk till exempel på scenariot med resewebbplatsen. Anta att kunden bokar flyg F1, F2 och F3 men inte kan boka ett rum på hotell H1. Det är bättre att erbjuda kunden ett rum på ett annat hotell i samma stad i stället för att ställa in flygen. Kunden kan fortfarande välja att avbryta. I så fall körs och ångras bokningarna för flyg F1, F2 och F3. Men kunden bör fatta det här beslutet, inte systemet.
Nästa steg
- Datakonsekvensprimer. Mönstret för kompenserande transaktioner används ofta för att ångra åtgärder som implementerar eventuell konsekvens. Den här primern innehåller information om fördelarna och kompromisserna med eventuell konsekvens.
- Idempotensmönster. I en kompenserande transaktion är det bäst att använda idempotent-kommandon. Det här blogginlägget beskriver faktorer att tänka på när du implementerar idempotens.
Relaterade resurser
- Scheduler Agent Supervisor-mönster. Den här artikeln beskriver hur du implementerar motståndskraftiga system som utför affärsåtgärder som använder distribuerade tjänster och resurser. I dessa system måste du ibland använda en kompenserande transaktion för att ångra det arbete som en åtgärd utför.
- Återförsöksmönster. Kompenserande transaktioner kan vara beräkningsmässigt krävande. Du kan försöka minimera användningen av dem med hjälp av återförsöksmönstret för att implementera en effektiv princip för att försöka utföra misslyckade åtgärder igen.
- Saga-mönster för distribuerade transaktioner. Den här artikeln beskriver hur du använder Saga-mönstret för att hantera datakonsekvens mellan mikrotjänster i distribuerade transaktionsscenarier. Saga-mönstret hanterar felåterställning med kompenserande transaktioner.
- Mönster för rör och filter. Den här artikeln beskriver mönstret Pipes och Filter, som du kan använda för att dela upp en komplex bearbetningsaktivitet i en serie återanvändbara element. Du kan använda mönstret Pipes och Filter med mönstret Kompenserande transaktion som ett alternativ till att implementera distribuerade transaktioner.
- Design för självåterställning. Den här guiden förklarar hur du utformar självåterställningsprogram. Du kan använda kompenserande transaktioner som en del av en självåterställningsmetod.