Gereelde vrae oor argitektuur en werk van VKontakte

Die geskiedenis van die skepping van VKontakte is op Wikipedia; dit is deur Pavel self vertel. Dit blyk dat almal haar reeds ken. Oor die interne, argitektuur en struktuur van die webwerf op HighLoad++ Pavel het my in 2010 vertel. Baie bedieners het sedertdien uitgelek, so ons sal die inligting opdateer: ons sal dit dissekteer, die binnekant uithaal, weeg en kyk na die VK-toestel vanuit 'n tegniese oogpunt.

Gereelde vrae oor argitektuur en werk van VKontakte

Alexey Akulovich (AterCattus) backend-ontwikkelaar in die VKontakte-span. Die transkripsie van hierdie verslag is 'n gesamentlike antwoord op gereelde vrae oor die werking van die platform, infrastruktuur, bedieners en interaksie tussen hulle, maar nie oor ontwikkeling nie, naamlik oor yster. Afsonderlik, oor databasisse en wat VK eerder het, oor die versameling van logs en die monitering van die hele projek as geheel. Besonderhede onder die snit.



Vir meer as vier jaar is ek besig met allerhande take wat verband hou met die backend.

  • Oplaai, stoor, verwerk, versprei media: video, regstreekse stroom, oudio, foto's, dokumente.
  • Infrastruktuur, platform, ontwikkelaarmonitering, logs, streekkas, CDN, eie RPC-protokol.
  • Integrasie met eksterne dienste: stootkennisgewings, eksterne skakelontleding, RSS-feed.
  • Om kollegas te help met verskeie vrae, waarvan die antwoorde vereis dat jy in onbekende kode duik.

Gedurende hierdie tyd het ek 'n hand in baie komponente van die webwerf gehad. Ek wil hierdie ervaring deel.

Algemene argitektuur

Alles, soos gewoonlik, begin met 'n bediener of groep bedieners wat versoeke aanvaar.

Voorste bediener

Die voorste bediener aanvaar versoeke via HTTPS, RTMP en WSS.

HTTPS - dit is versoeke vir die hoof- en mobiele webweergawes van die webwerf: vk.com en m.vk.com, en ander amptelike en nie-amptelike kliënte van ons API: mobiele kliënte, boodskappers. Ons het 'n onthaal RTMP-verkeer vir regstreekse uitsendings met aparte voorbedieners en WSS- verbindings vir Streaming API.

Vir HTTPS en WSS op bedieners is dit die moeite werd nginx. Vir RTMP-uitsendings het ons onlangs na ons eie oplossing oorgeskakel kive, maar dit is buite die bestek van die verslag. Vir foutverdraagsaamheid adverteer hierdie bedieners algemene IP-adresse en tree in groepe op sodat indien daar 'n probleem op een van die bedieners is, gebruikersversoeke nie verlore gaan nie. Vir HTTPS en WSS enkripteer dieselfde bedieners verkeer om 'n deel van die SVE-lading op hulself te neem.

Ons gaan nie verder oor WSS en RTMP praat nie, maar slegs oor standaard HTTPS-versoeke, wat gewoonlik met 'n webprojek geassosieer word.

Backend

Agter die voorkant is daar gewoonlik backend-bedieners. Hulle verwerk versoeke wat die voorste bediener van kliënte ontvang.

Dit kPHP-bedieners, waarop die HTTP-demoon loop, omdat HTTPS reeds gedekripteer is. kPHP is 'n bediener wat op loop voorvurk modelle: begin 'n meesterproses, 'n klomp kinderprosesse, gee luistervoete aan hulle en hulle verwerk hul versoeke. In hierdie geval word prosesse nie herbegin tussen elke versoek van die gebruiker nie, maar stel bloot hul toestand terug na die oorspronklike nulwaarde-toestand - versoek na versoek, in plaas van herbegin.

Vragverdeling

Al ons backends is nie 'n groot poel masjiene wat enige versoek kan verwerk nie. Ons hulle verdeel in aparte groepe: algemeen, selfoon, api, video, staging... Die probleem op 'n aparte groep masjiene sal nie alle ander raak nie. In die geval van probleme met video, sal die gebruiker wat na musiek luister nie eers van die probleme weet nie. Na watter backend die versoek gestuur moet word, word bepaal deur nginx aan die voorkant volgens die config.

Metrieke versameling en herbalansering

Om te verstaan ​​hoeveel motors ons in elke groep moet hê, moet ons moenie op QPS staatmaak nie. Die backends is anders, hulle het verskillende versoeke, elke versoek het 'n ander kompleksiteit van die berekening van QPS. Dis hoekom ons ons werk met die konsep van las op die bediener as geheel - op die SVE en perf.

Ons het duisende sulke bedieners. Elke fisiese bediener bestuur 'n kPHP-groep om al die kerne te herwin (omdat kPHP enkeldraad is).

Inhoudbediener

CS of inhoudbediener is 'n berging. CS is 'n bediener wat lêers stoor en ook opgelaaide lêers verwerk en allerhande agtergrond-sinchroniese take wat die hoof webfrontend daaraan toewys.

Ons het tienduisende fisiese bedieners wat lêers stoor. Gebruikers hou daarvan om lêers op te laai, en ons hou daarvan om dit te stoor en te deel. Sommige van hierdie bedieners word gesluit deur spesiale pu/pp-bedieners.

pu/pp

As jy die netwerkoortjie in VK oopgemaak het, het jy pu/pp gesien.

Gereelde vrae oor argitektuur en werk van VKontakte

Wat is pu/pp? As ons die een bediener na die ander toemaak, is daar twee opsies om 'n lêer op te laai en af ​​te laai na die bediener wat gesluit was: direk deur http://cs100500.userapi.com/path of via intermediêre bediener - http://pu.vk.com/c100500/path.

Pu is die historiese naam vir foto-oplaai, en pp is foto-instaanbediener. Dit wil sê, een bediener is vir die oplaai van foto's, en 'n ander is vir die oplaai. Nou word nie net foto's gelaai nie, maar die naam het behoue ​​gebly.

Hierdie bedieners beëindig HTTPS-sessiesom die verwerkerlading uit die stoor te verwyder. Ook, aangesien gebruikerslêers op hierdie bedieners verwerk word, hoe minder sensitiewe inligting wat op hierdie masjiene gestoor word, hoe beter. Byvoorbeeld, HTTPS-enkripsiesleutels.

Aangesien die masjiene deur ons ander masjiene gesluit word, kan ons bekostig om nie vir hulle "wit" eksterne IP's te gee nie, en gee "grys". Op hierdie manier het ons op die IP-poel bespaar en gewaarborg om die masjiene teen toegang van buite te beskerm - daar is eenvoudig geen IP om daarin te kom nie.

Veerkragtigheid oor gedeelde IP's. Wat fouttoleransie betref, werk die skema dieselfde - verskeie fisiese bedieners het 'n gemeenskaplike fisiese IP, en die hardeware voor hulle kies waarheen om die versoek te stuur. Ek sal later oor ander opsies praat.

Die kontroversiële punt is dat in hierdie geval die kliënt hou minder verbindings. As daar dieselfde IP vir verskeie masjiene is - met dieselfde gasheer: pu.vk.com of pp.vk.com, het die kliëntblaaier 'n beperking op die aantal gelyktydige versoeke aan een gasheer. Maar in die tyd van alomteenwoordige HTTP/2, glo ek dat dit nie meer so relevant is nie.

Die ooglopende nadeel van die skema is dat dit moet pomp alle verkeer, wat deur 'n ander bediener na die berging gaan. Aangesien ons verkeer deur masjiene pomp, kan ons nog nie swaar verkeer, byvoorbeeld video, met dieselfde skema pomp nie. Ons stuur dit direk - 'n aparte direkte verbinding vir aparte bergings spesifiek vir video. Ons stuur ligter inhoud deur 'n instaanbediener.

Nie lank gelede nie het ons 'n verbeterde weergawe van proxy gekry. Nou sal ek jou vertel hoe hulle verskil van gewones en hoekom dit nodig is.

Sondag

In September 2017 het Oracle, wat voorheen Sun gekoop het, 'n groot aantal Sun-werknemers afgedank het. Ons kan sê dat die maatskappy op hierdie oomblik ophou bestaan ​​het. Toe ons 'n naam vir die nuwe stelsel gekies het, het ons administrateurs besluit om hulde te bring aan die geheue van hierdie maatskappy en die nuwe stelsel Sun genoem. Onder ons noem ons haar sommer “sonne”.

Gereelde vrae oor argitektuur en werk van VKontakte

pp het 'n paar probleme gehad. Een IP per groep – oneffektiewe kas. Verskeie fisiese bedieners deel 'n gemeenskaplike IP-adres, en daar is geen manier om te beheer na watter bediener die versoek sal gaan nie. Daarom, as verskillende gebruikers vir dieselfde lêer kom, dan as daar 'n kas op hierdie bedieners is, beland die lêer in die kas van elke bediener. Dit is 'n baie ondoeltreffende skema, maar niks kon gedoen word nie.

Gevolglik - ons kan nie inhoud versnipper nie, want ons kan nie 'n spesifieke bediener vir hierdie groep kies nie - hulle het 'n gemeenskaplike IP. Ook vir 'n paar interne redes wat ons het dit was nie moontlik om sulke bedieners in streke te installeer nie. Hulle het net in St. Petersburg gestaan.

Met die sonne het ons die seleksiestelsel verander. Nou het ons anycast-roetering: dinamiese roetering, anycast, self-check daemon. Elke bediener het sy eie individuele IP, maar 'n gemeenskaplike subnet. Alles is so gekonfigureer dat as een bediener misluk, die verkeer outomaties oor die ander bedieners van dieselfde groep versprei word. Nou is dit moontlik om 'n spesifieke bediener te kies, geen oortollige caching nie, en betroubaarheid is nie aangetas nie.

Gewig ondersteuning. Nou kan ons bekostig om masjiene van verskillende krag te installeer soos nodig, en ook, in geval van tydelike probleme, die gewigte van die werkende "sonne" verander om die las op hulle te verminder, sodat hulle "rus" en weer begin werk.

Deling volgens inhoud-ID. 'n Snaakse ding van sharding: ons verdeel gewoonlik inhoud sodat verskillende gebruikers deur dieselfde "son" na dieselfde lêer gaan sodat hulle 'n gemeenskaplike kas het.

Ons het onlangs die "Clover"-toepassing bekendgestel. Dit is 'n aanlyn vasvra in 'n regstreekse uitsending, waar die gasheer vrae vra en gebruikers intyds antwoord deur opsies te kies. Die toepassing het 'n klets waar gebruikers kan gesels. Kan gelyktydig aan die uitsending koppel meer as 100 duisend mense. Hulle skryf almal boodskappe wat aan alle deelnemers gestuur word, en 'n avatar kom saam met die boodskap. As 100 duisend mense vir een avatar in een "son" kom, dan kan dit soms agter 'n wolk aanrol.

Om sarsies van versoeke vir dieselfde lêer te weerstaan, is dit vir 'n sekere tipe inhoud wat ons 'n dom skema aanskakel wat lêers oor alle beskikbare "sonne" in die streek versprei.

Son van binne

Omgekeerde proxy op nginx, kas óf in RAM óf op vinnige Optane/NVMe-skywe. Voorbeeld: http://sun4-2.userapi.com/c100500/path - 'n skakel na die "son", wat in die vierde streek, die tweede bedienergroep, geleë is. Dit maak die padlêer toe, wat fisies op bediener 100500 lê.

Cache

Ons voeg nog een nodus by ons argitektoniese skema - die kas-omgewing.

Gereelde vrae oor argitektuur en werk van VKontakte

Hieronder is die uitlegdiagram streeksgeheue, daar is omtrent 20 van hulle. Dit is die plekke waar caches en "sonne" geleë is, wat verkeer deur hulself kan kas.

Gereelde vrae oor argitektuur en werk van VKontakte

Dit is kas van multimedia-inhoud; geen gebruikerdata word hier gestoor nie - net musiek, video, foto's.

Om die gebruiker se streek te bepaal, het ons ons versamel BGP-netwerkvoorvoegsels wat in die streke aangekondig is. In die geval van terugval, moet ons ook die geoip-databasis ontleed as ons nie die IP deur voorvoegsels kon vind nie. Ons bepaal die streek deur die gebruiker se IP. In die kode kan ons na een of meer streke van die gebruiker kyk - daardie punte waaraan hy geografies die naaste is.

Hoe werk dit?

Ons tel die gewildheid van lêers volgens streek. Daar is 'n aantal van die streekkas waar die gebruiker geleë is, en 'n lêeridentifiseerder - ons neem hierdie paar en verhoog die gradering met elke aflaai.

Terselfdertyd kom demone - dienste in streke - van tyd tot tyd na die API en sê: "Ek is so en so 'n kas, gee my 'n lys van die gewildste lêers in my streek wat nog nie op my is nie. ” Die API lewer 'n klomp lêers gesorteer volgens gradering, die daemon laai dit af, neem dit na die streke en lewer die lêers van daar af. Dit is die fundamentele verskil tussen pu/pp en Sun vanaf kas: hulle gee die lêer dadelik deur hulself, selfs al is hierdie lêer nie in die kas nie, en die kas laai eers die lêer na homself af, en begin dit dan teruggee.

In hierdie geval kry ons inhoud nader aan gebruikers en versprei die netwerklading. Byvoorbeeld, slegs vanaf die Moskou-kas versprei ons meer as 1 Tbit/s gedurende spitstye.

Maar daar is probleme - kasbedieners is nie rubber nie. Vir supergewilde inhoud is daar soms nie genoeg netwerk vir 'n aparte bediener nie. Ons kasbedieners is 40-50 Gbit/s, maar daar is inhoud wat so 'n kanaal heeltemal verstop. Ons beweeg na die implementering van berging van meer as een kopie van gewilde lêers in die streek. Ek hoop dat ons dit teen die einde van die jaar sal implementeer.

Ons het na die algemene argitektuur gekyk.

  • Voorste bedieners wat versoeke aanvaar.
  • Backends wat proses versoeke.
  • Bergings wat deur twee tipes gevolmagtigdes gesluit word.
  • Streekskase.

Wat ontbreek in hierdie diagram? Natuurlik die databasisse waarin ons data stoor.

Databasisse of enjins

Ons noem dit nie databasisse nie, maar enjins - Enjins, want ons het feitlik nie databasisse in die algemeen aanvaarde sin nie.

Gereelde vrae oor argitektuur en werk van VKontakte

Dit is 'n noodsaaklike maatreël. Dit het gebeur omdat in 2008-2009, toe VK 'n plofbare groei in gewildheid gehad het, die projek heeltemal op MySQL en Memcache gewerk het en daar was probleme. MySQL was mal daaroor om lêers te verongeluk en korrupteer, waarna dit nie sou herstel nie, en Memcache het geleidelik afgeneem in werkverrigting en moes herbegin word.

Dit blyk dat die toenemend gewilde projek aanhoudende berging gehad het, wat data korrupteer, en 'n kas, wat stadiger word. In sulke toestande is dit moeilik om 'n groeiende projek te ontwikkel. Daar is besluit om die kritieke dinge waarop die projek gefokus was, op ons eie fietse te probeer herskryf.

Die oplossing was suksesvol. Daar was 'n geleentheid om dit te doen, sowel as 'n uiterste noodsaaklikheid, want ander maniere van skaal het op daardie stadium nie bestaan ​​nie. Daar was nie 'n klomp databasisse nie, NoSQL het nog nie bestaan ​​nie, daar was net MySQL, Memcache, PostrgreSQL - en dit is dit.

Universele werking. Die ontwikkeling is gelei deur ons span C-ontwikkelaars en alles is op 'n konsekwente manier gedoen. Ongeag die enjin, hulle het almal ongeveer dieselfde lêerformaat gehad wat op skyf geskryf is, dieselfde bekendstellingsparameters, seine op dieselfde manier verwerk, en het ongeveer dieselfde gedra in geval van randsituasies en probleme. Met die groei van enjins is dit gerieflik vir administrateurs om die stelsel te bedryf - daar is geen dieretuin wat in stand gehou moet word nie, en hulle moet weer leer hoe om elke nuwe derdeparty-databasis te bedryf, wat dit moontlik gemaak het om vinnig en gerieflik te vergroot hul nommer.

Soorte enjins

Die span het 'n hele paar enjins geskryf. Hier is net 'n paar van hulle: vriend, wenke, beeld, ipdb, briewe, lyste, logs, memcached, meowdb, nuus, nostradamus, foto, snitlyste, pmemcached, sandbox, soek, berging, laaiks, take, …

Vir elke taak wat 'n spesifieke datastruktuur vereis of atipiese versoeke verwerk, skryf die C-span 'n nuwe enjin. Hoekom nie.

Ons het 'n aparte enjin memcached, wat soortgelyk is aan 'n gewone een, maar met 'n klomp lekkernye, en wat nie stadiger word nie. Nie ClickHouse nie, maar dit werk ook. Afsonderlik beskikbaar pmemcached - Is aanhoudende memcached, wat ook data op skyf kan stoor, bowendien, dan pas in RAM, om nie data te verloor wanneer u herbegin nie. Daar is verskeie enjins vir individuele take: toue, lyste, stelle - alles wat ons projek vereis.

Trosse

Vanuit 'n kode-perspektief is dit nie nodig om aan enjins of databasisse te dink as prosesse, entiteite of gevalle nie. Die kode werk spesifiek met groepe, met groepe enjins - een tipe per tros. Kom ons sê daar is 'n gemcached cluster - dit is net 'n groep masjiene.

Die kode hoef glad nie die fisiese ligging, grootte of aantal bedieners te ken nie. Hy gaan na die groep met 'n sekere identifiseerder.

Vir dit om te werk, moet jy nog een entiteit byvoeg wat tussen die kode en die enjins geleë is - proxy.

RPC-instaanbediener

Volmag koppelbus, waarop byna die hele webwerf loop. Terselfdertyd het ons geen diensontdekking nie - in plaas daarvan is daar 'n konfigurasie vir hierdie instaanbediener, wat die ligging van alle trosse en alle skerwe van hierdie groep ken. Dit is wat admins doen.

Programmeerders gee glad nie om hoeveel, waar en wat dit kos nie - hulle gaan net na die groep. Dit laat ons baie toe. Wanneer 'n versoek ontvang word, herlei die gevolmagtigde die versoek, wetende waarheen - dit bepaal dit self.

Gereelde vrae oor argitektuur en werk van VKontakte

In hierdie geval is volmag 'n punt van beskerming teen diensmislukking. As een of ander enjin vertraag of ineenstort, verstaan ​​die proxy dit en reageer dienooreenkomstig aan die kliëntkant. Dit laat jou toe om die time-out te verwyder - die kode wag nie vir die enjin om te reageer nie, maar verstaan ​​dat dit nie werk nie en op een of ander manier anders moet optree. Die kode moet voorberei word vir die feit dat die databasisse nie altyd werk nie.

Spesifieke implementerings

Soms wil ons nog regtig 'n soort nie-standaard oplossing as 'n enjin hê. Terselfdertyd is besluit om nie ons klaargemaakte rpc-proxy, wat spesifiek vir ons enjins geskep is, te gebruik nie, maar om 'n aparte proxy vir die taak te maak.

Vir MySQL, wat ons nog hier en daar het, gebruik ons ​​db-proxy, en vir ClickHouse - Katjiehuisie.

Dit werk oor die algemeen so. Daar is 'n sekere bediener, dit loop kPHP, Go, Python - in die algemeen, enige kode wat ons RPC-protokol kan gebruik. Die kode loop plaaslik op 'n RPC-instaanbediener - elke bediener waar die kode geleë is, loop sy eie plaaslike instaanbediener. Op versoek verstaan ​​die gevolmagtigde waarheen om te gaan.

Gereelde vrae oor argitektuur en werk van VKontakte

As een enjin na 'n ander wil gaan, al is dit 'n buurman, gaan dit deur 'n instaanbediener, want die buurman kan in 'n ander datasentrum wees. Die enjin moet nie daarop staatmaak om die ligging van enigiets anders as homself te ken nie – dit is ons standaardoplossing. Maar daar is natuurlik uitsonderings :)

'n Voorbeeld van 'n TL-skema waarvolgens alle enjins werk.

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;

Dit is 'n binêre protokol, waarvan die naaste analoog is protobuf. Die skema beskryf opsionele velde, komplekse tipes - uitbreidings van ingeboude skalare en navrae. Alles werk volgens hierdie protokol.

RPC oor TL oor TCP/UDP … UDP?

Ons het 'n RPC-protokol vir die uitvoering van enjinversoeke wat bo-op die TL-skema loop. Dit werk alles oor 'n TCP/UDP-verbinding. TCP is verstaanbaar, maar hoekom het ons UDP dikwels nodig?

UDP help vermy die probleem van 'n groot aantal verbindings tussen bedieners. As elke bediener 'n RPC-instaanbediener het en dit oor die algemeen na enige enjin kan gaan, dan is daar tienduisende TCP-verbindings per bediener. Daar is 'n vrag, maar dit is nutteloos. In die geval van UDP bestaan ​​hierdie probleem nie.

Geen oortollige TCP-handdruk nie. Dit is 'n tipiese probleem: wanneer 'n nuwe enjin of 'n nuwe bediener geloods word, word baie TCP-verbindings gelyktydig tot stand gebring. Vir klein liggewig versoeke, byvoorbeeld, UDP loonvrag, is alle kommunikasie tussen die kode en die enjin twee UDP-pakkies: een vlieg in een rigting, die tweede in die ander. Een rondrit - en die kode het 'n reaksie van die enjin ontvang sonder 'n handdruk.

Ja, dit werk alles net met 'n baie klein persentasie pakkieverlies. Die protokol het ondersteuning vir heruitsendings en time-outs, maar as ons baie verloor, sal ons amper TCP kry, wat nie winsgewend is nie. Ons ry nie UDP oor oseane nie.

Ons het duisende sulke bedieners, en die skema is dieselfde: 'n pak enjins word op elke fisiese bediener geïnstalleer. Hulle is meestal enkeldraad om so vinnig as moontlik te hardloop sonder om te blokkeer, en word as enkeldraadoplossings geskeur. Terselfdertyd het ons niks meer betroubaar as hierdie enjins nie, en baie aandag word geskenk aan volgehoue ​​databerging.

Aanhoudende databerging

Enjins skryf binlogs. 'n Binlog is 'n lêer aan die einde waarvan 'n gebeurtenis vir 'n verandering in toestand of data bygevoeg word. In verskillende oplossings word dit anders genoem: binêre log, WAL, AOF, maar die beginsel is dieselfde.

Om te verhoed dat die enjin die hele binlog vir baie jare weer lees wanneer dit weer begin, skryf die enjins foto's - huidige toestand. Indien nodig, lees hulle eers daaruit, en lees dan klaar uit die binlog. Alle binlogs word in dieselfde binêre formaat geskryf - volgens die TL-skema, sodat admins dit eweredig kan administreer deur hul gereedskap te gebruik. Daar is nie so 'n behoefte aan kiekies nie. Daar is 'n algemene kopskrif wat aandui wie se momentopname int is, magie van die enjin, en watter liggaam vir niemand belangrik is nie. Dit is 'n probleem met die enjin wat die momentopname opgeneem het.

Ek sal vinnig die beginsel van werking beskryf. Daar is 'n bediener waarop die enjin loop. Hy maak 'n nuwe leë binlog oop vir skryf en skryf 'n geleentheid vir verandering daaraan.

Gereelde vrae oor argitektuur en werk van VKontakte

Op 'n stadium besluit hy óf om self 'n foto te neem, óf hy ontvang 'n sein. Die bediener skep 'n nuwe lêer, skryf sy hele toestand daarin, voeg die huidige binlog-grootte - offset - aan die einde van die lêer, en gaan voort om verder te skryf. 'n Nuwe binlog word nie geskep nie.

Gereelde vrae oor argitektuur en werk van VKontakte

Op 'n stadium, wanneer die enjin weer begin het, sal daar beide 'n binlog en 'n momentopname op die skyf wees. Die enjin lees die hele momentopname en verhoog sy toestand op 'n sekere punt.

Gereelde vrae oor argitektuur en werk van VKontakte

Lees die posisie wat was toe die momentopname geskep is en die grootte van die binlog.

Gereelde vrae oor argitektuur en werk van VKontakte

Lees die einde van die binlog om die huidige toestand te kry en gaan voort om verdere gebeure te skryf. Dit is 'n eenvoudige skema; ​​al ons enjins werk daarvolgens.

Data replikasie

As gevolg hiervan, data replikasie in ons verklaring gebaseer — ons skryf in die binlog nie enige bladsyveranderings nie, maar nl verander versoeke. Baie soortgelyk aan wat oor die netwerk kom, net effens gewysig.

Dieselfde skema word nie net vir replikasie gebruik nie, maar ook om rugsteun te skep. Ons het 'n enjin - 'n skryfmeester wat na die binlog skryf. Op enige ander plek waar die administrateurs dit opgestel het, word hierdie binlog gekopieer, en dit is dit - ons het 'n rugsteun.

Gereelde vrae oor argitektuur en werk van VKontakte

Indien nodig lees replikaOm die SVE-leeslading te verminder, word die leesenjin eenvoudig geloods, wat die einde van die binlog lees en hierdie opdragte plaaslik uitvoer.

Die vertraging hier is baie klein, en dit is moontlik om uit te vind hoeveel die replika agter die meester bly.

Datadeling in RPC-instaanbediener

Hoe werk skeuring? Hoe verstaan ​​die proxy na watter groepskerf om te stuur? Die kode sê nie: "Stuur vir 15 skerwe nie!" - nee, dit word deur die gevolmagtigde gedoen.

Die eenvoudigste skema is firstint — die eerste nommer in die versoek.

get(photo100_500) => 100 % N.

Dit is 'n voorbeeld vir 'n eenvoudige memcached teksprotokol, maar natuurlik kan navrae kompleks en gestruktureer wees. Die voorbeeld neem die eerste getal in die navraag en die res wanneer gedeel deur die groepgrootte.

Dit is nuttig wanneer ons data-lokaliteit van 'n enkele entiteit wil hê. Kom ons sê 100 is 'n gebruiker- of groep-ID, en ons wil hê dat al die data van een entiteit op een skerf moet wees vir komplekse navrae.

As ons nie omgee hoe versoeke oor die groep versprei word nie, is daar 'n ander opsie - hash die hele skerf.

hash(photo100_500) => 3539886280 % N

Ons kry ook die hash, die res van die verdeling en die skerfnommer.

Albei hierdie opsies werk net as ons voorbereid is op die feit dat wanneer ons die grootte van die groep vergroot, ons dit sal verdeel of dit met 'n veelvoud van kere sal vergroot. Ons het byvoorbeeld 16 skerwe gehad, ons het nie genoeg nie, ons wil meer hê - ons kan veilig 32 kry sonder stilstand. As ons nie veelvoude wil verhoog nie, sal daar stilstand wees, want ons sal nie alles akkuraat kan verdeel sonder verliese nie. Hierdie opsies is nuttig, maar nie altyd nie.

As ons 'n arbitrêre aantal bedieners moet byvoeg of verwyder, gebruik ons Konsekwente hashing op die ring a la Ketama. Maar terselfdertyd verloor ons die ligging van die data heeltemal; ons moet die versoek na die groep saamvoeg sodat elke stuk sy eie klein antwoord terugstuur, en dan die antwoorde saamvoeg na die instaanbediener.

Daar is superspesifieke versoeke. Dit lyk so: RPC-instaanbediener ontvang die versoek, bepaal na watter groep om te gaan en bepaal die skerf. Dan is daar óf skryfmeesters, óf, as die groep replika-ondersteuning het, stuur dit op aanvraag na 'n replika. Die gevolmagtigde doen dit alles.

Gereelde vrae oor argitektuur en werk van VKontakte

Logs

Ons skryf logs op verskeie maniere. Die mees voor die hand liggende en eenvoudigste een is skryf logs na memcache.

ring-buffer: prefix.idx = line

Daar is 'n sleutelvoorvoegsel - die naam van die log, 'n lyn, en daar is die grootte van hierdie log - die aantal reëls. Ons neem 'n ewekansige getal van 0 na die aantal reëls minus 1. Die sleutel in memcache is 'n voorvoegsel wat met hierdie ewekansige getal aaneengeskakel is. Ons stoor die loglyn en die huidige tyd tot die waarde.

Wanneer dit nodig is om logs te lees, voer ons uit Multi Kry alle sleutels, gesorteer volgens tyd, en kry dus 'n produksielog in reële tyd. Die skema word gebruik wanneer jy iets in produksie in reële tyd moet ontfout, sonder om iets te breek, sonder om verkeer na ander masjiene te stop of toe te laat, maar hierdie log hou nie lank nie.

Vir betroubare berging van stompe het ons 'n enjin logs-enjin. Dit is presies hoekom dit geskep is en word wyd gebruik in 'n groot aantal groepe. Die grootste groep wat ek ken, stoor 600 TB se verpakte stompe.

Die enjin is baie oud, daar is trosse wat al 6-7 jaar oud is. Daar is probleme daarmee wat ons probeer oplos, byvoorbeeld, ons het ClickHouse aktief begin gebruik om logs te stoor.

Versamel logs in ClickHouse

Hierdie diagram wys hoe ons in ons enjins instap.

Gereelde vrae oor argitektuur en werk van VKontakte

Daar is kode wat plaaslik via RPC na die RPC-proxy gaan, en dit verstaan ​​waarheen om na die enjin te gaan. As ons logs in ClickHouse wil skryf, moet ons twee dele in hierdie skema verander:

  • vervang een of ander enjin met ClickHouse;
  • vervang die RPC-instaanbediener, wat nie toegang tot ClickHouse kan kry nie, met een of ander oplossing wat kan, en via RPC.

Die enjin is eenvoudig - ons vervang dit met 'n bediener of 'n groep bedieners met ClickHouse.

En om na ClickHouse te gaan, het ons dit gedoen Katjiehuis. As ons direk van KittenHouse na ClickHouse gaan, sal dit nie regkom nie. Selfs sonder versoeke, voeg dit by van HTTP-verbindings van 'n groot aantal masjiene. Vir die skema om te werk, op 'n bediener met ClickHouse plaaslike omgekeerde volmag verhoog word, wat op so 'n manier geskryf is dat dit die vereiste volumes verbindings kan weerstaan. Dit kan ook data relatief betroubaar binne homself buffer.

Gereelde vrae oor argitektuur en werk van VKontakte

Soms wil ons nie die RPC-skema in nie-standaard oplossings implementeer nie, byvoorbeeld in nginx. Daarom het KittenHouse die vermoë om logs via UDP te ontvang.

Gereelde vrae oor argitektuur en werk van VKontakte

As die sender en ontvanger van die logs op dieselfde masjien werk, dan is die waarskynlikheid om 'n UDP-pakkie binne die plaaslike gasheer te verloor redelik laag. As 'n kompromie tussen die behoefte om RPC in 'n derdeparty-oplossing te implementeer en betroubaarheid, gebruik ons ​​eenvoudig UDP-versending. Ons sal later na hierdie skema terugkeer.

Monitering

Ons het twee tipes logs: dié wat deur administrateurs op hul bedieners ingesamel is en dié wat deur ontwikkelaars vanaf kode geskryf is. Hulle stem ooreen met twee tipes metrieke: stelsel en produk.

Stelsel statistieke

Dit werk op al ons bedieners netdata, wat statistieke versamel en dit na stuur Grafiet Koolstof. Daarom word ClickHouse as 'n stoorstelsel gebruik, en nie byvoorbeeld Whisper nie. Indien nodig, kan jy direk vanaf ClickHouse lees, of gebruik grafana vir statistieke, grafieke en verslae. As ontwikkelaars het ons genoeg toegang tot Netdata en Grafana.

Produk statistieke

Gerieflikheidshalwe het ons baie dinge geskryf. Daar is byvoorbeeld 'n stel gewone funksies waarmee u tellings, UniqueCounts-waardes in statistieke kan skryf, wat iewers verder gestuur word.

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

$stats = statlogsStatData($params)

Vervolgens kan ons sorteer- en groeperingsfilters gebruik en alles doen wat ons wil uit statistieke - grafieke bou, Waghonde instel.

Ons skryf baie baie maatstawwe die aantal gebeurtenisse is van 600 miljard tot 1 triljoen per dag. Ons wil hulle egter behou ten minste 'n paar jaarom tendense in metrieke te verstaan. Om alles bymekaar te sit is 'n groot probleem wat ons nog nie opgelos het nie. Ek sal jou vertel hoe dit die afgelope paar jaar gewerk het.

Ons het funksies wat hierdie metrieke skryf na plaaslike memcacheom die aantal inskrywings te verminder. Een keer in 'n kort tydperk plaaslik bekendgestel statistieke-daemon versamel alle rekords. Vervolgens voeg die demoon die statistieke saam in twee lae bedieners stompe-versamelaars, wat statistieke van 'n klomp van ons masjiene bymekaarmaak sodat die laag agter hulle nie doodgaan nie.

Gereelde vrae oor argitektuur en werk van VKontakte

Indien nodig, kan ons direk aan logs-collectors skryf.

Gereelde vrae oor argitektuur en werk van VKontakte

Maar om van kode direk na versamelaars te skryf, om stas-daemom te omseil, is 'n swak skaalbare oplossing omdat dit die las op die versamelaar verhoog. Die oplossing is slegs geskik as ons om een ​​of ander rede nie die memcache stats-daemon op die masjien kan verhoog nie, of dit het neergestort en ons het direk gegaan.

Vervolgens voeg logs-collectors statistieke saam meowDB - dit is ons databasis, wat ook statistieke kan stoor.

Gereelde vrae oor argitektuur en werk van VKontakte

Dan kan ons binêre "naby-SQL"-keuses uit die kode maak.

Gereelde vrae oor argitektuur en werk van VKontakte

eksperiment

In die somer van 2018 het ons 'n interne hackathon gehad, en die idee het ontstaan ​​om die rooi deel van die diagram te probeer vervang met iets wat metrieke in ClickHouse kan stoor. Ons het logs op ClickHouse - hoekom probeer dit nie?

Gereelde vrae oor argitektuur en werk van VKontakte

Ons het 'n skema gehad wat logs deur KittenHouse geskryf het.

Gereelde vrae oor argitektuur en werk van VKontakte

Ons het besluit voeg nog 'n "*Huis" by die diagram, wat presies die maatstawwe in die formaat sal ontvang soos ons kode dit via UDP skryf. Dan verander hierdie *Huis hulle in insetsels, soos stompe, wat KittenHouse verstaan. Hy kan hierdie logs perfek by ClickHouse aflewer, wat dit behoort te kan lees.

Gereelde vrae oor argitektuur en werk van VKontakte

Die skema met memcache, stats-daemon en logs-collectors databasis word met hierdie een vervang.

Gereelde vrae oor argitektuur en werk van VKontakte

Die skema met memcache, stats-daemon en logs-collectors databasis word met hierdie een vervang.

  • Daar is 'n versending van kode hier, wat plaaslik in StatsHouse geskryf is.
  • StatsHouse skryf UDP-statistieke, wat reeds in SQL-insetsels omgeskakel is, in bondels na KittenHouse.
  • KittenHouse stuur hulle na ClickHouse.
  • As ons dit wil lees, lees ons dit deur StatsHouse te omseil - direk vanaf ClickHouse deur gewone SQL te gebruik.

Is dit nog steeds 'n eksperiment, maar ons hou van hoe dit uitdraai. As ons die probleme met die skema regstel, sal ons miskien heeltemal daarna oorskakel. Persoonlik hoop ek so.

Die skema spaar nie yster nie. Minder bedieners is nodig, plaaslike statistiek-daemons en logboekversamelaars is nie nodig nie, maar ClickHouse benodig 'n groter bediener as dié in die huidige skema. Minder bedieners is nodig, maar hulle moet duurder en kragtiger wees.

Ontplooi

Kom ons kyk eers na die PHP-ontplooiing. Ons ontwikkel in git: gebruik GitLab и TeamCity vir ontplooiing. Ontwikkelingstakke word saamgesmelt in die meestertak, vanaf die meester vir toetsing word dit saamgevoeg in stadium, en vanaf stadium tot produksie.

Voor ontplooiing word die huidige produksietak en die vorige een geneem, en diff-lêers word daarin oorweeg - veranderinge: geskep, uitgevee, verander. Hierdie verandering word aangeteken in die binlog van 'n spesiale copyfast-enjin, wat vinnig veranderinge aan ons hele bedienervloot kan herhaal. Wat hier gebruik word, is nie direk kopiëring nie, maar skinder replikasie, wanneer een bediener veranderinge aan sy naaste bure stuur, dié na hul bure, ensovoorts. Dit laat jou toe om die kode in tientalle en eenhede van sekondes oor die hele vloot op te dateer. Wanneer die verandering die plaaslike replika bereik, pas dit hierdie kolle op sy plaaslike lêerstelsel. Terugrol word ook volgens dieselfde skema uitgevoer.

Ons ontplooi ook kPHP baie en dit het ook sy eie ontwikkeling aan git volgens die diagram hierbo. Sedert hierdie HTTP-bediener binêre, dan kan ons nie diff produseer nie - die vrystelling binêr weeg honderde MB. Daarom is daar 'n ander opsie hier - die weergawe word geskryf binlog copyfast. Met elke bou neem dit toe, en tydens terugrol neem dit ook toe. Weergawe na bedieners gerepliseer. Plaaslike copyfasts sien dat 'n nuwe weergawe die binlog betree het, en deur dieselfde skinderreplikasie neem hulle die nuutste weergawe van die binêre vir hulself, sonder om ons meesterbediener te moeg, maar versigtig die las oor die netwerk te versprei. Wat volg grasieuse herbekendstelling vir die nuwe weergawe.

Vir ons enjins, wat ook in wese binaries is, is die skema baie soortgelyk:

  • git meester tak;
  • binêre in deb;
  • die weergawe is geskryf na binlog copyfast;
  • na bedieners gerepliseer;
  • die bediener haal 'n vars .dep;
  • dpkg -i;
  • grasieuse herbekendstelling na nuwe weergawe.

Die verskil is dat ons binêre in argiewe verpak is deb, en wanneer hulle uitpomp dpkg -i word op die stelsel geplaas. Waarom word kPHP as 'n binêre ontplooi, en enjins word as dpkg ontplooi? Dit het so gebeur. Dit werk – moenie daaraan raak nie.

Nuttige skakels:

Alexey Akulovich is een van diegene wat as deel van die Programkomitee help PHP Rusland op 17 Mei sal die grootste geleentheid vir PHP-ontwikkelaars in onlangse tye word. Kyk wat 'n oulike rekenaar het ons, wat sprekers (twee van hulle is besig om PHP-kern te ontwikkel!) - lyk soos iets wat jy nie kan mis as jy PHP skryf nie.

Bron: will.com

Voeg 'n opmerking