Použití geografické redundance k návrhu vysoce dostupných aplikací

Cloudové infrastruktury, jako je Azure Storage, poskytují vysoce dostupnou a odolnou platformu pro hostování dat a aplikací. Vývojáři cloudových aplikací musí pečlivě zvážit, jak tuto platformu využít k maximalizaci těchto výhod pro své uživatele. Azure Storage nabízí možnosti geografické redundance, které zajišťují vysokou dostupnost i během oblastního výpadku. Účty úložiště nakonfigurované pro geograficky redundantní replikaci se synchronně replikují v primární oblasti a asynchronně se replikují do sekundární oblasti vzdálené stovky kilometrů.

Azure Storage nabízí dvě možnosti pro geograficky redundantní replikaci: geograficky redundantní úložiště (GRS) a geograficky zónově redundantní úložiště (GZRS). Pokud chcete využít možnosti geografické redundance služby Azure Storage, ujistěte se, že je váš účet úložiště nakonfigurovaný pro geograficky redundantní úložiště jen pro čtení (RA-GRS) nebo geograficky zónově redundantní úložiště jen pro čtení (RA-GZRS). Pokud tomu tak není, můžete si přečíst další informace o tom, jak změnit typ replikace účtu úložiště.

Tento článek ukazuje, jak navrhnout aplikaci, která bude i nadále fungovat, i když s omezenou kapacitou, i když dojde k významnému výpadku primární oblasti. Pokud primární oblast přestane být dostupná, může vaše aplikace bezproblémově přepínat a provádět operace čtení v sekundární oblasti, dokud primární oblast nebude znovu reagovat.

Aspekty návrhu aplikace

Pokud dojde k problému, který narušuje čtení z primární oblasti, můžete navrhnout aplikaci tak, aby zvládla přechodné chyby nebo významné výpadky. Jakmile bude primární oblast opět dostupná, vaše aplikace se může vrátit ke čtení z primární oblasti.

Při návrhu aplikace pro zajištění dostupnosti a odolnosti s využitím RA-GRS nebo RA-GZRS mějte na paměti tyto klíčové aspekty:

  • Kopie dat, která ukládáte v primární oblasti, jen pro čtení, se asynchronně replikuje v sekundární oblasti. Tato asynchronní replikace znamená, že kopie jen pro čtení v sekundární oblasti je nakonec konzistentní s daty v primární oblasti. Služba úložiště určuje umístění sekundární oblasti.

  • Klientské knihovny Azure Storage můžete použít k provádění požadavků na čtení a aktualizaci v primárním koncovém bodu oblasti. Pokud je primární oblast nedostupná, můžete žádosti o čtení automaticky přesměrovat do sekundární oblasti. Aplikaci můžete také nakonfigurovat tak, aby v případě potřeby odesílala žádosti o čtení přímo do sekundární oblasti, a to i v případě, že je primární oblast dostupná.

  • Pokud primární oblast přestane být dostupná, můžete zahájit převzetí služeb při selhání účtu. Při převzetí služeb při selhání sekundární oblastí se položky DNS odkazující na primární oblast změní tak, aby ukazovaly na sekundární oblast. Po dokončení převzetí služeb při selhání se pro účty GRS a RA-GRS obnoví přístup pro zápis. Další informace najdete v tématu Zotavení po havárii a převzetí služeb při selhání účtu úložiště.

Práce s časem konzistentními daty

Navrhované řešení předpokládá, že je přijatelné vrátit potenciálně zastaralá data volající aplikaci. Vzhledem k tomu, že data v sekundární oblasti jsou nakonec konzistentní, je možné, že primární oblast bude nedostupná před dokončením replikace aktualizace sekundární oblasti.

Předpokládejme například, že zákazník úspěšně odešle aktualizaci, ale primární oblast selže předtím, než se aktualizace rozšíří do sekundární oblasti. Když zákazník požádá o zpětné načtení dat, místo aktualizovaných dat obdrží zastaralá data ze sekundární oblasti. Při návrhu aplikace se musíte rozhodnout, jestli je toto chování přijatelné. Pokud ano, musíte také zvážit, jak uživatele upozornit.

Dále v tomto článku se dozvíte více o zpracování nakonec konzistentních dat a o tom, jak zkontrolovat vlastnost Čas poslední synchronizace , abyste mohli vyhodnotit případné nesrovnalosti mezi daty v primární a sekundární oblasti.

Manipulace se službami samostatně nebo společně

I když je to nepravděpodobné, je možné, že jedna služba (objekty blob, fronty, tabulky nebo soubory) přestane být dostupná, zatímco ostatní služby budou stále plně funkční. Opakované pokusy pro každou službu můžete zpracovávat samostatně nebo můžete pokusy zpracovávat obecně pro všechny služby úložiště najednou.

Pokud například ve své aplikaci používáte fronty a objekty blob, můžete se rozhodnout vložit samostatný kód pro zpracování opakovaných chyb pro každou službu. Chyba služby Blob Service tak ovlivní jenom tu část vaší aplikace, která pracuje s objekty blob, a fronty tak budou dál fungovat normálně. Pokud se ale rozhodnete zpracovávat všechny pokusy o opakování služby úložiště najednou, ovlivní to požadavky na služby objektů blob i služby front, pokud kterákoliv ze služeb vrátí chybu s možností opakování.

Toto rozhodnutí nakonec závisí na složitosti vaší aplikace. Možná dáváte přednost zpracování selhání službou, abyste omezili dopad opakovaných pokusů. Nebo se můžete rozhodnout přesměrovat žádosti o čtení všech služeb úložiště do sekundární oblasti, když zjistíte problém se službou úložiště v primární oblasti.

Spuštění aplikace v režimu jen pro čtení

Aby se vaše aplikace efektivně připravila na výpadek v primární oblasti, musí být schopná zpracovat neúspěšné žádosti o čtení i neúspěšné žádosti o aktualizaci. Pokud primární oblast selže, je možné žádosti o čtení přesměrovat do sekundární oblasti. Žádosti o aktualizaci se ale nedají přesměrovat, protože replikovaná data v sekundární oblasti jsou jen pro čtení. Z tohoto důvodu musíte navrhnout aplikaci tak, aby ji bylo možné spouštět v režimu jen pro čtení.

Můžete například nastavit příznak, který se zaškrtne před odesláním všech žádostí o aktualizaci do služby Azure Storage. Když přijde žádost o aktualizaci, můžete požadavek přeskočit a vrátit uživateli odpovídající odpověď. Můžete se dokonce rozhodnout některé funkce úplně zakázat, dokud se problém nevyřeší, a upozornit uživatele, že tyto funkce jsou dočasně nedostupné.

Pokud se rozhodnete zpracovávat chyby pro každou službu samostatně, budete také muset zpracovat možnost spustit aplikaci v režimu jen pro čtení podle služby. Pro každou službu můžete například nastavit příznaky jen pro čtení. Pak můžete podle potřeby povolit nebo zakázat příznaky v kódu.

Možnost spustit aplikaci v režimu jen pro čtení vám také dává možnost zajistit omezenou funkčnost během hlavního upgradu aplikace. Aplikaci můžete aktivovat tak, aby běžela v režimu jen pro čtení a odkazovala na sekundární datové centrum, čímž zajistíte, že během upgradu nebude nikdo přistupovat k datům v primární oblasti.

Zpracování aktualizací při spuštění v režimu jen pro čtení

Existuje mnoho způsobů, jak zpracovávat žádosti o aktualizaci v režimu jen pro čtení. Tato část se zaměřuje na několik obecných vzorů, které je potřeba zvážit.

  • Můžete odpovědět uživateli a upozornit ho, že se žádosti o aktualizaci právě nezpracovávají. Například systém pro správu kontaktů může uživatelům umožnit přístup ke kontaktním informacím, ale nemusí provádět aktualizace.

  • Aktualizace můžete zařadit do fronty v jiné oblasti. V takovém případě byste zapisovali čekající žádosti o aktualizaci do fronty v jiné oblasti a potom tyto žádosti zpracovali, jakmile se primární datové centrum znovu dostane do režimu online. V tomto scénáři byste měli dát uživateli vědět, že žádost o aktualizaci je zařazena do fronty pro pozdější zpracování.

  • Aktualizace můžete zapisovat do účtu úložiště v jiné oblasti. Když se primární oblast vrátí do online režimu, můžete tyto aktualizace sloučit do primárních dat v závislosti na struktuře dat. Pokud například vytváříte samostatné soubory s datem a časovým razítkem v názvu, můžete tyto soubory zkopírovat zpět do primární oblasti. Toto řešení se může vztahovat na úlohy, jako jsou protokolování a data IoT.

Zpracování opakovaných pokusů

Aplikace, které komunikují se službami spuštěnými v cloudu, musí být citlivé na neplánované události a chyby, ke kterým může dojít. Tyto chyby můžou být přechodné nebo trvalé, od momentální ztráty připojení až po významný výpadek způsobený přírodní katastrofou. Je důležité navrhovat cloudové aplikace s odpovídajícím zpracováním opakování, aby se maximalizovala dostupnost a zlepšila celková stabilita aplikace.

Žádosti o čtení

Pokud primární oblast přestane být dostupná, je možné žádosti o čtení přesměrovat do sekundárního úložiště. Jak jsme uvedli dříve, musí být přijatelné, aby vaše aplikace potenciálně četla zastaralá data. Klientská knihovna Azure Storage nabízí možnosti pro zpracování opakovaných pokusů a přesměrování žádostí o čtení do sekundární oblasti.

V tomto příkladu je zpracování opakování pro úložiště objektů blob nakonfigurované ve BlobClientOptions třídě a bude platit pro BlobServiceClient objekt, který vytvoříme pomocí těchto možností konfigurace. Tato konfigurace je primárním a sekundárním přístupem, kdy se opakované pokusy o čtení z primární oblasti přesměrují do sekundární oblasti. Tento přístup je nejlepší, když se očekává, že selhání v primární oblasti budou dočasná.

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);

Pokud zjistíte, že primární oblast bude pravděpodobně po dlouhou dobu nedostupná, můžete nakonfigurovat všechny žádosti o čtení tak, aby odkazovali na sekundární oblast. Tato konfigurace je pouze sekundární přístup. Jak už jsme si řekli dříve, budete potřebovat strategii pro zpracování žádostí o aktualizace během této doby a způsob, jak uživatele informovat, že se zpracovávají jenom žádosti o čtení. V tomto příkladu vytvoříme novou instanci BlobServiceClient , která používá koncový bod sekundární oblasti.

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);

Informace o tom, kdy přepnout do režimu jen pro čtení a sekundárních požadavků, je součástí vzoru návrhu architektury označovaného jako model Jistič, který bude popsán v pozdější části.

Žádosti o aktualizaci

Žádosti o aktualizaci není možné přesměrovat do sekundárního úložiště, které je jen pro čtení. Jak je popsáno výše, vaše aplikace musí být schopná zpracovávat žádosti o aktualizaci , když primární oblast není k dispozici.

Model Jistič se dá použít také k aktualizaci požadavků. Pokud chcete zpracovávat chyby požadavků na aktualizaci, můžete v kódu nastavit prahovou hodnotu, například 10 po sobě jdoucích selhání, a sledovat počet selhání požadavků na primární oblast. Jakmile je prahová hodnota dosažena, můžete aplikaci přepnout do režimu jen pro čtení, aby se už nevydávané žádosti o aktualizaci primární oblasti.

Implementace modelu Jistič

Zpracování selhání, ze kterého může zotavení trvat různě dlouho, je součástí vzoru návrhu architektury označovaného jako model Jistič. Správná implementace tohoto modelu může aplikaci zabránit v opakovaném pokusu o provedení operace, která pravděpodobně selže, a zlepšit tak stabilitu a odolnost aplikace.

Jedním z aspektů modelu Jistič je identifikace aktuálního problému s primárním koncovým bodem. Abyste to mohli zjistit, můžete sledovat, jak často se klient setkává s chybami, které se dají opakovat. Vzhledem k tomu, že se každý scénář liší, musíte určit vhodnou prahovou hodnotu, kterou byste měli použít pro rozhodnutí přepnout na sekundární koncový bod a spustit aplikaci v režimu jen pro čtení.

Můžete se například rozhodnout provést přepnutí, pokud v primární oblasti dojde k 10 po sobě jdoucích selhání. Můžete to sledovat tak, že v kódu ponecháte počet selhání. Pokud dojde k úspěchu před dosažením prahové hodnoty, nastavte počet zpět na nulu. Pokud počet dosáhne prahové hodnoty, přepněte aplikaci tak, aby pro žádosti o čtení používala sekundární oblast.

Jako alternativní přístup byste se mohli rozhodnout implementovat do aplikace vlastní monitorovací komponentu. Tato komponenta může nepřetržitě otestovat váš primární koncový bod úložiště příkazem ping pomocí triviálních požadavků na čtení (například čtení malého objektu blob), aby se zjistil její stav. Tento přístup by zabral určité prostředky, ale ne významné množství. Když zjistíte problém, který dosáhne vaší prahové hodnoty, přepnete do režimu jen sekundárního čtení a do režimu jen pro čtení. V tomto scénáři můžete při opětovném úspěšném spuštění příkazu ping na primární koncový bod úložiště přepnout zpět do primární oblasti a pokračovat v povolování aktualizací.

Prahová hodnota chyby použitá k určení, kdy provést přepnutí, se může v jednotlivých službách v rámci vaší aplikace lišit, takže byste měli zvážit jejich nastavení konfigurovatelných parametrů.

Dalším aspektem je, jak zpracovat více instancí aplikace a co dělat, když v každé instanci zjistíte chyby, které se dají opakovat. Můžete mít například 20 virtuálních počítačů se stejnou načtenou aplikací. Zpracováváte každou instanci samostatně? Pokud u jedné instance začnou mít problémy, chcete omezit odpověď jenom na tuto instanci? Nebo chcete, aby všechny instance reagovaly stejným způsobem, když má jedna instance problém? Zpracování instancí samostatně je mnohem jednodušší než se snažit koordinovat odpověď mezi nimi, ale váš přístup bude záviset na architektuře vaší aplikace.

Zpracování nakonec konzistentních dat

Geograficky redundantní úložiště funguje tak, že replikuje transakce z primární do sekundární oblasti. Proces replikace zaručuje, že data v sekundární oblasti budou nakonec konzistentní. To znamená, že všechny transakce v primární oblasti se nakonec zobrazí v sekundární oblasti, ale může dojít k prodlevě, než se zobrazí. Také není zaručeno, že transakce dorazí do sekundární oblasti ve stejném pořadí, v jakém byly původně použity v primární oblasti. Pokud vaše transakce dorazí do sekundární oblasti mimo pořadí , můžete považovat data v sekundární oblasti za nekonzistentní, dokud se služba nezachytí.

Následující příklad pro Azure Table Storage ukazuje, co se může stát, když aktualizujete podrobnosti o zaměstnanci tak, aby byl členem role správce. Pro účely tohoto příkladu je potřeba aktualizovat entitu zaměstnanec a aktualizovat entitu role správce celkovým počtem správců. Všimněte si, jak se aktualizace v sekundární oblasti aplikují mimo pořadí.

Čas Transakce Replikace Čas poslední synchronizace Výsledek
T0 Transakce A:
Vložit zaměstnance
entita v primárním
Transakce A vložena do primárního,
se ještě nereplikoval.
T1 Transakce A
replikováno do
Sekundární
T1 Transakce A replikovaná do sekundární.
Čas poslední synchronizace se aktualizoval.
T2 Transakce B:
Aktualizace
entita employee
v primárním
T1 Transakce B zapsaná na primární,
se ještě nereplikoval.
T3 Transakce C:
Aktualizace
správce
entita role v
Primární
T1 Transakce C zapsaná na primární,
se ještě nereplikoval.
T4 Transakce C
replikováno do
Sekundární
T1 Transakce C replikovaná do sekundární.
LastSyncTime se neaktualizoval, protože
transakce B ještě nebyla replikována.
T5 Čtení entit
ze sekundárního
T1 Získáte zastaralou hodnotu pro zaměstnance.
entita, protože transakce B nemá
dosud replikovaných. Získáte novou hodnotu pro
entita role správce, protože jazyk C má
Replikované. Čas poslední synchronizace stále není
byla aktualizována, protože transakce B
se nereplikoval. Poznáte
Entita role správce je nekonzistentní
protože datum a čas entity je následující
čas poslední synchronizace.
T6 Transakce B
replikováno do
Sekundární
T6 T6 – Všechny transakce přes C mají
replikováno, čas poslední synchronizace
se aktualizuje.

V tomto příkladu předpokládejme, že klient přepne na čtení ze sekundární oblasti na T5. V tuto chvíli může úspěšně číst entitu role správce , ale entita obsahuje hodnotu počtu správců, která není konzistentní s počtem entit zaměstnanců , které jsou v tuto chvíli označené jako správci v sekundární oblasti. Klient může zobrazit tuto hodnotu s rizikem, že informace budou nekonzistentní. Případně se klient může pokusit zjistit, že role správce je v potenciálně nekonzistentním stavu, protože aktualizace proběhly v opačném pořadí, a pak uživatele o této skutečnosti informovat.

Pokud chcete zjistit, jestli má účet úložiště potenciálně nekonzistentní data, může klient zkontrolovat hodnotu vlastnosti Čas poslední synchronizace . Čas poslední synchronizace udává čas, kdy byla data v sekundární oblasti naposledy konzistentní a kdy služba použila všechny transakce před tímto bodem v čase. Ve výše uvedeném příkladu je po vložení entity zaměstnance do sekundární oblasti nastaven čas poslední synchronizace na T1. Zůstane na úrovni T1 , dokud služba neaktualizuje entitu zaměstnance v sekundární oblasti, když je nastavená na hodnotu T6. Pokud klient při čtení entity v T5 načte čas poslední synchronizace, může ho porovnat s časovým razítkem entity. Pokud je časové razítko entity pozdější než čas poslední synchronizace, je entita v potenciálně nekonzistentním stavu a můžete provést příslušnou akci. Použití tohoto pole vyžaduje, abyste věděli, kdy byla dokončena poslední aktualizace primárního serveru.

Informace o tom, jak zkontrolovat čas poslední synchronizace, najdete v tématu Kontrola vlastnosti Čas poslední synchronizace pro účet úložiště.

Testování

Je důležité otestovat, jestli se vaše aplikace chová podle očekávání, když narazí na opakovatelné chyby. Musíte například otestovat, že se aplikace přepne do sekundární oblasti, když zjistí problém, a pak se přepne zpět, až bude primární oblast znovu dostupná. Pokud chcete toto chování správně otestovat, potřebujete způsob, jak simulovat opakovatelné chyby a řídit, jak často k nim dochází.

Jednou z možností je použít Fiddler k zachycení a úpravě odpovědí HTTP ve skriptu. Tento skript dokáže identifikovat odpovědi, které pocházejí z primárního koncového bodu, a změnit stavový kód HTTP na takový, který klientská knihovna služby Storage rozpozná jako chybu, která se dá opakovat. Tento fragment kódu ukazuje jednoduchý příklad fiddlerového skriptu, který zachytává odpovědi na žádosti o čtení v tabulce employeedata a vrací stav 502:

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

Tento příklad můžete rozšířit o zachycení širšího rozsahu požadavků a pouze změnit kód odpovědi u některých z nich, aby lépe simuloval skutečný scénář. Další informace o přizpůsobení skriptů Fiddler najdete v tématu Úprava požadavku nebo odpovědi v dokumentaci fiddler.

Pokud jste nastavili konfigurovatelné prahové hodnoty pro přepnutí aplikace na jen pro čtení, bude jednodušší otestovat chování s neprodukčními objemy transakcí.


Další kroky

Kompletní ukázku ukazující, jak přepínat mezi primárním a sekundárním koncovým bodem, najdete v tématu Ukázky Azure – Použití vzoru jističe s úložištěm RA-GRS.