Geo-redundantie gebruiken om toepassingen met hoge beschikbaarheid te ontwerpen

Cloudinfrastructuren zoals Azure Storage bieden een maximaal beschikbaar en duurzaam platform voor het hosten van gegevens en toepassingen. Ontwikkelaars van cloudtoepassingen moeten zorgvuldig overwegen hoe ze dit platform kunnen gebruiken om deze voordelen voor hun gebruikers te maximaliseren. Azure Storage biedt opties voor geo-redundantie om hoge beschikbaarheid te garanderen, zelfs tijdens een regionale storing. Opslagaccounts die zijn geconfigureerd voor geografisch redundante replicatie, worden synchroon gerepliceerd in de primaire regio en asynchroon gerepliceerd naar een secundaire regio op honderden kilometers afstand.

Azure Storage biedt twee opties voor geografisch redundante replicatie: Geografisch redundante opslag (GRS) en Geografisch zone-redundante opslag (GZRS). Als u gebruik wilt maken van de opties voor geo-redundantie van Azure Storage, moet u ervoor zorgen dat uw opslagaccount is geconfigureerd voor geografisch redundante opslag met leestoegang (RA-GRS) of geografisch zone-redundante opslag met leestoegang (RA-GZRS). Als dat niet zo is, kunt u meer informatie vinden over het wijzigen van het replicatietype van uw opslagaccount.

In dit artikel wordt beschreven hoe u een toepassing ontwerpt die blijft werken, zij het in een beperkte capaciteit, zelfs wanneer er een aanzienlijke storing is in de primaire regio. Als de primaire regio niet meer beschikbaar is, kan uw toepassing naadloos overschakelen om leesbewerkingen uit te voeren op de secundaire regio totdat de primaire regio weer reageert.

Ontwerpoverwegingen voor toepassingen

U kunt uw toepassing zo ontwerpen dat tijdelijke fouten of aanzienlijke storingen worden verwerkt door uit de secundaire regio te lezen wanneer er een probleem is dat het lezen vanuit de primaire regio verstoort. Wanneer de primaire regio weer beschikbaar is, kan uw toepassing teruggaan naar het lezen vanuit de primaire regio.

Houd rekening met deze belangrijke overwegingen bij het ontwerpen van uw toepassing voor beschikbaarheid en tolerantie met behulp van RA-GRS of RA-GZRS:

  • Een alleen-lezen kopie van de gegevens die u opslaat in de primaire regio wordt asynchroon gerepliceerd in een secundaire regio. Deze asynchrone replicatie betekent dat de alleen-lezen kopie in de secundaire regio uiteindelijk consistent is met de gegevens in de primaire regio. De opslagservice bepaalt de locatie van de secundaire regio.

  • U kunt de Azure Storage-clientbibliotheken gebruiken om lees- en updateaanvragen uit te voeren voor het eindpunt van de primaire regio. Als de primaire regio niet beschikbaar is, kunt u leesaanvragen automatisch omleiden naar de secundaire regio. U kunt uw app ook configureren om leesaanvragen rechtstreeks naar de secundaire regio te verzenden, indien gewenst, zelfs wanneer de primaire regio beschikbaar is.

  • Als de primaire regio niet meer beschikbaar is, kunt u een accountfailover initiëren. Wanneer u een failover naar de secundaire regio uitvoert, worden de DNS-vermeldingen die naar de primaire regio verwijzen, gewijzigd zodat deze verwijzen naar de secundaire regio. Nadat de failover is voltooid, wordt schrijftoegang hersteld voor GRS- en RA-GRS-accounts. Zie Herstel na noodgeval en failover van opslagaccounts voor meer informatie.

Werken met uiteindelijk consistente gegevens

In de voorgestelde oplossing wordt ervan uitgegaan dat het acceptabel is om mogelijk verouderde gegevens te retourneren naar de aanroepende toepassing. Omdat gegevens in de secundaire regio uiteindelijk consistent zijn, is het mogelijk dat de primaire regio ontoegankelijk wordt voordat een update naar de secundaire regio is gerepliceerd.

Stel dat uw klant een update heeft ingediend, maar dat de primaire regio mislukt voordat de update wordt doorgegeven aan de secundaire regio. Wanneer de klant vraagt om de gegevens terug te lezen, ontvangen ze de verouderde gegevens uit de secundaire regio in plaats van de bijgewerkte gegevens. Bij het ontwerpen van uw toepassing moet u beslissen of dit gedrag acceptabel is. Als dat zo is, moet u ook overwegen hoe u de gebruiker op de hoogte kunt stellen.

Verderop in dit artikel vindt u meer informatie over het verwerken van uiteindelijk consistente gegevens en het controleren van de eigenschap Laatste synchronisatietijd om eventuele discrepanties tussen gegevens in de primaire en secundaire regio's te evalueren.

Services afzonderlijk of allemaal samen verwerken

Hoewel het onwaarschijnlijk is, is het mogelijk dat de ene service (blobs, wachtrijen, tabellen of bestanden) niet beschikbaar is terwijl de andere services nog steeds volledig functioneel zijn. U kunt de nieuwe pogingen voor elke service afzonderlijk afhandelen of u kunt nieuwe pogingen algemeen afhandelen voor alle opslagservices samen.

Als u bijvoorbeeld wachtrijen en blobs in uw toepassing gebruikt, kunt u besluiten om afzonderlijke code in te voeren voor het afhandelen van fouten die opnieuw kunnen worden geprobeerd voor elke service. Op die manier is een blobservicefout alleen van invloed op het deel van uw toepassing dat blobs behandelt, waardoor wachtrijen gewoon kunnen blijven worden uitgevoerd. Als u echter besluit om alle nieuwe pogingen van de opslagservice samen af te handelen, worden aanvragen voor zowel blob- als wachtrijservices beïnvloed als een van beide services een fout retourneert die opnieuw kan worden geprobeerd.

Uiteindelijk is deze beslissing afhankelijk van de complexiteit van uw toepassing. U kunt er de voorkeur aan geven om fouten per service af te handelen om de impact van nieuwe pogingen te beperken. U kunt ook besluiten leesaanvragen voor alle opslagservices om te leiden naar de secundaire regio wanneer u een probleem met een opslagservice in de primaire regio detecteert.

Uw toepassing uitvoeren in de modus Alleen-lezen

Als u zich effectief wilt voorbereiden op een storing in de primaire regio, moet uw toepassing zowel mislukte leesaanvragen als mislukte updateaanvragen kunnen verwerken. Als de primaire regio mislukt, kunnen leesaanvragen worden omgeleid naar de secundaire regio. Updateaanvragen kunnen echter niet worden omgeleid omdat de gerepliceerde gegevens in de secundaire regio alleen-lezen zijn. Daarom moet u uw toepassing zo ontwerpen dat deze kan worden uitgevoerd in de modus Alleen-lezen.

U kunt bijvoorbeeld een vlag instellen die wordt gecontroleerd voordat er updateaanvragen worden verzonden naar Azure Storage. Wanneer een updateaanvraag binnenkomt, kunt u de aanvraag overslaan en een geschikt antwoord naar de gebruiker retourneren. U kunt er zelfs voor kiezen om bepaalde functies helemaal uit te schakelen totdat het probleem is opgelost en gebruikers op de hoogte te stellen dat de functies tijdelijk niet beschikbaar zijn.

Als u besluit om fouten voor elke service afzonderlijk af te handelen, moet u ook de mogelijkheid afhandelen om uw toepassing in de alleen-lezenmodus per service uit te voeren. U kunt bijvoorbeeld alleen-lezenvlagmen instellen voor elke service. Vervolgens kunt u de vlaggen in de code indien nodig in- of uitschakelen.

Als u uw toepassing in de alleen-lezenmodus kunt uitvoeren, kunt u ook zorgen voor beperkte functionaliteit tijdens een grote upgrade van de toepassing. U kunt uw toepassing activeren om te worden uitgevoerd in de modus Alleen-lezen en verwijzen naar het secundaire datacenter, zodat niemand toegang heeft tot de gegevens in de primaire regio terwijl u upgrades uitvoert.

Updates verwerken wanneer deze worden uitgevoerd in de modus Alleen-lezen

Er zijn veel manieren om updateaanvragen af te handelen wanneer deze worden uitgevoerd in de modus Alleen-lezen. Deze sectie is gericht op enkele algemene patronen die u kunt overwegen.

  • U kunt reageren op de gebruiker en deze laten weten dat er momenteel geen updateaanvragen worden verwerkt. Een contactbeheersysteem kan gebruikers bijvoorbeeld in staat stellen om toegang te krijgen tot contactgegevens, maar geen updates aan te brengen.

  • U kunt uw updates in een andere regio in de wachtrij plaatsen. In dit geval schrijft u uw wachtende updateaanvragen naar een wachtrij in een andere regio en verwerkt u deze aanvragen nadat het primaire datacenter weer online komt. In dit scenario moet u de gebruiker laten weten dat de updateaanvraag in de wachtrij staat voor latere verwerking.

  • U kunt uw updates schrijven naar een opslagaccount in een andere regio. Wanneer de primaire regio weer online komt, kunt u deze updates samenvoegen in de primaire gegevens, afhankelijk van de structuur van de gegevens. Als u bijvoorbeeld afzonderlijke bestanden maakt met een datum-/tijdstempel in de naam, kunt u deze bestanden terug kopiëren naar de primaire regio. Deze oplossing kan van toepassing zijn op workloads zoals logboekregistratie en IoT-gegevens.

Nieuwe pogingen verwerken

Toepassingen die communiceren met services die in de cloud worden uitgevoerd, moeten gevoelig zijn voor niet-geplande gebeurtenissen en fouten die kunnen optreden. Deze fouten kunnen tijdelijk of persistent zijn, variërend van een tijdelijk verlies van connectiviteit tot een aanzienlijke storing als gevolg van een natuurramp. Het is belangrijk om cloudtoepassingen te ontwerpen met de juiste verwerking van nieuwe pogingen om de beschikbaarheid te maximaliseren en de algehele stabiliteit van de toepassing te verbeteren.

Leesaanvragen

Als de primaire regio niet meer beschikbaar is, kunnen leesaanvragen worden omgeleid naar de secundaire opslag. Zoals eerder vermeld, moet het acceptabel zijn voor uw toepassing om mogelijk verouderde gegevens te lezen. De Azure Storage-clientbibliotheek biedt opties voor het afhandelen van nieuwe pogingen en het omleiden van leesaanvragen naar een secundaire regio.

In dit voorbeeld wordt de verwerking van nieuwe pogingen voor Blob Storage geconfigureerd in de BlobClientOptions klasse en wordt deze toegepast op het BlobServiceClient object dat we maken met behulp van deze configuratieopties. Deze configuratie is een primaire en secundaire benadering, waarbij nieuwe pogingen tot leesaanvragen van de primaire regio worden omgeleid naar de secundaire regio. Deze aanpak is het beste wanneer fouten in de primaire regio naar verwachting tijdelijk zijn.

string accountName = "<YOURSTORAGEACCOUNTNAME>";
Uri primaryAccountUri = new Uri($"https://{accountName}.blob.core.windows.net/");
Uri secondaryAccountUri = new Uri($"https://{accountName}-secondary.blob.core.windows.net/");

// Provide the client configuration options for connecting to Azure Blob storage
BlobClientOptions blobClientOptions = new BlobClientOptions()
{
    Retry = {
        // The delay between retry attempts for a fixed approach or the delay
        // on which to base calculations for a backoff-based approach
        Delay = TimeSpan.FromSeconds(2),

        // The maximum number of retry attempts before giving up
        MaxRetries = 5,

        // The approach to use for calculating retry delays
        Mode = RetryMode.Exponential,

        // The maximum permissible delay between retry attempts
        MaxDelay = TimeSpan.FromSeconds(10)
    },

    // If the GeoRedundantSecondaryUri property is set, the secondary Uri will be used for 
    // GET or HEAD requests during retries.
    // If the status of the response from the secondary Uri is a 404, then subsequent retries
    // for the request will not use the secondary Uri again, as this indicates that the resource 
    // may not have propagated there yet.
    // Otherwise, subsequent retries will alternate back and forth between primary and secondary Uri.
    GeoRedundantSecondaryUri = secondaryAccountUri
};

// Create a BlobServiceClient object using the configuration options above
BlobServiceClient blobServiceClient = new BlobServiceClient(primaryAccountUri, new DefaultAzureCredential(), blobClientOptions);

Als u vaststelt dat de primaire regio waarschijnlijk lange tijd niet beschikbaar is, kunt u alle leesaanvragen zo configureren dat deze verwijzen naar de secundaire regio. Deze configuratie is een secundaire benadering . Zoals eerder besproken, hebt u een strategie nodig voor het afhandelen van updateaanvragen gedurende deze periode en een manier om gebruikers te informeren dat alleen leesaanvragen worden verwerkt. In dit voorbeeld maken we een nieuw exemplaar waarvan het eindpunt van BlobServiceClient de secundaire regio wordt gebruikt.

string accountName = "<YOURSTORAGEACCOUNTNAME>";
Uri primaryAccountUri = new Uri($"https://{accountName}.blob.core.windows.net/");
Uri secondaryAccountUri = new Uri($"https://{accountName}-secondary.blob.core.windows.net/");

// Create a BlobServiceClient object pointed at the secondary Uri
// Use blobServiceClientSecondary only when issuing read requests, as secondary storage is read-only
BlobServiceClient blobServiceClientSecondary = new BlobServiceClient(secondaryAccountUri, new DefaultAzureCredential(), blobClientOptions);

Weten wanneer u moet overschakelen naar de alleen-lezenmodus en secundaire aanvragen, maakt deel uit van een architectuurontwerppatroon met de naam Circuitonderbrekerpatroon, dat in een latere sectie wordt besproken.

Updateaanvragen

Updateaanvragen kunnen niet worden omgeleid naar de secundaire opslag, die het kenmerk Alleen-lezen heeft. Zoals eerder beschreven, moet uw toepassing updateaanvragen kunnen verwerken wanneer de primaire regio niet beschikbaar is.

Het patroon Circuitonderbreker kan ook worden toegepast op updateaanvragen. Als u fouten met updateaanvragen wilt afhandelen, kunt u een drempelwaarde instellen in de code, zoals 10 opeenvolgende fouten, en het aantal fouten voor aanvragen naar de primaire regio bijhouden. Zodra aan de drempelwaarde is voldaan, kunt u de toepassing overschakelen naar de modus Alleen-lezen, zodat er geen updateaanvragen meer naar de primaire regio worden uitgegeven.

Het circuitonderbrekerpatroon implementeren

Het verwerken van fouten die mogelijk een variabele hoeveelheid tijd in beslag nemen om te herstellen, maakt deel uit van een architectonisch ontwerppatroon dat circuitonderbrekerpatroon wordt genoemd. Een juiste implementatie van dit patroon kan voorkomen dat een toepassing herhaaldelijk probeert een bewerking uit te voeren die waarschijnlijk mislukt, waardoor de stabiliteit en tolerantie van de toepassing wordt verbeterd.

Een aspect van het circuitonderbrekerpatroon is het identificeren wanneer er een doorlopend probleem is met een primair eindpunt. Om dit te bepalen, kunt u controleren hoe vaak de client fouten tegenkomt die opnieuw kunnen worden geprobeerd. Omdat elk scenario anders is, moet u een geschikte drempelwaarde bepalen voor de beslissing om over te schakelen naar het secundaire eindpunt en de toepassing uit te voeren in de modus Alleen-lezen.

U kunt bijvoorbeeld besluiten om de switch uit te voeren als er tien opeenvolgende fouten zijn in de primaire regio. U kunt dit bijhouden door het aantal fouten in de code bij te houden. Als er een succes is voordat de drempelwaarde wordt bereikt, stelt u het aantal terug op nul. Als het aantal de drempelwaarde bereikt, schakelt u de toepassing over op het gebruik van de secundaire regio voor leesaanvragen.

Als alternatief kunt u besluiten om een aangepast bewakingsonderdeel in uw toepassing te implementeren. Dit onderdeel kan uw primaire opslageindpunt continu pingen met triviale leesaanvragen (zoals het lezen van een kleine blob) om de status ervan te bepalen. Deze aanpak zou een aantal resources in beslag nemen, maar niet een aanzienlijk bedrag. Wanneer er een probleem wordt gedetecteerd dat uw drempelwaarde bereikt, schakelt u over naar secundaire alleen-lezenaanvragen en de modus Alleen-lezen. In dit scenario kunt u, wanneer het pingen van het primaire opslageindpunt weer lukt, teruggaan naar de primaire regio en doorgaan met het toestaan van updates.

De foutdrempelwaarde die wordt gebruikt om te bepalen wanneer de overstap moet worden gemaakt, kan per service in uw toepassing verschillen. U kunt daarom overwegen om deze configureerbare parameters te maken.

Een andere overweging is het afhandelen van meerdere exemplaren van een toepassing en wat u moet doen wanneer u fouten detecteert die opnieuw kunnen worden geprobeerd in elk exemplaar. U kunt bijvoorbeeld 20 VM's uitvoeren waarop dezelfde toepassing is geladen. Behandelt u elk exemplaar afzonderlijk? Als één exemplaar problemen begint te ondervinden, wilt u de reactie dan beperken tot slechts dat ene exemplaar? Of wilt u dat alle exemplaren op dezelfde manier reageren wanneer één exemplaar een probleem heeft? Het afzonderlijk verwerken van de exemplaren is veel eenvoudiger dan het coördineren van de reactie op de exemplaren, maar uw aanpak is afhankelijk van de architectuur van uw toepassing.

Uiteindelijk consistente gegevens verwerken

Geografisch redundante opslag werkt door transacties van de primaire naar de secundaire regio te repliceren. Het replicatieproces garandeert dat de gegevens in de secundaire regio uiteindelijk consistent zijn. Dit betekent dat alle transacties in de primaire regio uiteindelijk worden weergegeven in de secundaire regio, maar dat er een vertraging kan zijn voordat ze worden weergegeven. Er is ook geen garantie dat transacties in de secundaire regio binnenkomen in dezelfde volgorde als ze oorspronkelijk werden toegepast in de primaire regio. Als uw transacties buiten de volgorde van de secundaire regio binnenkomen, kunt u uw gegevens in de secundaire regio beschouwen als inconsistent totdat de service de status inhaalt.

In het volgende voorbeeld voor Azure Table Storage ziet u wat er kan gebeuren wanneer u de details van een werknemer bijwerkt om deze lid te maken van de beheerdersrol. In dit voorbeeld moet u hiervoor de werknemersentiteit bijwerken en een beheerdersrolentiteit bijwerken met een telling van het totale aantal beheerders. U ziet hoe de updates niet op volgorde worden toegepast in de secundaire regio.

Tijd Transactie Replicatie Laatste synchronisatietijd Resultaat
T0 Transactie A:
Werknemer invoegen
entiteit in primair
Transactie A ingevoegd in primaire,
nog niet gerepliceerd.
T1 Transactie A
gerepliceerd naar
Secundaire
T1 Transactie A gerepliceerd naar secundair.
Laatste synchronisatietijd bijgewerkt.
T2 Transactie B:
Bijwerken
werknemersentiteit
in primaire
T1 Transactie B geschreven naar primaire,
nog niet gerepliceerd.
T3 Transactie C:
Bijwerken
beheerder
rolentiteit in
Primaire
T1 Transactie C geschreven naar primaire,
nog niet gerepliceerd.
T4 Transactie C
gerepliceerd naar
Secundaire
T1 Transactie C gerepliceerd naar secundair.
LastSyncTime niet bijgewerkt omdat
transactie B is nog niet gerepliceerd.
T5 Entiteiten lezen
van secundaire
T1 U krijgt de verouderde waarde voor de werknemer
entiteit omdat transactie B niet
is nog gerepliceerd. U krijgt de nieuwe waarde voor
beheerdersrolentiteit omdat C
Gerepliceerd. Laatste synchronisatietijd is nog steeds niet
bijgewerkt omdat transactie B
is niet gerepliceerd. U ziet de
rolentiteit beheerder is inconsistent
omdat de datum/tijd van de entiteit na is
de laatste synchronisatietijd.
T6 Transactie B
gerepliceerd naar
Secundaire
T6 T6 – Alle transacties via C hebben
gerepliceerd, Laatste synchronisatietijd
wordt bijgewerkt.

In dit voorbeeld wordt ervan uitgegaan dat de client overschakelt naar lezen uit de secundaire regio op T5. De entiteit met de rol beheerder kan op dit moment worden gelezen, maar de entiteit bevat een waarde voor het aantal beheerders die niet consistent is met het aantal werknemersentiteiten dat op dit moment als beheerders in de secundaire regio is gemarkeerd. Uw client kan deze waarde weergeven, met het risico dat de informatie inconsistent is. De client kan ook proberen te bepalen dat de beheerdersrol een mogelijk inconsistente status heeft omdat de updates niet in de juiste volgorde zijn uitgevoerd, en de gebruiker vervolgens van dit feit op de hoogte brengen.

Om te bepalen of een opslagaccount mogelijk inconsistente gegevens bevat, kan de client de waarde van de eigenschap Laatste synchronisatietijd controleren. Laatste synchronisatietijd geeft aan wanneer de gegevens in de secundaire regio voor het laatst consistent waren en wanneer de service alle transacties vóór dat tijdstip heeft toegepast. In het bovenstaande voorbeeld wordt de laatste synchronisatietijd ingesteld op T1 nadat de service de entiteit werknemer in de secundaire regio heeft ingevoegd. Deze blijft op T1 totdat de service de werknemersentiteit in de secundaire regio bijwerkt wanneer deze is ingesteld op T6. Als de client de laatste synchronisatietijd ophaalt wanneer de entiteit op T5 wordt gelezen, kan deze worden vergeleken met de tijdstempel van de entiteit. Als de tijdstempel van de entiteit later is dan de laatste synchronisatietijd, heeft de entiteit een mogelijk inconsistente status en kunt u de juiste actie ondernemen. Als u dit veld gebruikt, moet u weten wanneer de laatste update naar de primaire versie is voltooid.

Zie De eigenschap Laatste synchronisatietijd voor een opslagaccount controleren voor meer informatie over het controleren van de laatste synchronisatietijd.

Testen

Het is belangrijk om te testen of uw toepassing zich gedraagt zoals verwacht wanneer er fouten optreden die opnieuw kunnen worden geprobeerd. U moet bijvoorbeeld testen of de toepassing overschakelt naar de secundaire regio wanneer er een probleem wordt gedetecteerd en vervolgens terugschakelt wanneer de primaire regio weer beschikbaar is. Als u dit gedrag goed wilt testen, hebt u een manier nodig om fouten die opnieuw kunnen worden geprobeerd te simuleren en te bepalen hoe vaak ze optreden.

Een optie is om Fiddler te gebruiken om HTTP-antwoorden in een script te onderscheppen en te wijzigen. Dit script kan antwoorden identificeren die afkomstig zijn van uw primaire eindpunt en de HTTP-statuscode wijzigen in een code die door de Storage-clientbibliotheek wordt herkend als een fout die opnieuw kan worden geprobeerd. In dit codefragment ziet u een eenvoudig voorbeeld van een Fiddler-script waarmee antwoorden op leesaanvragen voor de tabel employeedata worden onderschept om een 502-status te retourneren:

static function OnBeforeResponse(oSession: Session) {
    ...
    if ((oSession.hostname == "\[YOURSTORAGEACCOUNTNAME\].table.core.windows.net")
      && (oSession.PathAndQuery.StartsWith("/employeedata?$filter"))) {
        oSession.responseCode = 502;
    }
}

U kunt dit voorbeeld uitbreiden om een breder scala aan aanvragen te onderscheppen en alleen de responseCode voor sommige aanvragen te wijzigen om een praktijkscenario beter te simuleren. Zie Een aanvraag of antwoord wijzigen in de Fiddler-documentatie voor meer informatie over het aanpassen van Fiddler-scripts.

Als u configureerbare drempelwaarden hebt ingesteld voor het overschakelen van uw toepassing naar alleen-lezen, is het eenvoudiger om het gedrag te testen met niet-productietransactievolumes.


Volgende stappen

Zie Azure-voorbeelden : het circuitonderbrekerpatroon gebruiken met RA-GRS-opslag voor een volledig voorbeeld waarin wordt getoond hoe u heen en weer schakelt tussen de primaire en secundaire eindpunten.