Apache Sparkin kaltaiset laskentakehykset on otettu laajalti käyttöön suurten datasovellusten rakentamiseen. Uberille data on strategisen päätöksenteon ja tuotekehityksen ytimessä. Jotta voisimme hyödyntää tätä dataa paremmin, hallinnoimme massiivisia Spark-käyttöönottoja maailmanlaajuisissa suunnittelutoimistoissamme.
Vaikka Spark tekee datateknologiasta helpommin lähestyttävää, Spark-sovelluksille osoitettujen resurssien oikeanlainen mitoitus ja datainfrastruktuurimme toiminnan tehokkuuden optimointi edellyttävät hienojakoisempaa näkemystä näistä järjestelmistä, nimittäin niiden resurssien käyttömalleista.
Jotta voimme louhia näitä malleja muuttamatta käyttäjäkoodia, rakensimme ja avasimme avoimen lähdekoodin sisältävän hajautetun profilointilaitteen nimeltä JVM Profiler, jonka avulla voimme kerätä suorituskyky- ja resurssien käyttömetriikkaa ja tarjoilla ne jatkoanalyysiä varten. Vaikka se on rakennettu Sparkia varten, sen yleinen toteutus mahdollistaa sen soveltamisen mihin tahansa Java-virtuaalikoneeseen (JVM) perustuvaan palveluun tai sovellukseen. Lue, miten Uber käyttää tätä työkalua Spark-sovellusten profilointiin ja miten voit käyttää sitä omissa järjestelmissäsi.
- Profiloinnin haasteet
- Korreloida metriikoita suuren määrän prosessien välillä sovellustasolla
- Tehdä metriikoiden keräämisestä ei-tunkeutuvaa mielivaltaiselle käyttäjäkoodille
- JVM Profilerin esittely
- Mitä JVM-profilointilaite tekee?
- Tyypilliset käyttötapaukset
- Toteutuksen yksityiskohdat ja laajennettavuus
- How to extend the JVM Profiler to send metrics via a custom reporter
- Integrointi Uberin datainfrastruktuuriin
- JVM Profilerin käyttö
- Käytä profileria profiloimaan Spark-sovellus
- Metriikkakyselyesimerkkejä
- Tulokset ja seuraavat vaiheet
Profiloinnin haasteet
Uber tukee päivittäin kymmeniä tuhansia sovelluksia, jotka toimivat tuhansissa koneissa. Teknologiapinomme kasvaessa huomasimme nopeasti, että nykyinen suorituskyvyn profilointi- ja optimointiratkaisumme ei pystyisi vastaamaan tarpeisiimme. Halusimme erityisesti mahdollisuuden:
Korreloida metriikoita suuren määrän prosessien välillä sovellustasolla
Hajautetussa ympäristössä useita Spark-sovelluksia suoritetaan samalla palvelimella, ja kullakin Spark-sovelluksella on suuri määrä prosesseja (esim. tuhansia suorittajia), jotka suoritetaan monilla palvelimilla, kuten kuvassa 1 havainnollistetaan:
Olemassa olevat työkalumme pystyivät tarkkailemaan vain palvelintason mittareita eivätkä mitanneet yksittäisten sovellusten mittareita. Tarvitsimme ratkaisun, joka pystyisi keräämään metriikoita jokaiselle prosessille ja korreloimaan niitä kunkin sovelluksen prosessien välillä. Lisäksi emme tiedä, milloin nämä prosessit käynnistyvät ja kuinka kauan ne kestävät. Jotta voimme kerätä metriikoita tässä ympäristössä, profiloijan on käynnistyttävä automaattisesti jokaisen prosessin yhteydessä.
Tehdä metriikoiden keräämisestä ei-tunkeutuvaa mielivaltaiselle käyttäjäkoodille
Sparkin ja Apache Hadoopin kirjastot eivät nykyisissä toteutuksissaan vie suorituskykymetriikoita, mutta usein on kuitenkin tilanteita, joissa meidän on kerättävä näitä metriikoita muuttamatta käyttäjä- tai kehyskoodia. Jos esimerkiksi havaitsemme suurta latenssia Hadoopin hajautetun tiedostojärjestelmän (HDFS) NameNodessa, haluamme tarkistaa jokaisesta Spark-sovelluksesta havaitun latenssin varmistaaksemme, että nämä ongelmat eivät ole toistuneet. Koska NameNode-asiakaskoodit on upotettu Spark-kirjastoon, on hankalaa muuttaa sen lähdekoodia tämän mittarin lisäämiseksi. Jotta voisimme pysyä mukana datainfrastruktuurimme jatkuvassa kasvussa, meidän on voitava tehdä mittauksia mistä tahansa sovelluksesta milloin tahansa ja ilman koodimuutoksia. Lisäksi ei-tunkeutuvamman metriikan keruuprosessin toteuttaminen mahdollistaisi sen, että voisimme syöttää koodia dynaamisesti Java-metodeihin latausaikana.
JVM Profilerin esittely
Vastaaksemme näihin kahteen haasteeseen rakensimme ja avasimme JVM Profilerin. On olemassa joitakin olemassa olevia avoimen lähdekoodin työkaluja, kuten Etsyn statsd-jvm-profiler, jotka voivat kerätä metriikoita yksittäisen sovelluksen tasolla, mutta ne eivät tarjoa mahdollisuutta pistää dynaamisesti koodia olemassa olevaan Java-binääriin metriikoiden keräämiseksi. Joidenkin näiden työkalujen innoittamana rakensimme profilointilaitteemme, jossa on vielä enemmän ominaisuuksia, kuten mielivaltainen Java-metodien/argumenttien profilointi.
Mitä JVM-profilointilaite tekee?
JVM-profilointilaite koostuu kolmesta keskeisestä ominaisuudesta, jotka helpottavat suorituskyky- ja resurssien käyttömetriikoiden keräämistä ja sen jälkeen näiden metriikoiden tarjoamista (esim. Apache Kafka) muille järjestelmille jatkoanalyysiä varten:
- Java-agentti: Sisällyttämällä Java-agentti profilointilaitteeseemme käyttäjät voivat kerätä hajautetusti erilaisia metriikoita (esim. suorittimen/muistin käyttö) ja pinojälkiä JVM-prosesseille.
- Kehittyneet profilointiominaisuudet: JVM-profiilimme avulla voidaan jäljittää käyttäjän koodissa olevia mielivaltaisia Java-metodeja ja -argumentteja tekemättä varsinaisia koodimuutoksia. Tätä ominaisuutta voidaan käyttää Spark-sovellusten HDFS NameNode RPC -kutsujen latenssin jäljittämiseen ja hitaiden metodikutsujen tunnistamiseen. Se voi myös jäljittää HDFS-tiedostopolut, joita kukin Spark-sovellus lukee tai kirjoittaa, jotta voidaan tunnistaa kuumia tiedostoja lisäoptimointia varten.
- Data-analytiikan raportointi: Uberissa käytämme profiloijaa metriikoiden raportointiin Kafka-aiheisiin ja Apache Hive -taulukoihin, mikä nopeuttaa ja helpottaa data-analytiikkaa.
Tyypilliset käyttötapaukset
JVM-profiilimme tukee useita käyttötapauksia, joista merkittävin on se, että sen avulla voidaan instrumentoida mielivaltaista Java-koodia. Yksinkertaisen konfiguraatiomuutoksen avulla JVM Profiler voi liittyä Spark-sovelluksen kuhunkin suorittajaan ja kerätä Java-metodien ajonaikaisia metriikoita. Seuraavassa käsitellään joitakin näistä käyttötapauksista:
- Oikean kokoinen suoritin: Käytämme JVM Profilerin muistimittareita seurataksemme todellista muistinkäyttöä kunkin suorittajan osalta, jotta voimme asettaa oikean arvon Sparkin “executor-memory”-argumentille.
- Seuraa HDFS NameNode RPC -latenssia: Profiloimme Spark-sovelluksen luokan org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolTranslatorPB metodeja ja tunnistamme NameNode-kutsujen pitkät latenssit. Seuraamme päivittäin yli 50 tuhatta Spark-sovellusta, joissa on useita miljardeja tällaisia RPC-kutsuja.
- Seuraa ajurin pudottamia tapahtumia: Profiloimme metodeja, kuten org.apache.spark.scheduler.LiveListenerBus.onDropEvent, jäljittääksemme tilanteita, joiden aikana Spark-ajurin tapahtumajonosta tulee liian pitkä ja se pudottaa tapahtumia.
- Jäljitämme datajonoa: Profiloimme tiedostopolkuargumentit metodissa org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolTranslatorPB.getBlockLocations ja org.apache.hadoop.hdfs.protocolPB.ClientNamenodeProtocolTranslatorPB.addBlock jäljittääksemme, mitä tiedostoja Spark-sovellus lukee ja kirjoittaa.
Toteutuksen yksityiskohdat ja laajennettavuus
Jotta toteutus olisi mahdollisimman saumatonta, JVM Profilerilla on hyvin yksinkertainen ja laajennettavissa oleva rakenne. Ihmiset voivat helposti lisätä lisää profilaattoritoteutuksia kerätäkseen lisää metriikoita ja myös ottaa käyttöön omia mukautettuja raportoijia metriikoiden lähettämiseksi eri järjestelmiin tietojen analysointia varten.
JVM Profiler -koodi ladataan Java-prosessiin Java-agenttiargumentin kautta, kun prosessi käynnistyy. Se koostuu kolmesta pääosasta:
- Class File Transformer: instrumentoi prosessin sisällä olevaa Java-metodien tavukoodia mielivaltaisen käyttäjäkoodin profiloimiseksi ja metriikoiden tallentamiseksi sisäiseen metriikkapuskuriin.
- Metric Profilers
- CPU/Memory Profiler: kerää CPU/Memory-käytön metriikat JMX:n kautta ja lähettää ne raportoijille.
- Metodin keston profiloija: Lukee metriikkapuskurista metriikoiden keston (latenssin) metriikoita ja lähettää ne raportoijille.
- Method Argument Profiler: Lukee metriikkapuskurista metodin argumenttiarvoja ja lähettää ne raportoijille.
- Raportoijat
- Konsoliraportoija: Kirjoittaa metriikat konsolitulosteeseen.
- Kafka Reporter: lähettää metriikat Kafka-aiheisiin.
How to extend the JVM Profiler to send metrics via a custom reporter
Käyttäjät voisivat toteuttaa omat raporttinsa ja määrittää ne -javaagent-optiolla, kuten:
java
-javaagent:jvm-profiler-0.0.5.jar=reporter=com.uber.profiling.reporters.CustomReporter
Integrointi Uberin datainfrastruktuuriin
Integroimme JVM Profiler -mittarimme Uberin sisäiseen datainfrastruktuuriin mahdollistaaksemme:
- klusterin laajuisen data-analyysin: Metriikat syötetään ensin Kafkaan ja syötetään HDFS:ään, minkä jälkeen käyttäjät tekevät kyselyjä Hive/Presto/Sparkilla.
- Reaaliaikainen Spark-sovelluksen virheenkorjaus: Käytämme Flinkiä yksittäisen sovelluksen tietojen keräämiseen reaaliajassa ja kirjoittamiseen MySQL-tietokantaan, minkä jälkeen käyttäjät voivat tarkastella mittareita verkkopohjaisen käyttöliittymän kautta.
JVM Profilerin käyttö
Alhaalla annamme ohjeet siitä, miten voimme käyttää JVM Profileria yksinkertaisen Java-sovelluksen jäljittämiseen:
Aluksi git-kloonaamme projektin:
Keräämme projektin suorittamalla seuraavan komennon:
Seuraavaksi kutsumme rakentamisen tuloksena syntynyttä JAR-tiedostoa (esim. target/jvm-profiler-0.0.5.jar) ja ajamme sovelluksen JVM Profilerin sisällä seuraavalla komennolla:
Komento ajaa esimerkin Java-sovelluksen ja raportoi sen suorituskyky- ja resurssien käyttömittaustulokset ulostulon tulostuskonsoliin. Esimerkiksi:
Profiler voi myös lähettää metriikoita Kafka-aiheeseen seuraavan kaltaisella komennolla:
Käytä profileria profiloimaan Spark-sovellus
Kävellään nyt läpi, miten profileria ajetaan Spark-sovelluksen kanssa.
Edellyttäen, että meillä on jo HDFS-klusteri, lataamme JVM Profilerin JAR-tiedoston HDFS:ään:
Sitten käytämme spark-submit-komentoriviä käynnistääksemme Spark-sovelluksen profilerin kanssa:
Metriikkakyselyesimerkkejä
Ussa lähetämme metriikkatietojamme Kafka-aiheisiin ja ohjelmoimme tausta-aineistoputket, jotta ne voidaan syöttää Hive-taulukoihin automaattisesti. Käyttäjät voivat perustaa samanlaisia putkia ja käyttää SQL:ää profilointimittareiden kyselyyn. He voivat myös kirjoittaa omia raportoijia, jotka lähettävät metriikat SQL-tietokantaan, kuten MySQL:ään, ja tehdä kyselyn sieltä. Alla on esimerkki Hive-taulukon skeemasta:
Alhaalla tarjoamme esimerkkituloksen edellisen SQL-kyselyn suorittamisen yhteydessä, joka näyttää muisti- ja suorittimen metriikat kullekin prosessille Spark-toteuttajien osalta:
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 |
Tulokset ja seuraavat vaiheet
Sovelsimme JVM Profileria erääseen Uberin suurimpaan Spark-sovellukseen (joka käyttää yli 1000 suoritinta) ja vähensimme samalla jokaisen suoritimen muistinjakoa 2 Gt:lla eli 7 Gt:sta 5 Gt:iin. Pelkästään tässä Spark-sovelluksessa säästimme 2 Tt muistia.
Sovelsimme JVM Profileria myös kaikkiin Uberin sisällä oleviin Hive on Spark -sovelluksiin ja löysimme joitakin mahdollisuuksia parantaa muistinkäytön tehokkuutta. Alla olevassa kuvassa 3 näkyy yksi löytämämme tulos: noin 70 prosenttia sovelluksistamme käytti alle 80 prosenttia niille varatusta muistista. Tuloksemme osoittivat, että voisimme varata vähemmän muistia useimmille näistä sovelluksista ja lisätä muistin käyttöä 20 prosenttia.
Kun jatkamme ratkaisumme kasvattamista, odotamme lisää muistin vähentämistä koko JVM:ssä.
JVM Profiler on itsenäinen avoimen lähdekoodin projekti, ja toivotamme muutkin kehittäjät tervetulleiksi käyttämään tätä työkalua ja osallistumaan siihen (esim. lähettämään pull request -pyyntöjä)!
Seattlessa, Palo Altossa ja San Franciscossa sijaitseva Big Data Engineering -tiimimme työskentelee työkalujen ja järjestelmien parissa laajentaakseen koko Hadoop-ekosysteemiä, mukaan lukien HDFS, Hive, Presto ja Spark. Rakennamme tämän avoimen lähdekoodin ohjelmistoperheen päälle teknologioita, jotka auttavat meitä tekemään parempia, tietoon perustuvia liiketoimintapäätöksiä. Jos tämä kuulostaa sinusta houkuttelevalta, tutustu työmahdollisuuksiimme ja harkitse liittymistä tiimiimme!
Photo Credit Header: Seahorse, Roatan, Honduras: Conor Myhrvold.
Tilaa uutiskirjeemme, niin pysyt ajan tasalla Uber Engineeringin uusimmista innovaatioista.