Otsige kiirusega 1 TB/s

TL;DR: Neli aastat tagasi lahkusin Google'ist uue serveri jälgimise tööriista ideega. Idee oli ühendada tavaliselt eraldatud funktsioonid üheks teenuseks kogumine ja logianalüüs, mõõdikute kogumine, hoiatused ja armatuurlauad. Üks põhimõtetest on, et teenus peab olema tõeline kiire, pakkudes devopsidele lihtsat, interaktiivset ja nauditavat kogemust. See nõuab mitme gigabaidise andmekogumi töötlemist sekundi murdosadega, jäädes samas eelarve piiresse. Olemasolevad logihaldustööriistad on sageli aeglased ja kohmakad, seega seisime silmitsi hea väljakutsega: kasutajatele uue kogemuse pakkumiseks tööriista nutikalt kujundamine.

Selles artiklis kirjeldatakse, kuidas me Scalyris selle probleemi lahendasime, rakendades vana kooli meetodeid, toore jõu lähenemisviisi, kõrvaldades mittevajalikud kihid ja vältides keerulisi andmestruktuure. Saate neid õppetunde rakendada oma inseneriprobleemide lahendamisel.

Vana kooli jõud

Logianalüüs algab tavaliselt otsinguga: leia kõik sõnumid, mis vastavad kindlale mustrile. Scalyris on need kümnete või sadade gigabaitide logid paljudest serveritest. Kaasaegsed lähenemisviisid hõlmavad reeglina mõne keeruka andmestruktuuri loomist, mis on optimeeritud otsingu jaoks. Olen seda kindlasti Google'is näinud, kus nad on sellistes asjades päris head. Kuid me otsustasime palju jõhkrama lähenemisviisi järgi: palkide lineaarne skaneerimine. Ja see töötas – pakume otsitavat liidest, mis on meie konkurentidest suurusjärgus kiirem (vt animatsiooni lõpus).

Põhiline arusaam oli, et kaasaegsed protsessorid on tõepoolest väga kiired lihtsate ja arusaadavate toimingute tegemisel. Seda on lihtne kahe silma vahele jätta keerulistes mitmekihilistes süsteemides, mis sõltuvad I/O kiirusest ja võrgutoimingutest, ning sellised süsteemid on tänapäeval väga levinud. Seetõttu töötasime välja disaini, mis minimeerib kihte ja liigset prahti. Mitme protsessori ja serveriga paralleelselt ulatub otsingukiirus 1 TB sekundis.

Peamised väljavõtted sellest artiklist:

  • Toores jõuotsing on elujõuline lähenemisviis reaalsete suuremahuliste probleemide lahendamiseks.
  • Toores jõud on disainitehnika, mitte töövaba lahendus. Nagu iga tehnika, sobib see mõne probleemi lahendamiseks paremini kui teistega ning seda saab rakendada halvasti või hästi.
  • Toores jõud on saavutamiseks eriti hea stabiilne tootlikkus.
  • Toore jõu tõhus kasutamine nõuab koodi optimeerimist ja piisavate ressursside rakendamist õigel ajal. See sobib, kui teie serverid on suure mittekasutajakoormuse all ja kasutajatoimingud jäävad prioriteediks.
  • Jõudlus sõltub kogu süsteemi disainist, mitte ainult sisemise ahela algoritmist.

(Selles artiklis kirjeldatakse andmete otsimist mälust. Enamikul juhtudel, kui kasutaja teeb logiotsingu, on Scalyri serverid need juba vahemällu salvestanud. Järgmises artiklis käsitletakse vahemällu salvestamata logide otsimist. Kehtivad samad põhimõtted: tõhus kood, toore jõud suurte arvutusressurssidega).

Toore jõu meetod

Traditsiooniliselt otsitakse suurt andmekogumit märksõnaindeksi abil. Serveri logidele rakendades tähendab see logist iga kordumatu sõna otsimist. Iga sõna jaoks peate koostama kõigi lisamiste loendi. Nii on lihtne leida kõiki selle sõnaga sõnumeid, näiteks "viga", "firefox" või "transaction_16851951" – vaadake lihtsalt registrist.

Kasutasin seda lähenemisviisi Google'is ja see töötas hästi. Kuid Scalyris otsime logisid baithaaval.

Miks? Abstraktsest algoritmilisest vaatenurgast on märksõnaindeksid palju tõhusamad kui toore jõuga otsingud. Kuid me ei müü algoritme, vaid jõudlust. Ja jõudlus ei seisne ainult algoritmides, vaid ka süsteemitehnoloogias. Peame arvestama kõike: andmete mahtu, otsingu tüüpi, saadaolevat riist- ja tarkvara konteksti. Otsustasime, et meie konkreetse probleemi jaoks sobib midagi nagu „grep” paremini kui indeks.

Indeksid on suurepärased, kuid neil on piirangud. Ühte sõna on lihtne leida. Kuid mitme sõnaga sõnumite otsimine, nagu 'googlebot' ja '404', on palju keerulisem. Sellise fraasi nagu „tabamata erand” otsimiseks on vaja kohmakamat registrit, mis salvestab mitte ainult kõik selle sõnaga sõnumid, vaid ka sõna konkreetse asukoha.

Tõelised raskused tekivad siis, kui te ei otsi sõnu. Oletame, et soovite näha, kui palju liiklust robotid tulevad. Esimene mõte on otsida logidest sõna "bot". Nii leiate mõned robotid: Googlebot, Bingbot ja paljud teised. Kuid siin pole "bot" sõna, vaid selle osa. Kui otsime registrist sõna „bot”, ei leia me ühtegi postitust sõnaga „Googlebot”. Kui kontrollite indeksis iga sõna ja seejärel otsite indeksist leitud märksõnu, aeglustub otsing oluliselt. Seetõttu ei luba mõned logiprogrammid osasõnaotsingut või (parimal juhul) lubavad madalama jõudlusega spetsiaalset süntaksit. Tahame seda vältida.

Teine probleem on kirjavahemärgid. Kas soovite leida kõik päringud aadressilt 50.168.29.7? Kuidas on lood sisaldavate silumislogidega [error]? Alamindeksid jätavad tavaliselt kirjavahemärgid vahele.

Lõpuks armastavad insenerid võimsaid tööriistu ja mõnikord saab probleemi lahendada ainult regulaaravaldise abil. Märksõnaregister selleks väga ei sobi.

Lisaks indeksid keeruline. Iga sõnum tuleb lisada mitmesse märksõnaloendisse. Neid loendeid tuleks alati hoida hõlpsasti otsitavas vormingus. Fraaside, sõnafragmentide või regulaaravaldistega päringud tuleb tõlkida mitme loendiga toiminguteks ning tulemused skannida ja kombineerida, et luua tulemuste komplekt. Suuremahulise mitme rentniku teenuse kontekstis tekitab see keerukus jõudlusprobleeme, mis pole algoritmide analüüsimisel nähtavad.

Märksõnade indeksid võtavad samuti palju ruumi ja salvestamine on logihaldussüsteemis suur kulu.

Teisest küljest võib iga otsing kulutada palju arvutusvõimsust. Meie kasutajad hindavad unikaalsete päringute kiireid otsinguid, kuid selliseid päringuid tehakse suhteliselt harva. Tavaliste otsingupäringute jaoks, näiteks armatuurlaua jaoks, kasutame eritehnikaid (kirjeldame neid järgmises artiklis). Muid taotlusi esitatakse piisavalt harva, nii et harva peate korraga töötlema rohkem kui ühte. Kuid see ei tähenda, et meie serverid ei oleks hõivatud: nad on hõivatud uute sõnumite vastuvõtmise, analüüsimise ja tihendamisega, hoiatuste hindamisega, vanade andmete tihendamisega jne. Seega on meil üsna märkimisväärne varu protsessoreid, mida saab kasutada päringute täitmiseks.

Toores jõud töötab, kui teil on jõhker probleem (ja palju jõudu)

Toores jõud töötab kõige paremini lihtsate väikeste sisemiste ahelatega probleemide korral. Sageli saate optimeerida sisemist ahelat töötama väga suurel kiirusel. Kui kood on keeruline, on seda palju keerulisem optimeerida.

Meie otsingukoodil oli algselt üsna suur sisemine silmus. Salvestame sõnumeid lehtedele 4K-s; igal lehel on mõned sõnumid (UTF-8-s) ja iga sõnumi metaandmed. Metaandmed on struktuur, mis kodeerib väärtuse pikkuse, sisemise sõnumi ID ja muud väljad. Otsingutsükkel nägi välja selline:

Otsige kiirusega 1 TB/s

See on tegeliku koodi lihtsustatud versioon. Kuid isegi siin on nähtavad mitmed objektipaigutused, andmete koopiad ja funktsioonikutsed. JVM on funktsioonikutsete optimeerimisel ja lühiajaliste objektide eraldamisel päris hea, nii et see kood töötas paremini, kui me väärisime. Testimise käigus kasutasid kliendid seda üsna edukalt. Kuid lõpuks viisime selle järgmisele tasemele.

(Võite küsida, miks salvestame sõnumeid selles vormingus 4K-lehtede, teksti ja metaandmetega, mitte ei tööta otse logidega. Põhjuseid on palju, mis taanduvad asjaolule, et Scalyri mootor sarnaneb sisemiselt pigem hajutatud andmebaasiga kui failisüsteem.Tekstiotsing on sageli kombineeritud DBMS-i stiilis filtritega veeristes pärast logi sõelumist. Saame korraga otsida paljudest tuhandetest logidest ja lihtsad tekstifailid ei sobi meie tehingute, replikatsioonide, hajutatud andmete haldamiseks).

Esialgu tundus, et too kood ei sobi eriti toore jõu optimeerimiseks. "Päris töö" sisse String.indexOf() isegi ei domineerinud protsessori profiilis. See tähendab, et selle meetodi optimeerimine üksi ei annaks märkimisväärset mõju.

Juhtub nii, et salvestame metaandmed iga lehe algusesse ja kõigi UTF-8 sõnumite tekstid pakitakse teise otsa. Seda ära kasutades kirjutasime tsükli ümber, et otsida korraga kogu lehelt:

Otsige kiirusega 1 TB/s

See versioon töötab otse vaates raw byte[] ja otsib kõiki sõnumeid korraga kogu 4K lehelt.

Seda on toore jõu meetodi jaoks palju lihtsam optimeerida. Sisemist otsingutsüklit kutsutakse üheaegselt kogu 4K-lehe jaoks, mitte iga postituse puhul eraldi. Puudub andmete kopeerimine, objektide eraldamine. Ja keerukamaid metaandmete toiminguid kutsutakse välja ainult siis, kui tulemus on positiivne, mitte iga sõnumi puhul. Nii oleme kaotanud tonni üldkulusid ja ülejäänud koormus on koondatud väikesesse sisemisse otsinguahelasse, mis sobib hästi edasiseks optimeerimiseks.

Meie tegelik otsingualgoritm põhineb Leonid Volnitski suurepärane idee. See sarnaneb Boyeri-Moore'i algoritmiga, jättes igal sammul umbes otsingustringi pikkuse vahele. Peamine erinevus seisneb selles, et see kontrollib kahte baiti korraga, et minimeerida valesid vasteid.

Meie juurutamine nõuab iga otsingu jaoks 64 1,25 otsingutabeli loomist, kuid see pole midagi võrreldes otsitavate andmete gigabaitidega. Sisemine ahel töötleb ühes tuumas mitu gigabaiti sekundis. Praktikas on stabiilne jõudlus igal tuumal umbes XNUMX GB sekundis ja arenguruumi on. On võimalik kõrvaldada osa sisemisest tsüklist väljaspool olevast üldkulust ja plaanime katsetada Java asemel sisemist tsüklit C-s.

Me kasutame jõudu

Oleme arutanud, et logiotsingut saab rakendada "umbes", kuid kui palju "jõudu" meil on? Üsna palju.

1 tuum: Õige kasutamise korral on kaasaegse protsessori üks tuum omaette üsna võimas.

8 südamikku: töötame praegu Amazon hi1.4xlarge ja i2.4xlarge SSD serverites, millest igaühel on 8 südamikku (16 lõime). Nagu eespool mainitud, on need tuumad tavaliselt taustatoimingutega hõivatud. Kui kasutaja sooritab otsingu, peatatakse taustatoimingud, vabastades otsingu jaoks kõik 8 tuuma. Otsing lõpeb tavaliselt sekundi murdosaga, pärast mida jätkub taustatöö (drosseliprogramm tagab, et otsingupäringute tulv ei segaks olulist taustatööd).

16 südamikku: töökindluse huvides jagame serverid ülem-/alamgruppidesse. Igal masteril on tema käsutuses üks SSD ja üks EBS-server. Kui põhiserver jookseb kokku, võtab selle asemele kohe SSD-server. Peaaegu kogu aeg töötavad ülem ja alam hästi, nii et iga andmeplokk on otsitav kahes erinevas serveris (EBS-i alluvserveril on nõrk protsessor, seega me seda ei arvesta). Jagame ülesande nende vahel nii, et meil on saadaval kokku 16 tuuma.

Paljud südamikud: Lähitulevikus jagame andmeid serverite vahel nii, et nad kõik osaleksid iga mittetriviaalse päringu töötlemisel. Iga tuum töötab. [Märge: viisime plaani ellu ja suurendasime otsingukiirust 1 TB/s-ni, vt märkust artikli lõpus].

Lihtsus tagab töökindluse

Teine toore jõu meetodi eelis on selle üsna ühtlane jõudlus. Tavaliselt ei ole otsing probleemi ja andmekogumi üksikasjade suhtes kuigi tundlik (ma arvan, et sellepärast nimetatakse seda "jämedaks").

Märksõnaregister annab mõnikord uskumatult kiireid tulemusi ja mõnikord mitte. Oletame, et teil on 50 GB logisid, milles termin „customer_5987235982” esineb täpselt kolm korda. Selle termini otsing loendab kolm asukohta otse registrist ja lõpeb kohe. Kuid keerukad metamärgiotsingud võivad skannida tuhandeid märksõnu ja võtta kaua aega.

Teisest küljest toimivad toore jõuga otsingud mis tahes päringu puhul enam-vähem sama kiirusega. Pikkade sõnade otsimine on parem, kuid isegi üksiku tähemärgi otsimine on üsna kiire.

Toore jõu meetodi lihtsus tähendab, et selle jõudlus on teoreetilise maksimumi lähedal. Ketta ootamatu ülekoormuse, lukustamise, kursori tagaajamise ja tuhandete muude ebaõnnestumise põhjuste jaoks on vähem võimalusi. Vaatasin just eelmisel nädalal meie kõige aktiivsemas serveris Scalyri kasutajate esitatud taotlusi. Taotlusi oli 14 000. Neist täpselt kaheksal kulus rohkem kui üks sekund; 99% valmis 111 millisekundi jooksul (kui te pole logianalüüsi tööriistu kasutanud, usaldage mind: see on kiire).

Teenuse kasutamise hõlbustamiseks on oluline stabiilne ja usaldusväärne jõudlus. Kui see aeg-ajalt maha jääb, peavad kasutajad seda ebausaldusväärseks ja ei soovi seda kasutada.

Logi otsing tegevuses

Siin on lühike animatsioon, mis näitab Scalyri otsingut tegevuses. Meil on demokonto, kuhu impordime kõik sündmused igas avalikus Githubi hoidlas. Selles demos uurin nädala andmeid: ligikaudu 600 MB töötlemata logisid.

Video salvestati otse, ilma spetsiaalse ettevalmistuseta minu töölaual (serverist umbes 5000 kilomeetri kaugusel). Esitus, mida näete, on suuresti tingitud veebikliendi optimeerimine, samuti kiire ja töökindel taustaprogramm. Alati, kui on paus ilma laadimisnäidikuta, teen pausi, et saaksite lugeda, mida ma vajutan.

Otsige kiirusega 1 TB/s

Kokkuvõttes

Suurte andmemahtude töötlemisel on oluline valida hea algoritm, kuid "hea" ei tähenda "väljamõeldud". Mõelge, kuidas teie kood praktikas töötab. Algoritmide teoreetiline analüüs jätab välja mõned tegurid, millel võib reaalses maailmas suur tähtsus olla. Lihtsamaid algoritme on lihtsam optimeerida ja need on servaolukordades stabiilsemad.

Mõelge ka kontekstile, milles kood käivitatakse. Meie puhul vajame taustaülesannete haldamiseks piisavalt võimsaid servereid. Kasutajad algatavad otsinguid suhteliselt harva, nii et saame laenata terve rühma servereid lühikeseks perioodiks, mis on vajalik iga otsingu tegemiseks.

Toore jõu meetodit kasutades rakendasime kiire, usaldusväärse ja paindliku otsingu palkide hulgast. Loodame, et need ideed on teie projektide jaoks kasulikud.

Redigeeri: Pealkiri ja tekst on muudetud "Otsi 20 GB sekundis" asemel "Otsi kiirusega 1 TB sekundis", et kajastada jõudluse kasvu viimastel aastatel. Kiiruse suurenemine on peamiselt tingitud muudatustest EC2 serverite tüübis ja arvus, mida me täna oma suurenenud kliendibaasi teenindamiseks paneme. Peagi on tulemas muudatused, mis annavad järjekordse dramaatilise tõuke tegevustõhususele, ja me ei jõua ära oodata, millal saame neid jagada.

Allikas: www.habr.com

Lisa kommentaar