Stále se potkávám se snahou řešit potřebu dohledu aplikace infrastrukturními prostředky. Je vám tohle povědomé?
Řešením je samozřejmě monitoring na úrovni aplikace, protože tam se dozvíme opravdu nejvíc. Ale pak očekávám následující dvě obvyklé námitky:
Nutnost změnit kód je, jak už jsem vlastně psal, často brzdou nasazení aplikačního monitoringu. Neměla by být - vývoj software je přece k ničemu, když ho nejste schopni efektivně provozovat a to je zejména v éře mikroslužeb obtížné bez aplikačního monitoringu. Kolik vás stojí to, že raději nafouknete všechny zdroje na dvojnásobek (v cloudu se díky transparentnosti nákladů dá na tohle velmi dobře odpovědět)? Kolik vás stojí výpadky? Kolik naštvaný uživatel, kterému to jede pomalu? Investice do dobré provozovatelnosti by zkrátka měla být jedním ze zásadních nefunkčních požadavků na vývoj stejně jako třeba bezpečnost.
Ale zpět k tématu - někdy to prostě nejde nebo to nejde hned. V mnoha případech ale není nic ztraceno a je možné použít codeless attach neboli auto-instrumentation. Potřebné háčky do aplikace, které tuhle něco změří, odešlou, přidají hlavičku, se dají udělat i bez změny kódu. Monitorovací agent se napojí na proces v hostitelském serveru jako je Tomcat pro Javu nebo IIS pro .NET a automaticky rozezná použité frameworky a začne monitorovat. V případě Python se pak třeba aplikace spouští přes “zavaděč”, který aplikaci obohatí a tak podobně. Techniky jsou různé. U PaaS služeb jako je Azure App Service se to může stát přímo v platformě, u kontejnerové aplikace v Azure Kubernetes Service se to dá zařídit konceptem sidecar u aplikace a k tomu kolektor, v on-prem VM stačí pustit agenta jako další proces v JVM a tak podobně.
Skvělé - proč se tedy vůbec zabývat instrumentací přímo v kódu? Má codeless attach nějaké nevýhody?
Na trhu je spousta proprietárních systémů (Azure Monitor, Dynatrace, Datadog, X-Ray+CloudWatch, New Relic), které řeší problém v celé své škále. K tomu si můžete poskládat řešení z open source, ale jako vždy každou komponentu řeší něco jiného a navíc jsou mezi nimi alternativy. Trasování dělá třeba Zipkin (s pochybnou governance projektu) a Jaeger (CNCF), metriky hezky sbírá Prometheus, logy kombinace Logstash nebo Fluentd a Elastic, vizualizace metrik Grafana, vizualizace Elastiku Kibana a tak podobně. Místo jednoho řešení s podporou máte volně integrované komponenty a spoustu práce. Často pak vídám nasazení monitoringu do stejného prostředí jako aplikaci a v okamžiku kdy prostředí z důvodu nějaké havárie zmizí (třeba přijdete o svůj Kubernetes cluster i s daty), je docela škoda, že už nikdy nezjistíte co se vlastně dělo. Mám učinit svůj kód specifický pro nějaký konkrétní systém? To je těžké rozhodování a naděje v open source mě nezachrání (viz Zipkin vs. Jaeger).
Pokusy o vytvoření standardizovaného open source způsobu instrumentace aplikace už nějakou dobu běží. Smyslem je vytvořit otevřené API a SDK, takže aplikaci je nutné obohatit pouze jednou a na ni si pak napojit systém dle vlastní volby. Můžu využít obrovské síly komerčních řešení s pokročilými funkcemi včetně umělé inteligence nebo si to pytlíkovat sám v open source (nebo se to rozhodnu v provozu neřešit, protože na to nejsou peníze a čas a vrátím se k tomu až po prvních pár nocích s problémem, který nechá aplikaci žít, ale dělá ji občas nepoužitelně pomalou a moje CPU metrika mi nepomohla a v logu sice nacházím error, ale nevím ke které transakci patří) a přitom můj kód se tím nemění. Bohužel i tady se objevily dva projekty se vzájemným překryvem - OpenCensus a OpenTracing. Naštěstí se oba projekty dohodly a spojily do jednoho většího - OpenTelemetry.
Výbornou kombinací pro aplikační monitoring je vidět jednotlivé události jako systém návazností (trasování), měřit aplikační metriky (metrics) a logovat co se aktuálně děje ať už špatného nebo dobrého, ale zásadního (logging).
Kdo co zavolal, co se mu vrátilo, na co čekal a jak dlouho to trvalo? Jaký byl kontext toho volání, například na co se té databáze ptal a pro kterého uživatele? Distribuované trasování by mi mělo vytvořit orientovaný acyklický graf, nejčastěji graficky znázorněný jako časová osa událostí. Pokud se podaří kontext a korelační identifikátory předávat mezi systémy, měl by ideálem být stav, kdy v Angular kódu jedu od toho, že přihlášený uživatel Franta kliknul na tlačítko, to udělalo nějakou akci v browseru, která zavolala dvě backend API, ta následně provolala další, jednou se šlo přes frontu, tady je volání do databáze s tímto SELECTem a tady je volání nemonitorovaného externího systému (třeba SAP) a takhle dlouho mu trvala odpověď. Jasně - ne vždy se vyplatí takhle trasovat všechno, takže dává smysl nasadit nějaký sampling a tak podobně.
Díky trasování bych měl vidět svůj systém jako časovou osu pro akci uživatele a schápat tak co s čím a jak.
Druhým důležitým aspektem pro mě budou různé čitače. Kromě obligátních infrastrukturních ukazatelů tady očekávám aplikační věci. Počet requestů na danou instanci, rychlosti odbavení, statistiky chyb, velikosti requestů, počet dokončených objednávek, počet odeslaných potvrzení na email, délka neodbavené fronty požadavků, počet současně řešených požadavků, cache hit vs. miss a tak podobně. Smyslem je schopnost identifikovat negativní trendy nebo anomálie jednotlivých komponent nebo aspektů systému a reagovat na ně ať už automatizovaně (například autoškálováním) nebo ručně (hmm, jak to, že to tak často není v cache, možná ji nějakou operací nevhodně proplachuju nebo ji neplním po restartu a dlouho se učí).
Jak se píše v New Yorksém metru - když něco (nedobrého) vidíš, řekni to. O téhle disciplíně není na rozdíl od trasování a aplikačních metrik nikde diskuse o vhodnosti takové investice, logování je zkrátka zažité. To, že by se sbíralo na soubor ve VM asi netřeba komentovat - zuřiví provozáci logující se vzdáleně do OS všech komponent pokulhávajícího systému ideálně pod rootem nejen, že nemají potřebnou rychlost, efektivitu a schopnost korelovat hlášky z různých součástek, ale jejich přístup je bezpečnostní i provozní riziko. Logování na Syslog server, aby se dalo odškrtnout, že to máme, ale logy jsou dobré tak akorát na to, aby se po havárii a odebraných bonusech dalo o víkendu pročítat co to teda vlastně způsobilo, také není ideální cesta. Nepochybně logy patří do centrálního systému s možností v nich efektivně vyhledávat v téměř reálném čase přes nějaký query jazyk včetně věcí jako je parsování, full text a složitější dotazy, joinování dat z různých systémů, vizualizace a reporting až po nějaké sofistikovanější kousky jako je autobasket či clustering (techniky strojového učení hledající podobnosti v hláškách nebo seskupování do kategorií podle obsahu - tak například hláška “brutální error na adrese 0x4a2bc6, restartuju se”, kde se adresa pokaždé mění je rozhodně lépe viditelná, když dostanu výstup typu 1000x byl brutální error s restartem, jen adresa se měnila).
Ideálem tady je schopnost obohatit hlášku v logu kontextem (korelačním id) z distribuovaného trasování. Pokud celá ta Frantova akce s tlačítkem nakonec skončila nějakou nepříjemnou výjimkou v kódu jednoho z backendů, bylo by fajn na té časově ose v tomto místě vidět červeně jak se tato služba obrací na záda odhaluje svůj backtrace.
Výbornou odpovědí na instrumentaci aplikace standardizovaným způsobem je OpenTelemetry. Projekt je sice v beta fázi, ale to neznamená, že není ideální čas se s ním začít seznamovat notabene, když za ním stojí firmy jako je Google, Microsoft, Dynatrace, Uber a řada dalších. Příště se na projekt a specifikaci podíváme detailněji a začneme si ho i prakticky zkoušet, protože exporter do Azure Monitor Application Insights už je v betě.
A jak dnes řešíte aplikační monitoring vy?