Minimera samordning

Azure Storage
Azure SQL Database
Azure Cosmos DB

Minimera samordningen mellan programtjänster för att uppnå skalbarhet

De flesta molnprogram består av flera programtjänster – webbklientdelar, databaser, affärsprocesser, rapportering och analys och så vidare. För att uppnå skalbarhet och tillförlitlighet ska var och en av dessa tjänster köras på flera instanser.

Vad händer när två instanser försöker utföra samtidiga åtgärder som påverkar vissa delade tillstånd? I vissa fall kan måste det finnas en samordning mellan noderna, till exempel för att bevara ACID-garantier. I det här diagrammet väntar Node2 på att Node1 ska frigöra ett databaslås:

Database lock diagram

Samordning begränsar fördelarna med att skala horisontellt och skapar flaskhalsar. I det här exemplet, när du skalar ut programmet och lägger till flera instanser, ser du ökad låskonkurrens. I värsta fall kommer klientdelsinstanserna att tillbringa större delen av tiden i väntan på låsen.

”Exakt en gång”-semantik är en annan vanliga källa till samordning. Till exempel måste en order bearbetas exakt en gång. Två arbetsroller lyssnar efter nya order. Worker1 hämtar en order för bearbetning. Programmet måste se till att Worker2 inte duplicerar arbetet, utan även om Worker1 kraschar släpps inte ordningen.

Coordination diagram

Du kan använda ett mönster som Scheduler Agent Supervisor för att koordinera mellan arbetsrollerna, men i det här fallet kanske en bättre metod är att partitionera arbetet. Varje arbetsroll tilldelas ett visst intervall av order (efter exempelvis faktureringsregion). Om en arbetsroll kraschar tar en ny instans vid där föregående instans slutade, men flera instanser konkurrerar inte.

Rekommendationer

Tänk på den slutliga konsekvensen. När data distribueras krävs det samordning för att genomdriva starka konsekvensgaranterar. Anta exempelvis att en åtgärd uppdaterar två databaser. I stället för att försätta den i en enda transaktionsomfattning, är det bättre om systemet kan hantera slutlig konsekvens, kanske med hjälp av mönstret kompenserande transaktion för logisk återställning efter ett fel.

Använd domänhändelser för att synkronisera tillstånd. En domänhändelse är en händelse som registrerar när det händer något som har betydelse inom domänen. Berörda tjänster kan lyssna efter händelsen i stället för att använda en global transaktion för att koordinera mellan flera tjänster. Om den här metoden används måste systemet tolerera slutlig konsekvens (se föregående objekt).

Överväg mönster som CQRS och händelsekälla. Dessa två mönster kan bidra till att minska konkurrensen mellan skrivskyddade arbetsbelastningar och skrivbara arbetsbelastningar.

  • CQRS-mönstret avgränsar läsåtgärder från skrivåtgärder. Skrivskyddade data är fysiskt avgränsade från skrivbara data i vissa implementeringar.

  • I mönstret Event Sourcing registreras tillståndsändringar som en serie händelser i ett datalager med endast tillägg. Att lägga till en händelse i dataströmmen är en atomisk åtgärd som kräver minimal låsning.

Dessa två mönster kompletterar varandra. Om det lässkyddade arkivet i CQRS använder händelsekälla kan det skrivskyddade arkivet lyssna efter samma händelser för att skapa en läsbar ögonblicksbild av det aktuella tillståndet, optimerat för frågor. Innan du använder CQRS eller händelsekälla bör du dock vara medveten om utmaningarna med den här metoden.

Partitionera data. Undvik att placera alla data i ett dataschema som delas mellan många programtjänster. En arkitektur för mikrotjänster tillämpar denna princip genom att göra varje tjänst ansvarig för sitt eget datalager. Inom en enskild databas kan partitionering av data i shards förbättra samtidigheten, eftersom en tjänst som skrivs till en shard inte påverkar en tjänst som skrivs till en annan shard.

Utforma idempotenta åtgärder. Utforma om möjligt åtgärder så att de är idempotenta. På så sätt kan de hanteras med hjälp av-minst-en-gång-semantik. Du kan till exempel placera arbetsobjekt i en kö. Om en arbetsroll kraschar mitt i en åtgärd hämtar en annan arbetsroll bara upp arbetsobjektet. Om arbetaren behöver uppdatera data och generera andra meddelanden som en del av sin logik , bör mönstret för idempotent meddelandebearbetning användas.

Använd optimistisk samtidighet när det är möjligt. Pessimistisk samtidighetskontroll använder databaslås för att undvika konflikter. Detta kan orsaka prestandaproblem och minska tillgängligheten. Med optimistisk samtidighetskontroll ändrar varje transaktion en kopia eller en ögonblicksbild av data. När transaktionen genomförs validerar databasmotorn transaktionen och avvisar alla transaktioner som kan påverka databasens konsekvens.

Azure SQL Database och SQL Server stöder optimistisk samtidighet via ögonblicksbildisolering. Vissa Azure-lagringstjänster har stöd för optimistisk samtidighet genom användning av ETags, däribland Azure Cosmos DB och Azure Storage.

Överväg MapReduce eller andra parallella, distribuerade algoritmer. Beroende på data och den typ av arbete utförs kanske du kan dela upp arbete i oberoende aktiviteter som kan utföras med flera noder som arbetar parallellt. Se Arkitekturformatet Big Compute.

Använd val av ledare för samordning. I fall där du behöver samordna åtgärder, kontrollerar du att koordinatorn inte blir en felkritisk systemdel i programmet. Vid användning av Mönster för val av ledare är en instans ledare när som helst och fungerar som koordinator. Om ett fel uppstår i den ledande instansen välj en ny instans för denna roll.