Profiler JVM: | Uber Engineering Blog

JVM Profiler: Open Source Tool for Tracing Distributed JVM Applications at Scale:
954 Shares

Výpočetní rámce jako Apache Spark byly široce přijaty pro vytváření rozsáhlých datových aplikací. Pro společnost Uber jsou data základem strategického rozhodování a vývoje produktů. Abychom tato data mohli lépe využívat, spravujeme masivní nasazení Sparku v našich globálních inženýrských kancelářích.

Ačkoli Spark zpřístupňuje datové technologie, správné dimenzování zdrojů přidělených aplikacím Spark a optimalizace provozní efektivity naší datové infrastruktury vyžaduje jemnější poznatky o těchto systémech, konkrétně o vzorcích jejich využívání zdrojů.

Abychom mohli tyto vzorce vytěžit, aniž bychom měnili uživatelský kód, vytvořili jsme a otevřeli JVM Profiler, distribuovaný profiler, který shromažďuje metriky výkonu a využívání zdrojů a slouží k další analýze. Ačkoli byl vytvořen pro Spark, jeho obecná implementace jej umožňuje použít pro jakoukoli službu nebo aplikaci založenou na virtuálním stroji Java (JVM). Přečtěte si, jak společnost Uber používá tento nástroj k profilování našich aplikací Spark a jak jej můžete použít pro své vlastní systémy.

Problematika profilování

Společnost Uber denně podporuje desítky tisíc aplikací běžících na tisících strojích. Jak se náš technologický stack rozrůstal, rychle jsme si uvědomili, že naše stávající řešení pro profilování a optimalizaci výkonu nebude schopno uspokojit naše potřeby. Zejména jsme chtěli mít možnost:

Korelovat metriky napříč velkým počtem procesů na úrovni aplikace

V distribuovaném prostředí běží na stejném serveru více aplikací Spark a každá aplikace Spark má velký počet procesů (např. tisíce exekutorů) běžících na mnoha serverech, jak je znázorněno na obrázku 1:

Obrázek 1. V distribuovaném prostředí běží aplikace Spark na více serverech.

Naše stávající nástroje mohly sledovat pouze metriky na úrovni serveru a neměřily metriky pro jednotlivé aplikace. Potřebovali jsme řešení, které by dokázalo shromažďovat metriky pro jednotlivé procesy a korelovat je napříč procesy pro každou aplikaci. Navíc jsme nevěděli, kdy se tyto procesy spustí a jak dlouho budou trvat. Aby bylo možné v tomto prostředí sbírat metriky, musí se profiler spouštět automaticky s každým procesem.

Zajistit, aby sběr metrik nebyl rušivý pro libovolný uživatelský kód

Knihovny Spark a Apache Hadoop ve svých současných implementacích neexportují metriky výkonu; často však nastávají situace, kdy potřebujeme tyto metriky sbírat beze změny uživatelského kódu nebo kódu frameworku. Pokud například zaznamenáme vysokou latenci na jmenném uzlu distribuovaného souborového systému Hadoop (HDFS), chceme zkontrolovat latenci pozorovanou z každé aplikace Spark, abychom se ujistili, že tyto problémy nebyly replikovány. Vzhledem k tomu, že klientské kódy NameNode jsou vloženy uvnitř naší knihovny Spark, je těžkopádné upravovat její zdrojový kód a přidávat tuto specifickou metriku. Abychom udrželi krok s neustálým růstem naší datové infrastruktury, potřebujeme mít možnost kdykoli a bez nutnosti provádět změny v kódu provádět měření libovolné aplikace. Implementace neintruzivnějšího procesu sběru metrik by nám navíc umožnila dynamicky vkládat kód do metod Javy během načítání.

Představení nástroje JVM Profiler

Pro řešení těchto dvou výzev jsme vytvořili náš nástroj JVM Profiler a poskytli mu otevřený zdrojový kód. Existují některé existující open source nástroje, například statsd-jvm-profiler společnosti Etsy, které by mohly shromažďovat metriky na úrovni jednotlivých aplikací, ale neposkytují možnost dynamicky injektovat kód do existujících binárních souborů Javy a shromažďovat metriky. Inspirováni některými z těchto nástrojů jsme vytvořili náš profiler s ještě většími možnostmi, jako je profilování libovolných metod/argumentů Javy.

Co dělá JVM Profiler?

JVM Profiler se skládá ze tří klíčových funkcí, které usnadňují sběr metrik výkonu a využití zdrojů a následně tyto metriky (např. Apache Kafka) poskytují dalším systémům k další analýze:

  • Agent Javy: Začleněním agenta Javy do našeho profileru mohou uživatelé distribuovaně shromažďovat různé metriky (např. využití CPU/paměti) a stopy zásobníku pro procesy JVM.
  • Pokročilé možnosti profilování: Náš profilovač JVM umožňuje sledovat libovolné metody a argumenty jazyka Java v uživatelském kódu, aniž by bylo nutné provádět skutečné změny kódu. Tuto funkci lze použít ke sledování latence volání HDFS NameNode RPC u aplikací Spark a k identifikaci pomalých volání metod. Může také sledovat cesty k souborům HDFS, které každá aplikace Spark čte nebo zapisuje, a identifikovat tak horké soubory pro další optimalizaci.
  • Reportování v oblasti analýzy dat: Ve společnosti Uber používáme profiler k vykazování metrik do témat Kafka a tabulek Apache Hive, což urychluje a usnadňuje analýzu dat.

Typické případy použití

Náš JVM Profiler podporuje řadu případů použití, především umožňuje instrumentovat libovolný kód Javy. Pomocí jednoduché změny konfigurace se může JVM Profiler připojit ke každému spouštěči v aplikaci Spark a shromažďovat metriky běhu metod Java. Níže se dotkneme některých z těchto případů použití:

  • Správná velikost exekutoru: Pomocí metrik paměti z nástroje JVM Profiler sledujeme skutečné využití paměti pro každý executor, abychom mohli nastavit správnou hodnotu argumentu Spark “executor-memory”.
  • Sledujeme latenci RPC HDFS NameNode: Profilujeme metody třídy org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolTranslatorPB v aplikaci Spark a identifikujeme dlouhé latence při volání NameNode. Denně monitorujeme více než 50 tisíc aplikací Spark s několika miliardami takových RPC volání.
  • Sledujte události přerušení ovladače: Profilujeme metody jako org.apache.spark.scheduler.LiveListenerBus.onDropEvent, abychom mohli sledovat situace, během nichž se fronta událostí ovladače Spark příliš prodlouží a události se zahodí.
  • Trace data lineage: Profilujeme argumenty cesty k souboru v metodě org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolTranslatorPB.getBlockLocations a org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolTranslatorPB.addBlock, abychom mohli sledovat, jaké soubory aplikace Spark čte a zapisuje.

Detaily implementace a rozšiřitelnost

Aby byla implementace co nejplynulejší, má JVM Profiler velmi jednoduchý a rozšiřitelný design. Lidé mohou snadno přidávat další implementace profileru pro sběr dalších metrik a také nasadit vlastní vlastní reportéry pro odesílání metrik do různých systémů pro analýzu dat.

Obrázek 2. Náš profilovač JVM se skládá z několika různých profilovačů, které měří specifické metriky související s využitím a výkonem JVM.

Kód profilovače JVM je načten do procesu Java prostřednictvím argumentu agenta Java po spuštění procesu. Skládá se ze tří hlavních částí:

  • Transformátor souborů tříd: Instrumentuje bytekód metod jazyka Java uvnitř procesu, aby profiloval libovolný uživatelský kód a ukládal metriky do interní vyrovnávací paměti metrik.
  • Profilátor metrik
    • Profilátor CPU/paměti: shromažďuje metriky využití CPU/paměti prostřednictvím JMX a odesílá je reportérům.
    • Profiler trvání metody: načítá metriky trvání metody (latence) z vyrovnávací paměti metrik a odesílá je reportérům.
    • Method Argument Profiler: Čte hodnoty argumentů metody z vyrovnávací paměti metrik a odesílá je reportérům.
  • Reportéři
    • Reportér konzoly: Zapisuje metriky do výstupu konzoly.
    • Kafka Reporter: odešle metriky do témat Kafka.

Jak rozšířit JVM Profiler o odesílání metrik prostřednictvím vlastního reportéru

Uživatelé mohou implementovat vlastní reportéry a zadat je pomocí volby -javaagent, například:

java

-javaagent:jvm-profiler-0.0.5.jar=reporter=com.uber.profiling.reporters.CustomReporter

Integrace s datovou infrastrukturou společnosti Uber

Obrázek 3. Integrace našeho nástroje JVM Profiler se systémem datové infrastruktury společnosti Uber.

Integrovali jsme naše metriky nástroje JVM Profiler s interní datovou infrastrukturou společnosti Uber, abychom umožnili:

  1. Analýzu dat v rámci celého clusteru: Metriky jsou nejprve přivedeny do Kafky a vloženy do HDFS, poté se uživatelé dotazují pomocí Hive/Presto/Spark.
  2. Ladění aplikace Spark v reálném čase: Používáme Flink k agregaci dat pro jednu aplikaci v reálném čase a zápisu do naší databáze MySQL, uživatelé pak mohou metriky prohlížet prostřednictvím webového rozhraní.

Použití nástroje JVM Profiler

Níže uvádíme návod, jak pomocí našeho nástroje JVM Profiler sledovat jednoduchou aplikaci Java:

Nejprve provedeme klonování projektu git:

Projekt sestavíme spuštěním následujícího příkazu:

Následujícím příkazem vyvoláme soubor JAR s výsledkem sestavení (např. target/jvm-profiler-0.0.5.jar) a spustíme aplikaci uvnitř nástroje JVM Profiler pomocí následujícího příkazu:

Příkaz spustí ukázkovou aplikaci Java a do výstupní konzoly nahlásí její výkon a metriky využití prostředků. Například:

Profilovač může také odesílat metriky do tématu Kafka pomocí následujícího příkazu:

Použijte profilovač k profilování aplikace Spark

Nyní si projdeme, jak spustit profilovač s aplikací Spark.

Předpokládáme-li, že již máme cluster HDFS, nahrajeme soubor JVM Profiler JAR na náš HDFS:

Poté pomocí příkazového řádku spark-submit spustíme aplikaci Spark s profilerem:

Příklady metrických dotazů

V Uberu odešleme naše metriky do témat Kafka a naprogramujeme datové pipeline na pozadí, které je automaticky zařadí do tabulek Hive. Uživatelé mohou nastavit podobné pipelines a používat SQL k dotazování metrik profileru. Mohou si také napsat vlastní reportéry, které budou metriky posílat do databáze SQL, například MySQL, a dotazovat se odtud. Níže je uveden příklad schématu tabulky Hive:

Níže nabízíme příklad výsledku při spuštění předchozího dotazu SQL, který ukazuje metriky paměti a procesoru pro jednotlivé procesy pro vykonavatele Spark:

role processUuid maxHeapMemoryMB avgProcessCpuLoad
executor 6d3aa4ee-.4233-4cc7-a628-657e1a87825d 2805.255325 7.61E-11
executor 21f418d1-6d4f-440d-b28a-4eba1a3bb53d 3993.969582 9.56E-11
executor a5da6e8c-149b-4722-8fa8-74a16baabcf8 3154.484474 8.18E-11
executor a1994e27-59bd-4cda-9de3-745ead954a27 2561.847374 8.58E-11

Výsledky a další kroky

Použili jsme JVM Profiler na jednu z největších aplikací Spark společnosti Uber (která používá více než 1000 exekutorů) a přitom jsme snížili alokaci paměti pro každý exekutor o 2 GB, ze 7 GB na 5 GB. Jen u této aplikace Spark jsme ušetřili 2 TB paměti.

Profilátor JVM jsme také použili na všechny aplikace Hive on Spark uvnitř společnosti Uber a našli jsme několik možností, jak zlepšit efektivitu využití paměti. Obrázek 3 níže ukazuje jeden ze zjištěných výsledků: přibližně 70 % našich aplikací využívalo méně než 80 % přidělené paměti. Z našich zjištění vyplynulo, že pro většinu těchto aplikací bychom mohli alokovat méně paměti a zvýšit její využití o 20 procent.

Obrázek 3. Náš nástroj JVM Profiler zjistil, že 70 procent aplikací využívá méně než 80 procent přidělené paměti.

Při dalším rozvoji našeho řešení se těšíme na další snížení paměti napříč našimi JVM.

JVM Profiler je samostatný projekt s otevřeným zdrojovým kódem a vítáme, aby tento nástroj používali i další vývojáři a také přispívali (např. zasílali žádosti o stažení)!

Náš tým Big Data Engineering v Seattlu, Palo Altu a San Franciscu pracuje na nástrojích a systémech pro rozšíření celého ekosystému Hadoop, včetně HDFS, Hive, Presto a Spark. Nad touto rodinou open source softwaru vytváříme technologie, které nám pomáhají přijímat lepší obchodní rozhodnutí založená na datech. Pokud vám to zní lákavě, podívejte se na naše pracovní nabídky a zvažte možnost přidat se k našemu týmu!

Záhlaví fotografie:

Přihlaste se k odběru našeho newsletteru, abyste měli přehled o nejnovějších inovacích z Uber Engineering.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.