Yann Moisan
Yann Moisan

Follow

May 29, 2018 · 9 min read

Spark is the core component of Teads’s Machine Learning stack. We use it for many ML applications, from ad performance predictions to user Look-alike Modeling. Käytämme myös kipinä käsittely intensiivisiä töitä, kuten cross-device segmentin laajennus tai parketti SSTables transformation tietojen lataamiseen Cassandra.

Sparkilla työskennellessämme saavutamme säännöllisesti klusteriemme resurssien rajat muistin, levyn tai suorittimen suhteen. Mittakaava vain työntää asiaa taaksepäin, joten meidän on liattava kätemme.

tässä on kokoelma parhaita käytäntöjä ja optimointivinkkejä Spark 2.2.0: lle paremman suorituskyvyn ja puhtaamman Spark-koodin saavuttamiseksi, kattaen:

  • miten hyödyntää volframia,
  • Suoritussuunnitelman analyysi,
  • tiedonhallinta (välimuistiin tallentaminen, yleisradio),
  • pilveen liittyvät optimoinnit (mm.S3).

päivitys 07/12/2018, Katso myös toinen osa, joka käsittelee vianmääritystemppuja ja ulkoisen tietolähteen hallintaa.

se on maalaisjärkeä, mutta paras tapa parantaa koodin suorituskykyä on omaksua Sparkin vahvuudet. Yksi niistä on volframi.

standardi versiosta 1.5 lähtien volframi on kipinä SQL-komponentti, joka tarjoaa paremman suorituskyvyn uudelleenkirjoittamalla kipinä-operaatioita bytecode, ajonaikana. Volframi tukahduttaa virtuaalisia toimintoja ja hyödyntää lähellä paljas metalli suorituskykyä keskittymällä työpaikkoja CPU ja muistin tehokkuutta.

saadaksemme volframista kaiken irti kiinnitämme huomiota seuraaviin:

käytä Dataset-rakenteita dataframesin sijaan

varmistaaksemme, että koodimme hyötyy mahdollisimman paljon volframin optimoinneista käytämme oletusdataset API: ta Scalan kanssa (RDD: n sijaan).

Dataset tuo molempien maailmojen parhaat puolet relaatio – (DataFrame) ja funktionaalisten (RDD) muunnosten sekoituksella. Tämä API on ajantasaisin ja lisää tyyppiturvallisuutta sekä parempaa virheiden käsittelyä ja paljon luettavampia yksikkötestejä.

sen mukana tulee kuitenkin tradeoff, sillä kartta-ja suodatintoiminnot suoriutuvat huonommin tämän API: n kanssa. Kehyksetön on lupaava ratkaisu tämän rajoituksen ratkaisemiseksi.

Vältä käyttäjän määrittelemiä funktioita (UDFs) mahdollisimman paljon

UDF: n käyttäminen edellyttää deserialisointia, jotta tietoja voidaan käsitellä klassisessa Scalassa ja sen jälkeen uudelleensijoittaa. UDFs voidaan korvata Spark SQL-funktioilla, niitä on jo paljon ja uusia lisätään säännöllisesti.

UDFs: n välttäminen ei välttämättä tuota pikaparannuksia, mutta ainakin se estää tulevat suorituskykyongelmat, mikäli koodi muuttuu. Lisäksi käyttämällä sisäänrakennettuja Spark SQL-funktioita vähennämme testauspanostustamme, kun kaikki suoritetaan Spark-puolella. Nämä toiminnot ovat JVM: n asiantuntijoiden suunnittelemia, joten UDFs ei todennäköisesti saavuta parempaa suorituskykyä.

esimerkiksi seuraava koodi voidaan korvata sisäänrakennetulla coalesce-funktiolla:

def currency = udf(
(currencySub: String, currencyParent: String) ⇒
Option(currencyParent) match {
case Some(curr) ⇒ curr
case _ ⇒ currencySub
}
)

kun sisäänrakennettua korvaajaa ei ole, on vielä mahdollista toteuttaa ja laajentaa katalysaattorin (Spark ’ s SQL optimizer) lausekeluokkaa. Se pelaa hyvin koodin generointi. Lisätietoja, Chris Fregly puhui siitä täällä (katso slide 56). Tekemällä tämän me suoraan käyttää volframi muodossa, se ratkaisee sarjanumerointi ongelma ja kuoppia suorituskykyä.

Vältä käyttäjän määrittämiä Aggregaattifunktioita (Udaf)

UDAF luo Sortaggregaattioperaatioita, jotka ovat huomattavasti hitaampia kuin Hashaggregaatti. Esimerkiksi se, mitä me teemme sen sijaan, että kirjoittaisimme udaf: n, joka laskee mediaanin, käytetään sisäänrakennettua ekvivalenttia (kvantiili 0,5):

df.stat.approxQuantile("value”, Array(0.5), 0)

approxQuantile-funktio käyttää muunnelmaa Greenwaldin-Khannan algoritmista. Meidän tapauksessamme se oli lopulta 10 kertaa nopeampi kuin vastaava UDAF.

Vältä UDFs: ää tai Udaf: iä, jotka suorittavat useampaa kuin yhtä asiaa

Ohjelmistokäsityön periaatteet pätevät ilmeisesti big data-juttuja kirjoitettaessa (tee yksi asia ja tee se hyvin). Jakamalla UDFs pystymme käyttämään sisäänrakennettuja funktioita yhteen osaan tuloksena olevasta koodista. Se myös yksinkertaistaa huomattavasti testausta.

2 – Katso konepellin alle

Sparkin toteutussuunnitelman analysointi on helppo tapa havaita mahdolliset parannukset. Suunnitelma koostuu vaiheista, jotka ovat Sparkissa toteutettavia fyysisiä yksiköitä. Kun muokkaamme koodimme, ensimmäinen asia, jota etsimme, on epänormaali määrä vaiheita. Epäilyttävä suunnitelma voi olla sellainen, joka vaatii 10 vaihetta 2-3: n sijasta kahden Datapelin väliseen perustason liittymisoperaatioon.

Sparkissa ja yleisemmin hajautetussa tietojenkäsittelyssä datan lähettäminen verkon yli (alias Shuffle in Spark) on kalleinta toimintaa. Shuffles ovat kalliita, koska ne sisältävät levyn I/O, data serialization ja verkon I / O. niitä tarvitaan operaatioita, kuten liittyä tai groupBy ja tapahtua vaiheiden välillä.

ottaen tämän huomioon, vaiheiden määrän vähentäminen on ilmeinen tapa optimoida työtä. Käytämme .selitä (true) komento, joka näyttää suoritussuunnitelman, jossa esitetään kaikki työhön liittyvät vaiheet (vaiheet). Tässä on esimerkki:

Simple execution plan example

The Directed Acyclic Graph (DAG) in Spark UI can also be used to visualize the task repartition in each stage.

hyvin yksinkertainen DAG — esimerkkikuvakrediitit

optimointi nojaa paljon sekä tiedon tuntemukseen että sen käsittelyyn (ml. business logic). Yksi Spark SQL-optimoinnin rajoista katalysaattorilla on, että se käyttää” mekaanisia ” sääntöjä optimoidakseen suoritussuunnitelman (kohdassa 2.2.0).

monien muiden tavoin odotimme kustannusperusteista optimointimoottoria broadcast-liittymisvalinnan jälkeen. Se näyttää nyt saatavilla 2.3.0, meidän on tarkasteltava sitä.

3 – tunne tietosi ja hallitse niitä tehokkaasti

olemme nähneet, miten työsuoritusta voidaan parantaa tarkastelemalla toteutussuunnitelmaa, mutta datapuolella on myös paljon mahdollisia parannuksia.

erittäin epätasapainoiset tietojoukot

tarkistaaksemme nopeasti, onko kaikki kunnossa, käymme läpi kunkin tehtävän suoritusajan ja etsimme heterogeenista prosessiaikaa. Jos yksi tehtävistä on huomattavasti hitaampi kuin muut, se pidentää työn kokonaiskestoa ja tuhlaa nopeimpien suorittajien resursseja.

on melko helppo tarkistaa min, max ja mediaanikesto Spark UI: ssa. Tässä tasapainoinen esimerkki:

Vastaa

Sähköpostiosoitettasi ei julkaista.