DUK apie VKontakte architektūrą ir darbą

„VKontakte“ sukūrimo istorija yra Vikipedijoje, ją papasakojo pats Pavelas. Atrodo, kad visi ją jau pažįsta. Apie „HighLoad++ Pavel“ svetainės vidų, architektūrą ir struktūrą pasakė man dar 2010 m. Nuo to laiko nutekėjo daug serverių, tad informaciją atnaujinsime: išpjaustysime, išimsime vidų, pasversime, pažiūrėsime į VK įrenginį iš techninės pusės.

DUK apie VKontakte architektūrą ir darbą

Aleksejus Akulovičius (AterCattus) backend kūrėjas VKontakte komandoje. Šios ataskaitos nuorašas yra bendras atsakymas į dažniausiai užduodamus klausimus apie platformos veikimą, infrastruktūrą, serverius ir jų sąveiką, bet ne apie plėtrą, t. apie geležį. Atskirai apie duomenų bazes ir tai, ką vietoj jų turi VK, apie žurnalų rinkimą ir viso projekto stebėjimą. Detalės po pjūviu.



Daugiau nei ketverius metus sprendžiu įvairiausias užduotis, susijusias su backend.

  • Įkelti, saugoti, apdoroti, platinti mediją: vaizdo įrašą, tiesioginę transliaciją, garsą, nuotraukas, dokumentus.
  • Infrastruktūra, platforma, kūrėjo stebėjimas, žurnalai, regioninės talpyklos, CDN, patentuotas RPC protokolas.
  • Integracija su išorinėmis paslaugomis: tiesioginiai pranešimai, išorinių nuorodų analizė, RSS kanalas.
  • Padedame kolegoms įvairiais klausimais, į kuriuos atsakant reikia pasinerti į nežinomą kodą.

Per tą laiką aš prisidėjau prie daugelio svetainės komponentų. Noriu pasidalinti šia patirtimi.

Bendroji architektūra

Viskas, kaip įprasta, prasideda nuo serverio ar serverių grupės, kuri priima užklausas.

Priekinis serveris

Priekinis serveris priima užklausas per HTTPS, RTMP ir WSS.

HTTPS - tai užklausos pagrindinėms ir mobiliosioms žiniatinklio svetainės versijoms: vk.com ir m.vk.com bei kitiems oficialiems ir neoficialiems mūsų API klientams: mobiliesiems klientams, pasiuntiniams. Turime priėmimą RTMP- tiesioginių transliacijų srautas su atskirais priekiniais serveriais ir WSS- Srautinio API jungtys.

HTTPS ir WSS serveriuose verta nginx. RTMP transliacijų atveju neseniai perėjome prie savo sprendimo kive, tačiau tai nepatenka į ataskaitos taikymo sritį. Dėl tolerancijos gedimams šie serveriai reklamuoja bendrus IP adresus ir veikia grupėse, kad, kilus problemai viename iš serverių, vartotojų užklausos nebūtų prarastos. HTTPS ir WSS atveju tie patys serveriai šifruoja srautą, kad patys prisiimtų dalį procesoriaus apkrovos.

Toliau nekalbėsime apie WSS ir RTMP, o tik apie standartines HTTPS užklausas, kurios dažniausiai siejamos su žiniatinklio projektu.

Vidinis

Už priekio paprastai yra užpakaliniai serveriai. Jie apdoroja užklausas, kurias priekinis serveris gauna iš klientų.

Jis kPHP serveriai, kuriame veikia HTTP demonas, nes HTTPS jau iššifruotas. kPHP yra serveris, kuris veikia prefork modeliai: pradeda pagrindinį procesą, krūva vaikų apdoroja, perduoda jiems klausymosi lizdus ir jie apdoroja jų prašymus. Tokiu atveju procesai nėra paleidžiami iš naujo tarp kiekvienos vartotojo užklausos, o tiesiog atkuriama jų būsena į pradinę nulinės reikšmės būseną – užklausa po užklausos, o ne iš naujo.

Apkrovos paskirstymas

Visos mūsų užpakalinės programos nėra didžiulis įrenginių, galinčių apdoroti bet kokią užklausą, telkinys. Mes juos suskirstyti į atskiras grupes: bendrasis, mobilusis, api, vaizdo įrašas, sustojimo... Problema atskiroje mašinų grupėje nepaveiks visų kitų. Kilus problemų su vaizdo įrašu, muzikos klausantis vartotojas apie problemas net nežinos. Į kurią užklausą siųsti, nusprendžia nginx priekyje pagal konfigūraciją.

Metrų surinkimas ir balansavimas

Norėdami suprasti, kiek automobilių turime turėti kiekvienoje grupėje, mes nepasikliaukite QPS. Užpakalinės programos yra skirtingos, jos turi skirtingas užklausas, kiekviena užklausa turi skirtingą QPS skaičiavimo sudėtingumą. Štai kodėl mes dirbame su viso serverio apkrovos samprata – CPU ir perf.

Tokių serverių turime tūkstančius. Kiekvienas fizinis serveris valdo kPHP grupę, kad perdirbtų visus branduolius (nes kPHP yra vienos gijos).

Turinio serveris

CS arba turinio serveris yra saugykla. CS yra serveris, kuriame saugomi failai, taip pat apdorojami įkelti failai ir visos foninės sinchroninės užduotys, kurias jam priskiria pagrindinė žiniatinklio sąsaja.

Turime dešimtis tūkstančių fizinių serverių, kuriuose saugomi failai. Vartotojai mėgsta įkelti failus, o mes mėgstame juos saugoti ir bendrinti. Kai kuriuos iš šių serverių uždaro specialūs pu/pp serveriai.

pu/pp

Jei atidarėte tinklo skirtuką VK, pamatėte pu/pp.

DUK apie VKontakte architektūrą ir darbą

Kas yra pu/pp? Jei uždarome vieną serverį po kito, yra dvi galimybės įkelti ir atsisiųsti failą į uždarytą serverį: tiesiogiai per http://cs100500.userapi.com/path arba per tarpinį serverį - http://pu.vk.com/c100500/path.

Pu yra istorinis nuotraukų įkėlimo pavadinimas, o pp yra nuotraukos tarpinis serveris. Tai yra, vienas serveris skirtas nuotraukoms įkelti, o kitas – įkelti. Dabar ne tik nuotraukos įkeliamos, bet ir pavadinimas išsaugotas.

Šie serveriai nutraukti HTTPS seansuskad pašalintumėte procesoriaus apkrovą iš saugyklos. Be to, kadangi vartotojų failai apdorojami šiuose serveriuose, kuo mažiau slaptos informacijos saugoma šiuose įrenginiuose, tuo geriau. Pavyzdžiui, HTTPS šifravimo raktai.

Kadangi aparatus uždaro kiti mūsų įrenginiai, galime sau leisti nesuteikti jiems „baltų“ išorinių IP adresų ir duok "pilka". Taip sutaupėme IP telkinyje ir garantavome, kad apsaugome mašinas nuo pašalinių prieigos – tiesiog nėra IP, kad į jį patektų.

Atsparumas bendriems IP. Kalbant apie atsparumą gedimams, schema veikia taip pat – keli fiziniai serveriai turi bendrą fizinį IP, o priešais esanti aparatinė įranga pasirenka, kur siųsti užklausą. Apie kitus variantus pakalbėsiu vėliau.

Prieštaringa yra ta, kad šiuo atveju klientas palaiko mažiau ryšių. Jei keliuose kompiuteriuose yra tas pats IP – su tuo pačiu kompiuteriu: pu.vk.com arba pp.vk.com, kliento naršyklėje yra ribojamas vienalaikių užklausų vienam kompiuteriui skaičius. Tačiau visur paplitusio HTTP/2 laikais manau, kad tai nebėra taip aktualu.

Akivaizdus schemos trūkumas yra tai, kad ji turi pumpuoti visą eismą, kuris patenka į saugyklą per kitą serverį. Kadangi srautą pumpuojame per mašinas, dar negalime perpumpuoti didelio srauto, pavyzdžiui, vaizdo įrašų, naudodami tą pačią schemą. Mes jį perduodame tiesiogiai – atskira tiesioginė jungtis atskiroms saugykloms specialiai vaizdo įrašams. Lengvesnį turinį perduodame per tarpinį serverį.

Neseniai gavome patobulintą tarpinio serverio versiją. Dabar aš jums pasakysiu, kuo jie skiriasi nuo įprastų ir kodėl tai būtina.

Saulė

2017 m. rugsėjį „Oracle“, anksčiau nusipirkusi „Sun“, atleido daugybę „Sun“ darbuotojų. Galima sakyti, kad šiuo metu įmonė nustojo egzistuoti. Rinkdamiesi pavadinimą naujai sistemai mūsų administratoriai nusprendė pagerbti šios įmonės atminimą ir naująją sistemą pavadino Sun. Tarp savęs mes ją tiesiog vadiname „saulelėmis“.

DUK apie VKontakte architektūrą ir darbą

pp turėjo keletą problemų. Vienas IP vienai grupei – neefektyvi talpykla. Keletas fizinių serverių naudojasi bendru IP adresu ir nėra galimybės valdyti, į kurį serverį bus išsiųsta užklausa. Todėl, jei skirtingi vartotojai ieško to paties failo, tada, jei šiuose serveriuose yra talpykla, failas patenka į kiekvieno serverio talpyklą. Tai labai neefektyvi schema, bet nieko negalima padaryti.

Vadinasi - negalime suskaidyti turinio, nes šiai grupei konkretaus serverio pasirinkti negalime – jie turi bendrą IP. Taip pat dėl ​​tam tikrų vidinių priežasčių turime tokių serverių nebuvo įmanoma įdiegti regionuose. Jie stovėjo tik Sankt Peterburge.

Su saulutėmis pakeitėme atrankos sistemą. Dabar turime Anycast maršrutizavimas: dinaminis maršruto parinkimas, anycast, savitikros demonas. Kiekvienas serveris turi savo individualų IP, bet bendrą potinklį. Viskas sukonfigūruota taip, kad vienam serveriui sugedus srautas automatiškai paskirstomas po kitus tos pačios grupės serverius. Dabar galima pasirinkti konkretų serverį, nėra perteklinio kaupimo talpykloje, o patikimumas nebuvo paveiktas.

Svorio palaikymas. Dabar galime sau leisti pagal poreikį montuoti skirtingo galingumo mašinas, o taip pat, iškilus laikiniems nesklandumams, pakeisti veikiančių „saulių“ svorius, kad sumažintume jų apkrovą, kad jos „pailsėtų“ ir vėl pradėtų dirbti.

Dalijimasis pagal turinio ID. Juokingas dalykas, susijęs su dalijimu: paprastai dalijame turinį, kad skirtingi vartotojai patektų į tą patį failą per tą pačią „saulę“, kad jie turėtų bendrą talpyklą.

Neseniai paleidome programą „Dobilas“. Tai internetinė viktorina tiesioginėje transliacijoje, kurios vedėjas užduoda klausimus, o vartotojai atsako realiu laiku, pasirinkdami parinktis. Programoje yra pokalbis, kuriame vartotojai gali kalbėtis. Galima vienu metu prisijungti prie transliacijos daugiau nei 100 tūkst. Jie visi rašo žinutes, kurios siunčiamos visiems dalyviams, o kartu su pranešimu ateina avataras. Jei 100 tūkstančių žmonių ateina į vieną avatarą vienoje „saulėje“, tai kartais jis gali riedėti už debesies.

Siekdami atlaikyti daugybę užklausų dėl to paties failo, tam tikro tipo turiniui įjungiame kvailą schemą, kuri paskirsto failus po visas pasiekiamas „saules“ regione.

Saulė iš vidaus

Atvirkštinis tarpinis serveris nginx, talpykla RAM arba greituose Optane / NVMe diskuose. Pavyzdys: http://sun4-2.userapi.com/c100500/path — nuoroda į „saulę“, esančią ketvirtame regione, antroje serverių grupėje. Jis uždaro kelio failą, kuris fiziškai yra serveryje 100500.

Cache

Prie savo architektūrinės schemos pridedame dar vieną mazgą – talpyklos aplinką.

DUK apie VKontakte architektūrą ir darbą

Žemiau yra išdėstymo schema regioninės talpyklos, jų yra apie 20. Tai yra vietos, kuriose yra talpyklos ir „saulės“, kurios gali saugoti srautą per save.

DUK apie VKontakte architektūrą ir darbą

Tai daugialypės terpės turinio kaupimas talpykloje; čia nesaugomi jokie vartotojo duomenys – tik muzika, vaizdo įrašai, nuotraukos.

Norėdami nustatyti vartotojo regioną, mes renkame regionuose skelbiamus BGP tinklo prefiksus. Atsarginės dalies atveju taip pat turime išanalizuoti geoip duomenų bazę, jei nepavyko rasti IP pagal priešdėlius. Mes nustatome regioną pagal vartotojo IP. Kode galime pažvelgti į vieną ar kelis vartotojo regionus – tuos taškus, prie kurių jis yra arčiausiai geografiškai.

Kaip tai veikia?

Failų populiarumą skaičiuojame pagal regioną. Yra keletas regioninės talpyklos, kurioje yra vartotojas, ir failo identifikatorius – mes paimame šią porą ir padidiname įvertinimą su kiekvienu atsisiuntimu.

Tuo pačiu metu demonai - paslaugos regionuose - retkarčiais ateina į API ir sako: „Aš esu tokia ir tokia talpykla, pateikite man sąrašą populiariausių failų mano regione, kurių dar nėra. “ API pateikia daugybę failų, surūšiuotų pagal įvertinimą, demonas juos atsisiunčia, nukelia į regionus ir iš ten pristato failus. Tai yra esminis skirtumas tarp pu/pp ir Sun iš talpyklų: jie iš karto perduoda failą per save, net jei šio failo nėra talpykloje, o talpykla pirmiausia atsisiunčia failą sau, o tada pradeda jį grąžinti.

Šiuo atveju gauname turinys arčiau vartotojų ir paskirstyti tinklo apkrovą. Pavyzdžiui, tik iš Maskvos talpyklos piko valandomis platiname daugiau nei 1 Tbit/s.

Bet yra problemų - talpyklos serveriai nėra guminiai. Itin populiariam turiniui kartais nepakanka tinklo atskiram serveriui. Mūsų talpyklos serveriai yra 40-50 Gbit/s, tačiau yra turinio, kuris visiškai užkemša tokį kanalą. Siekiame įdiegti daugiau nei vienos populiarių failų kopijos regione saugojimą. Tikiuosi, kad iki metų pabaigos ją įgyvendinsime.

Pažiūrėjome į bendrą architektūrą.

  • Priekiniai serveriai, kurie priima užklausas.
  • Užklausas apdorojančios užpakalinės programos.
  • Saugyklos, uždaromos dviejų tipų tarpiniais serveriais.
  • Regioninės talpyklos.

Ko trūksta šioje diagramoje? Žinoma, duomenų bazės, kuriose saugome duomenis.

Duomenų bazės arba varikliai

Mes jas vadiname ne duomenų bazėmis, o varikliais – Varikliais, nes duomenų bazių visuotinai priimta prasme praktiškai neturime.

DUK apie VKontakte architektūrą ir darbą

Tai būtina priemonė. Taip atsitiko todėl, kad 2008–2009 m., kai VK populiarumas sparčiai augo, projektas dirbo tik su MySQL ir „Memcache“ ir kilo problemų. „MySQL“ mėgo strigti ir sugadinti failus, o po to neatkurdavo, o „Memcache“ našumas palaipsniui prastėjo ir turėjo būti paleistas iš naujo.

Pasirodo, vis labiau populiarėjantis projektas turėjo nuolatinę saugyklą, kuri gadina duomenis, ir talpyklą, kuri sulėtėja. Tokiomis sąlygomis sunku plėtoti augantį projektą. Buvo nuspręsta pabandyti perrašyti svarbiausius dalykus, į kuriuos buvo orientuotas projektas, ant mūsų pačių dviračių.

Sprendimas buvo sėkmingas. Atsirado galimybė tai padaryti, o kartu ir ypatinga būtinybė, nes kitų mastelio keitimo būdų tuo metu dar nebuvo. Duomenų bazių nebuvo krūvos, NoSQL dar nebuvo, buvo tik MySQL, Memcache, PostrgreSQL – ir viskas.

Universalus veikimas. Kūrimui vadovavo mūsų C kūrėjų komanda ir viskas buvo daroma nuosekliai. Nepriklausomai nuo variklio, jie visi turėjo maždaug tą patį failo formatą, įrašytą į diską, tuos pačius paleidimo parametrus, vienodai apdorojo signalus ir elgėsi maždaug taip pat esant kraštutinėms situacijoms ir problemoms. Augant varikliams, administratoriams patogu valdyti sistemą – nėra zoologijos sodo, kurį reikėtų prižiūrėti, o tenka iš naujo išmokti valdyti kiekvieną naują trečiųjų šalių duomenų bazę, kuri leido greitai ir patogiai padidinti jų skaičių.

Variklių tipai

Komanda parašė nemažai variklių. Štai tik keletas iš jų: draugas, užuominos, vaizdas, ipdb, raidės, sąrašai, žurnalai, atmintinė, meowdb, naujienos, nostradamus, nuotrauka, grojaraščiai, pmemcached, smėlio dėžė, paieška, saugykla, patinka, užduotys,…

Kiekvienai užduočiai, kuriai reikalinga specifinė duomenų struktūra arba kuri apdoroja netipines užklausas, C komanda sukuria naują variklį. Kodėl gi ne.

Turime atskirą variklį memcached, kuris panašus į įprastą, bet su krūva gėrybių ir kuris nemažina greičio. Ne ClickHouse, bet jis taip pat veikia. Galima įsigyti atskirai pmemcached - yra atkakliai atmintyje, kuris taip pat gali saugoti duomenis diske, be to, netelpa į RAM, kad nebūtų prarasti duomenys paleidžiant iš naujo. Atskiroms užduotims atlikti yra įvairūs varikliai: eilės, sąrašai, rinkiniai – viskas, ko reikia mūsų projektui.

Klasteriai

Kodo požiūriu nereikia galvoti apie variklius ar duomenų bazes kaip apie procesus, objektus ar egzempliorius. Kodas veikia konkrečiai su klasteriais, su variklių grupėmis - vienas tipas klasteryje. Tarkime, yra atmintyje išsaugotas klasteris – tai tik mašinų grupė.

Kodui visai nereikia žinoti serverių fizinės vietos, dydžio ar skaičiaus. Jis eina į klasterį naudodamas tam tikrą identifikatorių.

Kad tai veiktų, turite pridėti dar vieną objektą, esantį tarp kodo ir variklių - įgaliojimas.

RPC tarpinis serveris

Proxy jungiantis autobusas, kurioje veikia beveik visa svetainė. Tuo pačiu mes turime jokios paslaugos atradimo — vietoj to yra šio tarpinio serverio konfigūracija, kuri žino visų grupių ir visų šios klasterio skeveldrų vietą. Štai ką daro administratoriai.

Programuotojams visiškai nerūpi, kiek, kur ir kiek tai kainuoja - jie tiesiog eina į klasterį. Tai mums leidžia daug. Gavęs užklausą įgaliotasis serveris peradresuoja užklausą, žinodamas kur – pats tai nustato.

DUK apie VKontakte architektūrą ir darbą

Šiuo atveju tarpinis serveris yra apsaugos nuo paslaugos gedimo taškas. Jei kuris nors variklis sulėtėja arba sugenda, tarpinis serveris tai supranta ir atitinkamai reaguoja į kliento pusę. Tai leidžia pašalinti skirtąjį laiką – kodas nelaukia, kol variklis atsakys, o supranta, kad jis neveikia ir reikia kažkaip kitaip elgtis. Kodas turi būti paruoštas tam, kad duomenų bazės ne visada veikia.

Konkretūs įgyvendinimai

Kartais vis dar labai norime turėti kokį nestandartinį sprendimą kaip variklį. Tuo pačiu metu buvo nuspręsta nenaudoti mūsų paruošto rpc-proxy, sukurto specialiai mūsų varikliams, o sukurti atskirą tarpinį serverį šiai užduočiai atlikti.

MySQL, kurį vis dar turime šen bei ten, naudojame db-proxy, o ClickHouse - Kačiukas.

Paprastai tai veikia taip. Yra tam tikras serveris, jame veikia kPHP, Go, Python – apskritai bet koks kodas, galintis naudoti mūsų RPC protokolą. Kodas veikia vietoje RPC tarpiniame serveryje – kiekvienas serveris, kuriame yra kodas, veikia savo vietiniame tarpiniame serveryje. Paprašius įgaliotinis supranta, kur kreiptis.

DUK apie VKontakte architektūrą ir darbą

Jei vienas variklis nori pereiti į kitą, net jei jis yra kaimynas, jis eina per tarpinį serverį, nes kaimynas gali būti kitame duomenų centre. Variklis neturėtų pasikliauti nežinodamas nieko kito, nei jis pats – tai mūsų standartinis sprendimas. Bet, žinoma, yra išimčių :)

TL schemos, pagal kurią veikia visi varikliai, pavyzdys.

memcache.not_found                                = memcache.Value;
memcache.strvalue	value:string flags:int = memcache.Value;
memcache.addOrIncr key:string flags:int delay:int value:long = memcache.Value;

tasks.task
    fields_mask:#
    flags:int
    tag:%(Vector int)
    data:string
    id:fields_mask.0?long
    retries:fields_mask.1?int
    scheduled_time:fields_mask.2?int
    deadline:fields_mask.3?int
    = tasks.Task;
 
tasks.addTask type_name:string queue_id:%(Vector int) task:%tasks.Task = Long;

Tai dvejetainis protokolas, kurio artimiausias analogas yra protobufas. Schema iš anksto apibrėžia pasirenkamus laukus, sudėtingus tipus – įtaisytųjų skaliarų plėtinius ir užklausas. Viskas veikia pagal šį protokolą.

RPC per TL per TCP/UDP… UDP?

Mes turime RPC protokolą variklio užklausoms vykdyti, kuris veikia pagal TL schemą. Visa tai veikia per TCP/UDP ryšį. TCP suprantama, bet kodėl mums dažnai reikia UDP?

UDP padeda išvengti daugybės ryšių tarp serverių problemos. Jei kiekvienas serveris turi RPC tarpinį serverį ir apskritai jis gali pereiti prie bet kurio variklio, tada vienam serveriui yra dešimtys tūkstančių TCP jungčių. Krovinys yra, bet nenaudingas. UDP atveju ši problema neegzistuoja.

Jokio perteklinio TCP rankos paspaudimo. Tai tipiška problema: kai paleidžiamas naujas variklis arba naujas serveris, vienu metu užmezgama daug TCP jungčių. Esant mažoms lengvoms užklausoms, pavyzdžiui, UDP naudingoji apkrova, visas kodo ir variklio ryšys yra du UDP paketai: vienas skrenda į vieną pusę, antrasis į kitą. Viena kelionė pirmyn ir atgal – ir kodas gavo atsakymą iš variklio be rankos paspaudimo.

Taip, viskas tiesiog veikia su labai mažu paketų praradimo procentu. Protokolas turi retransliacijų ir timeout'ų palaikymą, bet jei daug pralaimėsime, gausime beveik TCP, o tai nėra pelninga. Mes nevažinėjame UDP per vandenynus.

Tokių serverių turime tūkstančius, o schema ta pati: kiekviename fiziniame serveryje įdiegtas variklių paketas. Jie dažniausiai yra vienos sriegio, kad veiktų kuo greičiau ir neužblokuotų, ir yra suskaidyti kaip vienos gijos sprendimai. Tuo pačiu neturime nieko patikimesnio už šiuos variklius, o daug dėmesio skiriama nuolatiniam duomenų saugojimui.

Nuolatinis duomenų saugojimas

Varikliai rašo binlogus. „Binlog“ yra failas, kurio pabaigoje pridedamas būsenos arba duomenų pasikeitimo įvykis. Skirtinguose sprendimuose jis vadinamas skirtingai: dvejetainis žurnalas, WAL, AOF, bet principas tas pats.

Kad variklis neperskaitytų viso binlogo daug metų, kai paleidžiamas iš naujo, varikliai rašo momentinės nuotraukos – dabartinė būsena. Jei reikia, jie pirmiausia skaito iš jo, o tada baigia skaityti iš binlogo. Visi binlogai rašomi tuo pačiu dvejetainiu formatu – pagal TL schemą, kad administratoriai galėtų juos vienodai administruoti savo įrankiais. Nėra tokio momentinių vaizdų poreikio. Yra bendra antraštė, kuri nurodo, kieno momentinė nuotrauka yra int, variklio magija ir kuris korpusas niekam nesvarbus. Tai yra variklio, kuris įrašė momentinę nuotrauką, problema.

Greitai aprašysiu veikimo principą. Yra serveris, kuriame veikia variklis. Jis atidaro naują tuščią žurnalą rašymui ir įrašo įvykį, kad jį pakeistų.

DUK apie VKontakte architektūrą ir darbą

Tam tikru momentu jis arba nusprendžia pats padaryti momentinę nuotrauką, arba gauna signalą. Serveris sukuria naują failą, įrašo į jį visą jo būseną, prie failo pabaigos prideda esamą binlogo dydį – poslinkį – ir toliau rašo. Naujas bilogas nesukuriamas.

DUK apie VKontakte architektūrą ir darbą

Tam tikru momentu, kai variklis bus paleistas iš naujo, diske bus ir binlogas, ir momentinė nuotrauka. Variklis nuskaito visą momentinę nuotrauką ir tam tikru momentu padidina savo būseną.

DUK apie VKontakte architektūrą ir darbą

Nuskaito poziciją, kuri buvo momentinės nuotraukos kūrimo metu, ir binlogo dydį.

DUK apie VKontakte architektūrą ir darbą

Skaito binlogo pabaigą, kad gautų dabartinę būseną, ir toliau rašo tolesnius įvykius. Tai paprasta schema, pagal ją veikia visi mūsų varikliai.

Duomenų replikacija

Dėl to duomenų replikacija mūsų pareiškimu pagrįstas — binlog'e rašome ne bet kokius puslapio pakeitimus, o būtent prašymus pakeisti. Labai panašus į tai, kas ateina per tinklą, tik šiek tiek pakeista.

Ta pati schema naudojama ne tik replikacijai, bet ir atsarginėms kopijoms kurti. Turime variklį – rašymo meistrą, kuris rašo į binlogą. Bet kurioje kitoje vietoje, kur administratoriai jį nustato, šis binlogas nukopijuojamas, ir viskas – turime atsarginę kopiją.

DUK apie VKontakte architektūrą ir darbą

Jei reikia skaitymo replikaNorint sumažinti procesoriaus skaitymo apkrovą, tiesiog paleidžiamas skaitymo variklis, kuris nuskaito binlog pabaigą ir vykdo šias komandas vietoje.

Atsilikimas čia labai mažas, ir galima sužinoti, kiek replika atsilieka nuo meistro.

Duomenų bendrinimas RPC tarpiniame serveryje

Kaip veikia dalijimasis? Kaip įgaliotasis serveris supranta, į kurią klasterio skeveldrą siųsti? Kode neparašyta: „Siųsk už 15 šukių! - ne, tai atlieka įgaliotinis.

Paprasčiausia schema yra pirmoji — pirmasis prašymo numeris.

get(photo100_500) => 100 % N.

Tai yra paprasto atmintyje įrašyto teksto protokolo pavyzdys, tačiau, žinoma, užklausos gali būti sudėtingos ir struktūrizuotos. Pavyzdyje paimamas pirmasis užklausos skaičius, o likusi dalis padalyta iš grupės dydžio.

Tai naudinga, kai norime turėti vieno objekto duomenų vietą. Tarkime, kad 100 yra vartotojo arba grupės ID ir norime, kad visi vieno objekto duomenys būtų vienoje skeveldroje sudėtingoms užklausoms.

Jei mums nerūpi, kaip užklausos paskirstomos klasteryje, yra kita galimybė – maišyti visą skeveldrą.

hash(photo100_500) => 3539886280 % N

Taip pat gauname maišą, likusią padalijimo dalį ir skeveldros numerį.

Abu šie variantai veikia tik tuo atveju, jei esame pasiruošę tam, kad padidinę klasterio dydį, jį padalinsime arba padidinsime kelis kartus. Pavyzdžiui, mes turėjome 16 šukių, neturime pakankamai, norime daugiau - galime saugiai gauti 32 be prastovų. Jei norime didinti ne kartotinius, bus prastovos, nes negalėsime visko tiksliai išskaidyti be nuostolių. Šios parinktys yra naudingos, bet ne visada.

Jei mums reikia pridėti arba pašalinti savavališką skaičių serverių, mes naudojame Nuosekli maiša ant žiedo a la Ketama. Tačiau tuo pačiu metu visiškai prarandame duomenų vietą; turime sujungti užklausą su klasteriumi, kad kiekviena dalis pateiktų savo nedidelį atsakymą, o tada atsakymus sujungti su tarpiniu serveriu.

Yra ypač specifinių užklausų. Tai atrodo taip: RPC tarpinis serveris gauna užklausą, nustato, į kurį klasterį eiti, ir nustato skeveldrą. Tada yra arba rašymo meistrai, arba, jei klasteris palaiko repliką, jis siunčia į kopiją pagal poreikį. Įgaliotasis serveris daro visa tai.

DUK apie VKontakte architektūrą ir darbą

Rąstai

Žurnalus rašome keliais būdais. Akivaizdžiausias ir paprasčiausias yra rašyti žurnalus į atmintinę.

ring-buffer: prefix.idx = line

Yra rakto priešdėlis – žurnalo pavadinimas, eilutė, ir yra šio žurnalo dydis – eilučių skaičius. Paimame atsitiktinį skaičių nuo 0 iki eilučių skaičiaus atėmus 1. Raktas atminties talpykloje yra priešdėlis, sujungtas su šiuo atsitiktiniu skaičiumi. Į reikšmę išsaugome žurnalo eilutę ir esamą laiką.

Kai reikia skaityti žurnalus, atliekame Multi Get visi raktai, surūšiuoti pagal laiką, ir tokiu būdu gauti gamybos žurnalą realiuoju laiku. Schema naudojama, kai reikia kažką derinti gamyboje realiu laiku, nieko nesulaužant, nestabdant ir neleidžiant srauto į kitas mašinas, tačiau šis žurnalas trunka neilgai.

Patikimam rąstų saugojimui turime variklį rąstų variklis. Būtent todėl jis buvo sukurtas ir plačiai naudojamas daugelyje grupių. Didžiausiame mano žinomame klasteryje supakuotų rąstų yra 600 TB.

Variklis labai senas, yra klasterių kurioms jau 6-7 metai. Yra problemų, kurias bandome išspręsti, pavyzdžiui, pradėjome aktyviai naudoti „ClickHouse“ žurnalams saugoti.

Žurnalų rinkimas ClickHouse

Ši diagrama parodo, kaip mes patenkame į savo variklius.

DUK apie VKontakte architektūrą ir darbą

Yra kodas, kuris vietiniu būdu per RPC patenka į RPC tarpinį serverį ir supranta, kur eiti į variklį. Jei norime rašyti žurnalus „ClickHouse“, šioje schemoje turime pakeisti dvi dalis:

  • pakeisti kai kuriuos variklius ClickHouse;
  • pakeisti RPC tarpinį serverį, kuris negali pasiekti ClickHouse, kokiu nors sprendimu, kuris gali, ir per RPC.

Variklis paprastas – jį pakeičiame serveriu arba serverių klasterį su ClickHouse.

O norėdami patekti į ClickHouse, mes tai padarėme Kačiuko namas. Jei eisime tiesiai iš KittenHouse į ClickHouse, jis nesusitvarkys. Net ir be užklausų jis susidaro iš daugybės mašinų HTTP jungčių. Kad schema veiktų, serveryje su ClickHouse pakeliamas vietinis atvirkštinis tarpinis serveris, kuris parašytas taip, kad atlaikytų reikiamus jungčių kiekius. Jis taip pat gali gana patikimai saugoti duomenis savyje.

DUK apie VKontakte architektūrą ir darbą

Kartais mes nenorime įdiegti RPC schemos nestandartiniuose sprendimuose, pavyzdžiui, nginx. Todėl „KittenHouse“ turi galimybę gauti žurnalus per UDP.

DUK apie VKontakte architektūrą ir darbą

Jei žurnalų siuntėjas ir gavėjas dirba tame pačiame kompiuteryje, tada tikimybė prarasti UDP paketą vietiniame pagrindiniame kompiuteryje yra gana maža. Kaip kompromisą tarp būtinybės įdiegti RPC trečiosios šalies sprendime ir patikimumo, mes tiesiog naudojame UDP siuntimą. Prie šios schemos grįšime vėliau.

Stebėjimas

Turime dviejų tipų žurnalus: tuos, kuriuos renka administratoriai savo serveriuose, ir tuos, kuriuos kūrėjai parašė iš kodo. Jie atitinka dviejų tipų metriką: sistema ir produktas.

Sistemos metrika

Jis veikia visuose mūsų serveriuose „Netdata“, kuri renka statistiką ir siunčia ją į Grafitas anglis. Todėl „ClickHouse“ naudojama kaip saugojimo sistema, o ne, pavyzdžiui, „Whisper“. Jei reikia, galite skaityti tiesiogiai iš ClickHouse arba naudoti grafana metrikai, diagramoms ir ataskaitoms. Kaip kūrėjai, turime pakankamai prieigos prie „Netdata“ ir „Grafana“.

Produkto metrika

Patogumui prirašėme daug dalykų. Pavyzdžiui, yra įprastų funkcijų rinkinys, leidžiantis į statistiką įrašyti Counts, UniqueCounts reikšmes, kurios siunčiamos kažkur toliau.

statlogsCountEvent   ( ‘stat_name’,            $key1, $key2, …)
statlogsUniqueCount ( ‘stat_name’, $uid,    $key1, $key2, …)
statlogsValuetEvent  ( ‘stat_name’, $value, $key1, $key2, …)

$stats = statlogsStatData($params)

Vėliau galime naudoti rūšiavimo ir grupavimo filtrus ir daryti viską, ko norime iš statistikos – kurti grafikus, konfigūruoti Watchdogs.

Rašome labai daug metrikų įvykių skaičius yra nuo 600 milijardų iki 1 trilijono per dieną. Tačiau norime juos išlaikyti bent porą metųsuprasti metrikos tendencijas. Viską sudėti – didelė problema, kurios dar neišsprendėme. Aš jums papasakosiu, kaip tai veikė pastaruosius kelerius metus.

Turime funkcijas, kurios įrašo šiuos rodiklius į vietinę atmintinęsumažinti įrašų skaičių. Kartą per trumpą laiką paleistas vietoje statistikos demonas renka visus įrašus. Tada demonas sujungia metrikas į du serverių sluoksnius rąstų surinkėjai, kuri kaupia kelių mūsų mašinų statistiką, kad už jų esantis sluoksnis nemirtų.

DUK apie VKontakte architektūrą ir darbą

Esant poreikiui galime rašyti tiesiai į rąstus-rinkėjus.

DUK apie VKontakte architektūrą ir darbą

Tačiau rašymas iš kodo tiesiai į kolektorius, apeinant stas-daemom, yra prastai keičiamas sprendimas, nes tai padidina kolektoriaus apkrovą. Sprendimas tinka tik tuo atveju, jei dėl kokių nors priežasčių negalime pakelti memcache stats-daemon mašinoje arba jis sudužo ir mes nuėjome tiesiai.

Toliau žurnalų rinkėjai sujungia statistiką į miauDB – tai mūsų duomenų bazė, kurioje taip pat galima saugoti metrikas.

DUK apie VKontakte architektūrą ir darbą

Tada galime pasirinkti iš kodo dvejetainiu „beveik SQL“ būdu.

DUK apie VKontakte architektūrą ir darbą

Eksperimentas

2018 m. vasarą turėjome vidinį hakatoną ir kilo mintis pabandyti pakeisti raudoną diagramos dalį kažkuo, kas galėtų saugoti metriką ClickHouse. „ClickHouse“ turime žurnalus – kodėl gi nepabandžius?

DUK apie VKontakte architektūrą ir darbą

Turėjome schemą, kuri rašė žurnalus per KittenHouse.

DUK apie VKontakte architektūrą ir darbą

Mes nusprendėme prie diagramos pridėkite kitą „*Namą“., kuri gaus tiksliai metriką tokiu formatu, kokiu mūsų kodas juos įrašys per UDP. Tada šis *House juos paverčia įdėklais, kaip rąstais, kuriuos KittenHouse supranta. Jis gali puikiai pristatyti šiuos žurnalus į ClickHouse, kuris turėtų sugebėti juos perskaityti.

DUK apie VKontakte architektūrą ir darbą

Schema su „memcache“, „stats-demon“ ir „logs-collectors“ duomenų baze pakeičiama šia.

DUK apie VKontakte architektūrą ir darbą

Schema su „memcache“, „stats-demon“ ir „logs-collectors“ duomenų baze pakeičiama šia.

  • Čia yra siuntimas iš kodo, kuris parašytas vietoje StatsHouse.
  • StatsHouse rašo UDP metrikas, jau konvertuotas į SQL įdėklus, į KittenHouse partijomis.
  • KittenHouse juos siunčia į ClickHouse.
  • Jei norime juos perskaityti, skaitome juos aplenkdami StatsHouse – tiesiai iš ClickHouse naudodami įprastą SQL.

Ar vis dar eksperimentas, bet mums patinka, kaip tai pasirodo. Jei išspręsime schemos problemas, galbūt visiškai prie jos pereisime. Asmeniškai aš taip tikiuosi.

Schema netaupo geležies. Reikia mažiau serverių, nereikia vietinių statistikos demonų ir žurnalų rinktuvų, tačiau ClickHouse reikia didesnio serverio nei dabartinėje schemoje. Reikia mažiau serverių, tačiau jie turi būti brangesni ir galingesni.

Dislokuoti

Pirmiausia pažvelkime į PHP diegimą. Mes vystome Git: naudoti GitLab и TeamCity dislokavimui. Plėtros šakos sujungiamos į pagrindinę šaką, iš pagrindinio testavimui sujungiamos į pastatymą, o iš sustojimo į gamybą.

Prieš diegiant paimama dabartinė gamybos šaka ir ankstesnė, jose atsižvelgiama į diff failus - pakeitimus: sukurta, ištrinta, pakeista. Šis pakeitimas įrašomas specialaus „copyfast“ variklio, kuris gali greitai pakartoti pakeitimus visame mūsų serverių parke, žurnale. Čia naudojamas ne tiesioginis kopijavimas, o paskalų replikacija, kai vienas serveris siunčia pakeitimus artimiausiems kaimynams, tuos – savo kaimynams ir pan. Tai leidžia atnaujinti kodą per kelias dešimtis ir sekundžių vienetais visame automobilių parke. Kai pakeitimas pasiekia vietinę kopiją, jis taiko šiuos pataisymus vietinė failų sistema. Atšaukimas taip pat atliekamas pagal tą pačią schemą.

Taip pat daug diegiame kPHP ir jis taip pat turi savo plėtrą Git pagal aukščiau pateiktą schemą. Nuo šio HTTP serverio dvejetainis, tada mes negalime sukurti diff – išleidimo dvejetainis failas sveria šimtus MB. Todėl čia yra kitas variantas – versija rašoma į binlog copyfast. Su kiekvienu konstravimu jis didėja, o atšaukimo metu taip pat didėja. Versija replikuotas į serverius. Vietiniai kopijavimo specialistai mato, kad į binlog pateko nauja versija, ir tuo pačiu paskalų replikavimu jie paima sau naujausią dvejetainio failo versiją, nevargindami mūsų pagrindinio serverio, bet atsargiai paskirstydami apkrovą visame tinkle. Kas seka grakštus paleidimas naujajai versijai.

Mūsų variklių, kurie taip pat iš esmės yra dvejetainiai, schema yra labai panaši:

  • git master filialas;
  • dvejetainis in deb;
  • versija įrašyta į binlog copyfast;
  • replikuotas į serverius;
  • serveris ištraukia naują .dep;
  • dpkg -i;
  • grakštus naujos versijos paleidimas.

Skirtumas tas, kad mūsų dvejetainis failas yra supakuotas archyvuose deb, o juos išpumpuojant dpkg -i yra dedami į sistemą. Kodėl kPHP naudojamas kaip dvejetainis failas, o varikliai – kaip dpkg? Taip atsitiko. Veikia – nelieskite.

Naudingos nuorodos:

Aleksejus Akulovičius yra vienas iš tų, kurie, kaip programos komiteto dalis, padeda PHP Rusija gegužės 17 d., taps didžiausiu PHP kūrėjų renginiu pastaruoju metu. Pažiūrėk, kokį šaunų kompiuterį turime, ką garsiakalbiai (du iš jų kuria PHP branduolį!) – atrodo, kad nieko negalite praleisti rašydami PHP.

Šaltinis: www.habr.com

Добавить комментарий