Antipattern pro opakování Stormu
Pokud je služba nedostupná nebo zaneprázdněná, může příliš časté opakování připojení klientů způsobit potíže s obnovením služby a může to problém ještě zhoršit. Také nedává smysl opakovat to donekonečna, protože žádosti jsou obvykle platné pouze po definované časové období.
Popis problému
V cloudu mají služby někdy problémy a stanou se nedostupnými pro klienty nebo musí omezit nebo omezit rychlost svých klientů. I když je vhodné, aby klienti zkusili neúspěšná připojení ke službám opakovat, je důležité, aby se neopakovali příliš často nebo příliš dlouho. Opakované pokusy během krátkého časového období pravděpodobně nebudou úspěšné, protože služby se pravděpodobně neobnoví. Služby navíc můžou být ještě více zatížené, když se během pokusu o obnovení provádí velké množství pokusů o připojení, a opakované pokusy o připojení můžou službu dokonce zahltit a zhoršovat základní problém.
Následující příklad ukazuje scénář, kdy se klient připojuje k serverovém rozhraní API. Pokud požadavek neuspěje, klient se okamžitě pokusí opakovat a bude to pořád opakovat. Tento druh chování je často jemnější než v tomto příkladu, ale platí stejný princip.
public async Task<string> GetDataFromServer()
{
while(true)
{
var result = await httpClient.GetAsync(string.Format("http://{0}:8080/api/...", hostName));
if (result.IsSuccessStatusCode) break;
}
// ... Process result.
}
Jak problém vyřešit
Klientské aplikace by měly dodržovat některé osvědčené postupy, aby nedošlo k opakovanému za stormu.
- Zasadíte počet opakovaných pokusů a neudržujte opakování po dlouhou dobu. I když se může zdát snadné napsat smyčku
while(true)
, téměř jistě nechcete, aby se to po dlouhou dobu skutečně opakovat, protože situace, která vedla k zahájení žádosti, se pravděpodobně změnila. Ve většině aplikací stačí opakování po dobu několika sekund nebo minut. - Pozastavte se mezi opakovanými pokusy. Pokud je služba nedostupná, je nepravděpodobné, že by bylo úspěšné okamžité opakování. Postupně prodlužujte dobu čekání mezi pokusy, například pomocí exponenciální strategie zpochybnění.
- Řádné zpracování chyb Pokud služba nereaguje, zvažte, jestli má smysl pokus přerušit a vrátit chybu zpět uživateli nebo volajícímu vaší komponenty. Při návrhu aplikace zvažte tyto scénáře selhání.
- Zvažte použití vzoru Jistič, který je navržený speciálně tak, aby se zabránilo opakovaným bouřím.
- Pokud server poskytuje hlavičku
retry-after
odpovědi, ujistěte se, že se nepokusíte opakovat akci, dokud neuplyne zadané časové období. - Při komunikaci se službami Azure používejte oficiální sady SDK. Tyto sady SDK mají obecně integrované zásady opakování a ochranu proti vzniku nebo přispívání k opakovaným bouřím. Pokud komunikujete se službou, která nemá sadu SDK nebo kde sada SDK nezpracuje správně logiku opakování, zvažte použití knihovny, jako je Polly (pro .NET), nebo opakování (pro JavaScript), abyste mohli správně zpracovat logiku opakování a vyhnout se psaní kódu sami.
- Pokud používáte prostředí, které ho podporuje, použijte k odesílání odchozích volání síť služby (nebo jinou vrstvu abstrakce). Tyto nástroje, například Dapr, obvykle podporují zásady opakování a automaticky se řídí osvědčenými postupy, jako je například vypnutí po opakovaných pokusech. Tento přístup znamená, že nemusíte psát kód opakování sami.
- Zvažte dávkování požadavků a použití sdružování žádostí tam, kde je to k dispozici. Mnoho sad SDK zpracovává dávky požadavků a sdružování připojení vaším jménem, což sníží celkový počet odchozích pokusů o připojení, které vaše aplikace provede, i když stále musíte být opatrní, abyste se tato připojení nezkoušeli příliš často.
Služby by se také měly chránit před opakovanými bouřemi.
- Přidejte vrstvu brány, abyste mohli během incidentu vypnout připojení. Toto je příklad modelu Přepážka. Azure poskytuje mnoho různých služeb brány pro různé typy řešení, včetně služby Front Door, Application Gateway a API Management.
- Omezte požadavky na bránu, což zajistí, že nebudete přijímat tolik požadavků, aby back-endové komponenty nemohly dál fungovat.
- Pokud dochází k omezování, pošlete zpátky hlavičku
retry-after
, která klientům pomůže pochopit, kdy se mají připojení znovu připojit.
Požadavky
- Klienti by měli zvážit typ vrácené chyby. Některé typy chyb neindikují selhání služby, ale místo toho indikují, že klient odeslal neplatný požadavek. Pokud například klientská aplikace obdrží chybovou
400 Bad Request
odpověď, opakování stejného požadavku pravděpodobně nepomůže, protože server vám říká, že váš požadavek není platný. - Klienti by měli zvážit dobu, po kterou je vhodné připojení obnovit. Doba, po kterou byste měli opakovat, se bude řídit vašimi obchodními požadavky a tím, jestli můžete přiměřeně rozšířit chybu zpět na uživatele nebo volajícího. Ve většině aplikací stačí opakování po dobu několika sekund nebo minut.
Jak zjistit problém
Z pohledu klienta můžou příznaky tohoto problému zahrnovat velmi dlouhou dobu odezvy nebo zpracování spolu s telemetrií, která značí opakované pokusy o opakování připojení.
Z pohledu služby mohou příznaky tohoto problému zahrnovat velký počet požadavků od jednoho klienta během krátkého časového období nebo velký počet požadavků od jednoho klienta při zotavení z výpadků. Mezi příznaky můžou patřit také potíže při obnovování služby nebo průběžná kaskádová selhání služby hned po opravě chyby.
Ukázková diagnostika
Následující části znázorňují jeden přístup ke zjištění potenciálního útoku opakování, a to jak na straně klienta, tak na straně služby.
Identifikace z telemetrie klienta
Aplikace Azure Insights zaznamenává telemetrii z aplikací a zpřístupňuje data pro dotazování a vizualizaci. Odchozí připojení se sledují jako závislosti a informace o nich se dají získat a vymapovat, aby bylo možné určit, kdy klient provádí velký počet odchozích požadavků na stejnou službu.
Následující graf byl převzat z karty Metriky na portálu Application Insights a zobrazil metriku Selhání závislostí rozdělenou podle názvu vzdálené závislosti. To ukazuje scénář, kdy během krátké doby došlo k velkému počtu (více než 21 000) neúspěšných pokusů o připojení k závislosti.
Identifikace z telemetrie serveru
Serverové aplikace můžou být schopné rozpoznat velký počet připojení z jednoho klienta. V následujícím příkladu funguje Služba Azure Front Door jako brána pro aplikaci a je nakonfigurovaná tak, aby protokolovala všechny požadavky do pracovního prostoru služby Log Analytics.
Ve službě Log Analytics je možné provést následující dotaz Kusto. Identifikuje IP adresy klientů, které během posledního dne odeslaly do aplikace velký počet požadavků.
AzureDiagnostics
| where ResourceType == "FRONTDOORS" and Category == "FrontdoorAccessLog"
| where TimeGenerated > ago(1d)
| summarize count() by bin(TimeGenerated, 1h), clientIp_s
| order by count_ desc
Spuštění tohoto dotazu během opakovaného útoku ukazuje velký počet pokusů o připojení z jedné IP adresy.