Scénář optimalizace výkonu: distribuované obchodní transakce

Tento článek popisuje, jak vývojový tým použil metriky k nalezení kritických bodů a zlepšení výkonu distribuovaného systému. Článek vychází ze skutečného zátěžového testování, které jsme pro ukázkovou aplikaci použili. Aplikace pochází ze směrného plánu služby Azure Kubernetes (AKS) pro mikroslužby.

Tento článek je součástí série. Přečtěte si tuprvní část.

Scénář: klientská aplikace zahájí obchodní transakci, která zahrnuje několik kroků.

Tento scénář zahrnuje aplikaci pro doručování pomocí dronů, která běží na AKS. Zákazníci používají webovou aplikaci k naplánování dodávek od pomocí dronů. Každá transakce vyžaduje více kroků, které jsou prováděny samostatnými mikroslužbami v back-endu:

  • Doručovací služba spravuje dodávky.
  • Služba plánovače pomocí dronů plánuje DRONY zachraňují životy pro vyzvednutí.
  • Služba balíčku spravuje balíčky.

Existují dvě další služby: službu ingestování, která přijímá požadavky klientů a ukládá je do fronty ke zpracování, a službu pracovního postupu, která koordinuje kroky v pracovním postupu.

Diagram znázorňující distribuovaný pracovní postup

Další informace o tomto scénáři najdete v tématu navrhování architektury mikroslužeb.

Test 1: směrný plán

U prvního zátěžového testu vytvořil tým cluster AKS s šesti uzly a nasadil tři repliky každé mikroslužby. Zátěžový test byl testem zátěžového testu, který začíná dvěma simulovanými uživateli a rozkládá až 40 simulovaných uživatelů.

Nastavení Hodnota
Uzly clusteru 6
Podů 3 na službu

Následující graf ukazuje výsledky zátěžového testu, jak je znázorněno v Visual Studio. Fialová čára vykresluje uživatelské zatížení a oranžový řádek vykresluje celkový počet požadavků.

Graph výsledků zátěžového testu Visual Studio

První věc, kterou je potřeba využít k tomuto scénáři, je to, že požadavky klientů za sekundu nejsou užitečnou metrikou výkonu. Důvodem je, že aplikace zpracovává požadavky asynchronně, takže klient obdrží odpověď hned. Kód odpovědi je vždy HTTP 202 (přijato), což znamená, že žádost byla přijata, ale zpracování není dokončeno.

To, co opravdu chceme znát, je, zda se v back-endu zachovává frekvence požadavků. fronta Service Bus může absorbovat špičky, ale pokud back-end nedokáže zpracovat trvalé zatížení, bude zpracování zachováno ještě dál a dále.

Tady je další informativní graf. vykreslí počet příchozích a odchozích zpráv ve frontě Service Bus. Příchozí zprávy jsou zobrazovány světle modře a odchozí zprávy jsou zobrazeny tmavě modře:

Graph příchozích a odchozích zpráv

Tento graf znázorňuje, že se zvyšuje rychlost příchozích zpráv, dosáhlo se špičky a pak se na konci zátěžového testu vrátí zpět na nulu. Ale počet odchozích zpráv se zachází do začátku v testu a pak se ve skutečnosti vyřazuje. To znamená, že služba pracovního postupu, která zpracovává požadavky, nezůstane zachovává. I po ukončení zátěžového testu (okolo 9:22 v grafu) se zprávy stále zpracovávají, protože služba pracovního postupu pokračuje ve vyřazení fronty.

Co zpomaluje zpracování? První věc, kterou je třeba vyhledat, jsou chyby nebo výjimky, které mohou signalizovat systematický problém. Mapa aplikace v Azure monitor zobrazuje graf volání mezi komponentami a představuje rychlý způsob, jak vymezit problémy a potom kliknutím na tlačítko získat další podrobnosti.

Je-li to nutné, mapa aplikace zobrazí, že služba pracovního postupu získává chyby ze služby doručování:

Snímek obrazovky s mapou aplikace

Chcete-li zobrazit další podrobnosti, můžete vybrat uzel v grafu a kliknout na koncové zobrazení transakce. V takovém případě se zobrazí, že služba doručování vrací chyby HTTP 500. Chybové zprávy označují, že se vyvolala výjimka z důvodu omezení paměti v mezipaměti Azure pro Redis.

Snímek obrazovky se zobrazením kompletní transakce

Můžete si všimnout, že tato volání Redis se nezobrazují v mapě aplikace. to je proto, že knihovna .net pro Application Insights nemá integrovanou podporu pro sledování Redis jako závislosti. (Seznam podporovaných funkcí najdete v tématu Automatická kolekce závislostí.) Jako záložní můžete ke sledování libovolné závislosti použít rozhraní TrackDependency API. Zátěžové testování často odhaluje tyto druhy mezer v telemetrie, které je možné opravit.

Test 2: zvýšená velikost mezipaměti

Pro druhý zátěžový test zvýšil vývojový tým velikost mezipaměti v mezipaměti Azure cache pro Redis. (Viz Jak škálovat Azure cache pro Redis.) Tato změna vyřešila výjimky nedostatku paměti a teď mapa aplikace zobrazuje nulové chyby:

Snímek obrazovky s mapou aplikace ukazující, že zvýšení velikosti mezipaměti vyřešilo výjimky nedostatku paměti.

Stále ale dochází k výrazné prodlevě při zpracování zpráv. Ve špičce zátěžového testu je míra příchozích zpráv větší než 5 × a odchozí rychlost:

Graph příchozích a odchozích zpráv, které ukazují, že je míra příchozích zpráv větší než pětinásobné, je odchozí.

následující graf měří propustnost v souvislosti s doplňováním zpráv — , což je rychlost, s jakou služba pracovního postupu označí Service Busé zprávy jako dokončené. Každý bod v grafu představuje 5 sekund dat a zobrazuje maximální propustnost přibližně 16/s.

Graph propustnosti zprávy

Tento graf byl vygenerován spuštěním dotazu v pracovním prostoru Log Analytics pomocí dotazovacího jazyka Kusto:

let start=datetime("2020-07-31T22:30:00.000Z");
let end=datetime("2020-07-31T22:45:00.000Z");
dependencies
| where cloud_RoleName == 'fabrikam-workflow' 
| where timestamp > start and timestamp < end
| where type == 'Azure Service Bus' 
| where target has 'https://dev-i-iuosnlbwkzkau.servicebus.windows.net'
| where client_Type == "PC"
| where name == "Complete" 
| summarize succeeded=sumif(itemCount, success == true), failed=sumif(itemCount, success == false) by bin(timestamp, 5s)
| render timechart

Test 3: horizontální navýšení kapacity back-end služeb

Zdá se, že back-end je kritický bod. Jednoduchým dalším krokem je horizontální navýšení kapacity obchodních služeb (balení, doručování a pomocí dronů Scheduler) a zjištění, jestli se zvyšuje výkon. Pro další zátěžový test tým škáloval tyto služby ze tří replik na šest replik.

Nastavení Hodnota
Uzly clusteru 6
Služba příjmu dat 3 repliky
Služba pracovního postupu 3 repliky
Package, Delivery, pomocí dronů Scheduler Services 6 replik každý

Tento zátěžový test bohužel ukazuje pouze mírné zlepšení. Odchozí zprávy stále nepracují se příchozími zprávami:

Graph příchozích a odchozích zpráv, které ukazují, že odchozí zprávy stále nepracují s příchozími zprávami.

Propustnost je větší konzistence, ale maximální dosažená hodnota je stejná jako u předchozího testu:

Graph propustnosti zprávy ukazující, že maximální dosažená hodnota je stejná jako u předchozího testu.

Kromě toho se zdá, že při Azure monitor pro kontejneryse problém nezpůsobilo vyčerpání prostředků v clusteru. Za prvé metriky na úrovni uzlu ukazují, že využití CPU zůstává pod 40% i na 95. percentilu a využití paměti je přibližně 20%.

Graph využití uzlu AKS

V Kubernetes prostředí je možné, že jednotlivá Luska budou omezená na prostředky, a to i v případě, že uzly nejsou. Ale zobrazení na úrovni pod ukazuje, že všechny lusky jsou v dobrém stavu.

Graph využití v AKS pod

Z tohoto testu se zdá, že pouhým přidáním více lusků do back-endu nebude pomáhat. V dalším kroku se podíváme podrobněji na službu pracovního postupu, abyste zjistili, co se děje při zpracovávání zpráv. Application Insights ukazuje, že průměrná doba trvání operace služby pracovního postupu Process je 246 ms.

snímek obrazovky s Application Insights

Můžeme také spustit dotaz, který získá metriky pro jednotlivé operace v rámci každé transakce:

cílové percentile_duration_50 percentile_duration_95
https://dev-i-iuosnlbwkzkau.servicebus.windows.net/ | dev-i-iuosnlbwkzkau 86,66950203 283,4255578
doručení 37 57
package 12 17
dronescheduler 21 41

první řádek v této tabulce představuje frontu Service Bus. Ostatní řádky jsou volání služby back-end. Pro referenci tady je Log Analytics dotaz pro tuto tabulku:

let start=datetime("2020-07-31T22:30:00.000Z");
let end=datetime("2020-07-31T22:45:00.000Z");
let dataset=dependencies
| where timestamp > start and timestamp < end
| where (cloud_RoleName == 'fabrikam-workflow')
| where name == 'Complete' or target in ('package', 'delivery', 'dronescheduler');
dataset
| summarize percentiles(duration, 50, 95) by target

Snímek obrazovky s Log Analytics výsledků dotazu

Tyto latence vypadají rozumným způsobem. Ale tady je klíč Insight: Pokud celkový čas operace je ~ 250 ms, která představuje přísnou horní mez toho, jak se dají rychlé zprávy zpracovávat v sériovém tvaru. Klíč ke zlepšení propustnosti je proto větší paralelismu.

To by mělo být možné v tomto scénáři, a to ze dvou důvodů:

  • Jedná se o síťová volání, takže většina času stráví čekání na dokončení vstupně-výstupních operací.
  • Zprávy jsou nezávislé a nemusíte je zpracovávat v daném pořadí.

Test 4: zvýšení paralelismu

Pro tento test se tým zaměřuje na zvýšení paralelismu. pokud to chcete udělat, upravili jsme dvě nastavení na Service Bus klientu, který používá služba pracovního postupu:

Nastavení Popis Výchozí Nová hodnota
MaxConcurrentCalls Maximální počet zpráv, které mají být zpracovány současně. 1 20
PrefetchCount Kolik zpráv bude klient načítat před časem do místní mezipaměti. 0 3000

další informace o těchto nastaveních najdete v tématu osvědčené postupy pro zlepšení výkonu pomocí Service Bus zasílání zpráv. Spuštění testu s tímto nastavením vyprodukuje následující graf:

Graph příchozích a odchozích zpráv zobrazujících počet odchozích zpráv, které ve skutečnosti překračují celkový počet příchozích zpráv.

Odvolat, že příchozí zprávy jsou zobrazeny modře a odchozí zprávy jsou zobrazeny tmavě modře.

Na první pohled se jedná o velmi divné graf. Za chvíli se míra odchozích zpráv přesně sleduje jenom příchozí. Ale potom v přibližně 2:03 se míra příchozích zpráv vypíná, zatímco počet odchozích zpráv se pořád zvyšuje, ale celkový počet příchozích zpráv je dál vyšší. To zřejmě není možné.

potvrzení na tento mystery najdete v zobrazení závislosti v Application Insights. Tento graf shrnuje všechna volání, která služba pracovního postupu provedla, Service Bus:

Graph volání závislostí

Všimněte si, že položka pro DeadLetter . tato volání označují, že se zprávy přecházejí do fronty nedoručenýchzpráv Service Bus.

Chcete-li zjistit, co se děje, je nutné pochopit sémantiku prohlížení v Service Bus. když klient používá nástroj pro prohlížení zámku, Service Bus atomicky načte a zamkne zprávu. I když je zámek uložený, zpráva se garantuje, že se nebude doručovat jiným příjemcům. Pokud zámek vyprší, bude zpráva k dispozici ostatním příjemcům. po maximálním počtu pokusů o doručení (které lze konfigurovat) Service Bus umístí zprávy do fronty nedoručenýchzpráv, kde je lze prozkoumat později.

Mějte na paměti, že služba pracovního postupu předběžné načítání velkých dávkových zpráv — 3000 zpráv. To znamená, že celková doba zpracování každé zprávy je delší, což vede k vypršení časového limitu zpráv, k návratu do fronty a nakonec ke frontě nedoručených zpráv.

Toto chování lze také zobrazit v výjimkách, kde MessageLostLockException je zaznamenáno množství výjimek:

snímek obrazovky s Application Insightsmi výjimkami znázorňujícími množství výjimek MessageLostLockException.

Test 5: prodloužit dobu trvání zámku

Pro tento zátěžový test byla doba trvání zámku zprávy nastavena na 5 minut, aby se zabránilo vypršení časových limitů zámků. Graf příchozích a odchozích zpráv nyní ukazuje, že systém udržuje rychlost příchozích zpráv:

Graph příchozích a odchozích zpráv, které ukazují, že systém udržuje počet příchozích zpráv.

Po celkovém trvání 8 minut zátěžového testu aplikace dokončila 25 KB operací s špičkou propustnosti 72 operací/s, která představuje 400% zvýšení maximální propustnosti.

Graph propustnosti zprávy ukazující 400% zvýšení maximální propustnosti.

Nicméně spuštění stejného testu s delší dobou trvání ukázalo, že aplikace nemůže tolerovat tuto rychlost:

Graph příchozích a odchozích zpráv, které ukazují, že aplikace nemohla tuto rychlost tolerovat.

Metriky kontejneru ukazují, že maximální využití CPU bylo blízko až 100%. V tomto okamžiku se aplikace zdá být vázaná na procesor. Škálování clusteru může nyní zvýšit výkon na rozdíl od předchozího pokusu o horizontální navýšení kapacity.

Graph využití uzlu AKS ukazuje, že maximální využití CPU bylo blízko 100%.

Test 6: horizontální navýšení kapacity back-end služeb (znovu)

Pro finální zátěžový test v řadě tým škáluje cluster Kubernetes a lusky následujícím způsobem:

Nastavení Hodnota
Uzly clusteru 12
Služba příjmu dat 3 repliky
Služba pracovního postupu 6 replik
Package, Delivery, pomocí dronů Scheduler Services 9 replik každý

Výsledkem tohoto testu je vyšší dlouhodobá propustnost, bez významného prodlevy ve zpracování zpráv. Kromě toho využití CPU uzlu nechali nižší než 80%.

Graph propustnosti zpráv s vyšší trvalou propustností, a to bez významného prodlevy ve zpracování zpráv.

Souhrn

V tomto scénáři byly zjištěny následující kritické body:

  • Výjimky z důvodu nedostatku paměti v mezipaměti Azure pro Redis
  • Nedostatečná paralelismus při zpracování zpráv.
  • Nedostatečná doba trvání zámku zprávy, což vede k uzamknutí časových limitů a zpráv umístěných do fronty nedoručených zpráv.
  • Vyčerpání procesoru.

Pro diagnostiku těchto problémů vývojový tým spoléhal na následující metriky:

  • míra příchozích a odchozích zpráv Service Bus.
  • mapa aplikace v Application Insights.
  • Chyby a výjimky.
  • Vlastní dotazy Log Analytics.
  • Využití CPU a paměti v Azure Monitor pro kontejnery.

Další kroky

Další informace o návrhu tohoto scénáře najdete v tématu navrhování architektury mikroslužeb.