Često postavljana pitanja o arhitekturi i radu VKontakte

Povijest stvaranja VKontaktea nalazi se na Wikipediji, ispričao ju je sam Pavel. Čini se da je već svi znaju. O unutrašnjosti, arhitekturi i strukturi stranice na HighLoad++ Pavel rekao mi je još 2010. Od tada je procurilo mnogo servera, pa ćemo ažurirati informacije: secirat ćemo ga, izvaditi unutrašnjost, izvagati i pogledati VK uređaj s tehničke strane.

Često postavljana pitanja o arhitekturi i radu VKontakte

Aleksej Akulovič (AterCattus) backend programer u VKontakte timu. Transkript ovog izvješća je skupni odgovor na često postavljana pitanja o radu platforme, infrastrukturi, poslužiteljima i interakciji između njih, ali ne i o razvoju, tj. o željezu. Odvojeno, o bazama podataka i onome što VK ima umjesto toga, o prikupljanju dnevnika i praćenju cijelog projekta u cjelini. Detalji ispod kroja.



Više od četiri godine bavim se svakakvim poslovima vezanim uz backend.

  • Prijenos, pohrana, obrada, distribucija medija: video, live streaming, audio, fotografije, dokumenti.
  • Infrastruktura, platforma, razvojni nadzor, dnevnici, regionalne predmemorije, CDN, vlasnički RPC protokol.
  • Integracija s vanjskim uslugama: push obavijesti, parsiranje vanjske veze, RSS feed.
  • Pomaganje kolegama s raznim pitanjima, čiji odgovori zahtijevaju ronjenje u nepoznati kod.

Tijekom tog vremena imao sam ruku u mnogim komponentama stranice. Želim podijeliti ovo iskustvo.

Opća arhitektura

Sve, kao i obično, počinje s poslužiteljem ili grupom poslužitelja koji prihvaćaju zahtjeve.

Prednji poslužitelj

Prednji poslužitelj prihvaća zahtjeve putem HTTPS-a, RTMP-a i WSS-a.

HTTPS - ovo su zahtjevi za glavnu i mobilnu web verziju stranice: vk.com i m.vk.com, te druge službene i neslužbene klijente našeg API-ja: mobilne klijente, messengere. Imamo recepciju RTMP-promet za prijenose uživo s odvojenim prednjim poslužiteljima i WSS- veze za Streaming API.

Za HTTPS i WSS na poslužiteljima vrijedi Nginx. Za RTMP emitiranje nedavno smo se prebacili na vlastito rješenje kive, ali to je izvan opsega izvješća. Za toleranciju grešaka, ovi poslužitelji reklamiraju zajedničke IP adrese i djeluju u grupama tako da se korisnički zahtjevi ne izgube ako postoji problem na jednom od poslužitelja. Za HTTPS i WSS, ti isti poslužitelji šifriraju promet kako bi preuzeli dio CPU opterećenja na sebe.

Nećemo dalje govoriti o WSS i RTMP, već samo o standardnim HTTPS zahtjevima, koji su obično povezani s web projektom.

Backend

Iza prednje strane obično se nalaze pozadinski poslužitelji. Oni obrađuju zahtjeve koje prednji poslužitelj prima od klijenata.

ovo kPHP poslužitelji, na kojem je pokrenut HTTP demon jer je HTTPS već dekriptiran. kPHP je poslužitelj koji radi na prefork modeli: pokreće glavni proces, hrpu podređenih procesa, prosljeđuje im slušajuće utičnice i oni obrađuju njihove zahtjeve. U ovom slučaju, procesi se ne pokreću ponovno između svakog zahtjeva korisnika, već jednostavno vraćaju svoje stanje na izvorno stanje nulte vrijednosti - zahtjev za zahtjevom, umjesto ponovnog pokretanja.

Raspodjela opterećenja

Sve naše pozadine nisu veliki skup strojeva koji mogu obraditi bilo koji zahtjev. Mi njih podijeljeni u posebne skupine: opći, mobilni, api, video, staging... Problem na zasebnoj grupi strojeva neće utjecati na sve ostale. U slučaju problema s videom, korisnik koji sluša glazbu neće ni znati za probleme. Kojoj pozadini poslati zahtjev odlučuje nginx na prednjoj strani prema konfiguraciji.

Prikupljanje metrike i rebalansiranje

Da bismo razumjeli koliko automobila trebamo imati u svakoj grupi, mi nemojte se oslanjati na QPS. Pozadine su različite, imaju različite zahtjeve, svaki zahtjev ima različitu složenost izračuna QPS-a. Zato mi operiramo s konceptom opterećenja poslužitelja u cjelini - na CPU i perf.

Imamo tisuće takvih poslužitelja. Svaki fizički poslužitelj pokreće kPHP grupu za recikliranje svih jezgri (jer je kPHP jednonit).

Poslužitelj sadržaja

CS ili Content Server je pohrana. CS je poslužitelj koji pohranjuje datoteke i također obrađuje učitane datoteke i sve vrste pozadinskih sinkronih zadataka koje mu dodjeljuje glavno web sučelje.

Imamo desetke tisuća fizičkih poslužitelja koji pohranjuju datoteke. Korisnici vole učitavati datoteke, a mi ih volimo pohranjivati ​​i dijeliti. Neki od tih poslužitelja zatvoreni su posebnim pu/pp poslužiteljima.

pu/pp

Ako ste otvorili karticu mreže u VK, vidjeli ste pu/pp.

Često postavljana pitanja o arhitekturi i radu VKontakte

Što je pu/pp? Ako zatvaramo jedan poslužitelj za drugim, tada postoje dvije opcije za učitavanje i preuzimanje datoteke na poslužitelj koji je zatvoren: direktno kroz http://cs100500.userapi.com/path ili preko posredničkog poslužitelja - http://pu.vk.com/c100500/path.

Pu je povijesni naziv za učitavanje fotografija, a pp je foto proxy. Odnosno, jedan poslužitelj služi za učitavanje fotografija, a drugi za učitavanje. Sada se ne učitavaju samo fotografije, već je i ime sačuvano.

Ovi poslužitelji prekinuti HTTPS sesijeza uklanjanje opterećenja procesora iz memorije. Također, budući da se korisničke datoteke obrađuju na ovim poslužiteljima, što je manje osjetljivih informacija pohranjeno na tim strojevima, to bolje. Na primjer, ključevi HTTPS enkripcije.

Budući da su strojevi zatvoreni od strane naših drugih strojeva, možemo si priuštiti da im ne damo "bijele" vanjske IP adrese i dati "sivo". Na ovaj smo način uštedjeli na skupu IP adresa i zajamčeno zaštitili strojeve od vanjskog pristupa - jednostavno nema IP adrese za pristup.

Otpornost preko zajedničkih IP adresa. Što se tiče tolerancije na pogreške, shema funkcionira isto – nekoliko fizičkih poslužitelja ima zajednički fizički IP, a hardver ispred njih bira gdje će poslati zahtjev. Kasnije ću govoriti o drugim opcijama.

Kontroverzna točka je da u ovom slučaju klijent zadržava manje veza. Ako postoji isti IP za nekoliko strojeva - s istim hostom: pu.vk.com ili pp.vk.com, preglednik klijenta ima ograničenje broja istodobnih zahtjeva prema jednom hostu. Ali u vrijeme sveprisutnog HTTP/2, vjerujem da to više nije toliko relevantno.

Očigledni nedostatak sheme je da mora pumpati sav promet, koji ide u pohranu, preko drugog poslužitelja. Budući da pumpamo promet kroz strojeve, još ne možemo pumpati gust promet, na primjer, video, koristeći istu shemu. Prenosimo ga izravno - zasebna izravna veza za odvojene pohrane posebno za video. Lakši sadržaj prenosimo preko proxyja.

Nedavno smo dobili poboljšanu verziju proxyja. Sada ću vam reći kako se razlikuju od običnih i zašto je to potrebno.

sunce

U rujnu 2017. Oracle, koji je prethodno kupio Sun, otpustio ogroman broj zaposlenika Sunca. Možemo reći da je u ovom trenutku tvrtka prestala postojati. Prilikom odabira imena za novi sustav, naši administratori odlučili su odati počast sjećanju na ovu tvrtku te su novi sustav nazvali Sunce. Među sobom je jednostavno zovemo “sunce”.

Često postavljana pitanja o arhitekturi i radu VKontakte

pp je imao nekoliko problema. Jedan IP po grupi - neučinkovita predmemorija. Nekoliko fizičkih poslužitelja dijeli zajedničku IP adresu i ne postoji način da se kontrolira kojem će poslužitelju zahtjev ići. Stoga, ako različiti korisnici dođu po istu datoteku, onda ako postoji predmemorija na tim poslužiteljima, datoteka završava u predmemorije svakog poslužitelja. Ovo je vrlo neučinkovita shema, ali ništa se nije moglo učiniti.

Posljedično - ne možemo dijeliti sadržaj, jer ne možemo odabrati određeni poslužitelj za ovu grupu - imaju zajednički IP. Također iz nekih unutarnjih razloga koje imamo nije bilo moguće instalirati takve poslužitelje u regijama. Stajali su samo u St.

Sa suncima smo promijenili sustav selekcije. Sada imamo anycast usmjeravanje: dinamičko usmjeravanje, anycast, demon za samoprovjeru. Svaki poslužitelj ima svoju individualnu IP adresu, ali zajedničku podmrežu. Sve je konfigurirano na takav način da ako jedan poslužitelj zakaže, promet se automatski raspoređuje na druge poslužitelje iste grupe. Sada je moguće odabrati određeni poslužitelj, nema suvišnog predmemoriranja, a pouzdanost nije utjecala.

Potpora težini. Sada si možemo priuštiti ugradnju strojeva različite snage prema potrebi, a također, u slučaju privremenih problema, promijeniti težinu radnih „sunaca“ kako bismo ih smanjili opterećenje, tako da se „odmore“ i ponovno počnu raditi.

Sharding prema ID-u sadržaja. Smiješna stvar o dijeljenju: obično dijelimo sadržaj tako da različiti korisnici idu na istu datoteku kroz isti "sun" tako da imaju zajedničku predmemoriju.

Nedavno smo pokrenuli aplikaciju “Djetelina”. Ovo je online kviz u prijenosu uživo, gdje voditelj postavlja pitanja, a korisnici odgovaraju u stvarnom vremenu, birajući opcije. Aplikacija ima chat gdje korisnici mogu razgovarati. Može se istovremeno spojiti na emitiranje više od 100 tisuća ljudi. Svi pišu poruke koje se šalju svim sudionicima, a uz poruku dolazi i avatar. Ako dođe 100 tisuća ljudi po jedan avatar u jednom “suncu”, onda se to ponekad zna otkotrljati iza oblaka.

Kako bismo izdržali rafalne zahtjeve za istom datotekom, za određenu vrstu sadržaja uključujemo glupu shemu koja širi datoteke po svim dostupnim “suncu” u regiji.

Sunce iznutra

Obrnuti proxy na nginxu, predmemorija u RAM-u ili na brzim Optane/NVMe diskovima. Primjer: http://sun4-2.userapi.com/c100500/path — poveznica na "sunce", koje se nalazi u četvrtoj regiji, druga grupa poslužitelja. Zatvara datoteku staze, koja fizički leži na poslužitelju 100500.

Cache

Dodajemo još jedan čvor našoj arhitektonskoj shemi - okruženje za predmemoriju.

Često postavljana pitanja o arhitekturi i radu VKontakte

Ispod je dijagram izgleda regionalne predmemorije, ima ih 20-ak. To su mjesta gdje se nalaze cache-ovi i "sunca", koji mogu cache-ovati promet kroz sebe.

Često postavljana pitanja o arhitekturi i radu VKontakte

Ovo je predmemorija multimedijskog sadržaja; ovdje se ne pohranjuju korisnički podaci - samo glazba, video, fotografije.

Da bismo odredili regiju korisnika, mi prikupljamo BGP mrežne prefikse najavljene u regijama. U slučaju zamjene, također moramo analizirati geoip bazu podataka ako ne možemo pronaći IP prema prefiksima. Regiju određujemo prema IP-u korisnika. U kodu možemo promatrati jednu ili više regija korisnika – onih točaka kojima je geografski najbliži.

Kako se to radi?

Brojimo popularnost datoteka po regijama. Postoji broj regionalne predmemorije u kojoj se nalazi korisnik i identifikator datoteke - uzimamo ovaj par i povećavamo ocjenu sa svakim preuzimanjem.

Istodobno, demoni - usluge u regijama - s vremena na vrijeme dolaze do API-ja i kažu: “Ja sam taj i takav keš, dajte mi popis najpopularnijih datoteka u mojoj regiji koje još nisu na meni. ” API isporučuje hrpu datoteka razvrstanih po ocjeni, demon ih preuzima, odvodi u regije i otuda isporučuje datoteke. Ovo je temeljna razlika između pu/pp i Sun-a od predmemorije: oni daju datoteku kroz sebe odmah, čak i ako ta datoteka nije u predmemorij, a predmemorija prvo preuzima datoteku u sebe, a zatim je počinje vraćati.

U ovom slučaju dobivamo sadržaj približiti korisnicima i raspoređivanje mrežnog opterećenja. Na primjer, samo iz moskovske predmemorije distribuiramo više od 1 Tbit/s tijekom vršnih sati.

Ali postoje problemi - cache poslužitelji nisu gumeni. Za super popularan sadržaj ponekad nema dovoljno mreže za zasebni poslužitelj. Naši cache serveri su 40-50 Gbit/s, ali ima sadržaja koji potpuno začepe takav kanal. Idemo prema implementaciji pohrane više od jedne kopije popularnih datoteka u regiji. Nadam se da ćemo to realizirati do kraja godine.

Pogledali smo opću arhitekturu.

  • Prednji poslužitelji koji prihvaćaju zahtjeve.
  • Pozadine koje obrađuju zahtjeve.
  • Skladišta koja su zatvorena s dvije vrste proxyja.
  • Regionalna spremišta.

Što nedostaje ovom dijagramu? Naravno, baze podataka u kojima pohranjujemo podatke.

Baze podataka ili motori

Ne zovemo ih bazama podataka, već motorima - Motorima, jer baze podataka u općeprihvaćenom smislu praktički nemamo.

Često postavljana pitanja o arhitekturi i radu VKontakte

Ovo je nužna mjera. To se dogodilo jer je 2008.-2009., kada je VK imao eksplozivan rast popularnosti, projekt u potpunosti radio na MySQL i Memcache i bilo je problema. MySQL se volio rušiti i kvariti datoteke, nakon čega se nije mogao oporaviti, a performanse Memcachea postupno su padale i morao se ponovno pokrenuti.

Ispostavilo se da je sve popularniji projekt imao stalnu pohranu, koja kvari podatke, i predmemoriju, koja usporava. U takvim uvjetima teško je razvijati projekt koji raste. Odlučeno je pokušati prepisati kritične stvari na koje je projekt bio fokusiran na vlastitim biciklima.

Rješenje je bilo uspješno. Postojala je prilika za to, ali i krajnja potreba, jer drugi načini skaliranja u to vrijeme nisu postojali. Nije bilo gomile baza podataka, NoSQL još nije postojao, postojali su samo MySQL, Memcache, PostrgreSQL - i to je to.

Univerzalni rad. Razvoj je vodio naš tim C programera i sve je urađeno na dosljedan način. Bez obzira na motor, svi su imali približno isti format datoteke zapisane na disk, iste parametre pokretanja, obrađene signale na isti način i ponašali su se približno jednako u slučaju rubnih situacija i problema. S rastom motora, administratorima je zgodno upravljati sustavom - nema zoološkog vrta koji treba održavati i moraju iznova učiti kako upravljati svakom novom bazom podataka treće strane, što je omogućilo brzo i zgodno povećati njihov broj.

Vrste motora

Tim je napisao dosta motora. Evo samo nekih od njih: prijatelj, savjeti, slika, ipdb, slova, liste, zapisi, memcached, meowdb, vijesti, nostradamus, fotografije, playliste, pmemcached, sandbox, pretraživanje, pohrana, lajkovi, zadaci, …

Za svaki zadatak koji zahtijeva određenu strukturu podataka ili obrađuje netipične zahtjeve, C tim piše novi motor. Zašto ne.

Imamo zaseban motor Memcached, koji je sličan običnom, ali s hrpom dobrih stvari i koji ne usporava. Nije ClickHouse, ali također radi. Dostupno zasebno pmemcached - Je uporni memcached, koji također može pohraniti podatke na disk, štoviše, nego što se uklapa u RAM, kako ne bi izgubio podatke prilikom ponovnog pokretanja. Postoje različiti motori za pojedinačne zadatke: redovi čekanja, liste, setovi - sve što naš projekt zahtijeva.

Grozdovi

Iz perspektive koda, nema potrebe razmišljati o motorima ili bazama podataka kao o procesima, entitetima ili instancama. Kod radi posebno s klasterima, s grupama motora - jedna vrsta po klasteru. Recimo da postoji memcached klaster - to je samo grupa strojeva.

Kod uopće ne mora znati fizičku lokaciju, veličinu ili broj poslužitelja. On odlazi u klaster koristeći određeni identifikator.

Da bi ovo radilo, trebate dodati još jedan entitet koji se nalazi između koda i motora - proxy.

RPC proxy

Proxy spojni autobus, na kojem radi gotovo cijela stranica. U isto vrijeme imamo nema otkrivanja usluge — umjesto toga, postoji konfiguracija za ovaj proxy, koja zna lokaciju svih klastera i svih fragmenata ovog klastera. To rade administratori.

Programere uopće ne zanima koliko, gdje i koliko košta - oni samo idu u klaster. To nam omogućuje puno. Kada primi zahtjev, proxy preusmjerava zahtjev, znajući gdje - to sam određuje.

Često postavljana pitanja o arhitekturi i radu VKontakte

U ovom slučaju, proxy je točka zaštite od kvara usluge. Ako neki motor uspori ili se sruši, tada proxy to razumije i u skladu s tim odgovara strani klijenta. To vam omogućuje uklanjanje vremenskog ograničenja - kod ne čeka da motor odgovori, već razumije da ne radi i mora se ponašati nekako drugačije. Kod mora biti pripremljen za činjenicu da baze podataka ne rade uvijek.

Specifične implementacije

Ponekad još uvijek stvarno želimo imati nekakvo nestandardno rješenje kao motor. U isto vrijeme, odlučeno je da se ne koristi naš gotov rpc-proxy, kreiran posebno za naše motore, već da se napravi zaseban proxy za zadatak.

Za MySQL, koji još imamo tu i tamo, koristimo db-proxy, a za ClickHouse - Kuća za mačiće.

Općenito radi ovako. Postoji određeni poslužitelj, pokreće kPHP, Go, Python - općenito, bilo koji kod koji može koristiti naš RPC protokol. Kod se izvodi lokalno na RPC proxyju - svaki poslužitelj na kojem se nalazi kod pokreće vlastiti lokalni proxy. Na zahtjev, proxy razumije kamo treba ići.

Često postavljana pitanja o arhitekturi i radu VKontakte

Ako jedan motor želi ići na drugi, čak i ako je susjed, ide preko proxyja, jer susjed može biti u drugom podatkovnom centru. Motor se ne bi trebao oslanjati na poznavanje lokacije bilo čega drugog osim samog sebe - ovo je naše standardno rješenje. Ali naravno ima izuzetaka :)

Primjer TL-sheme prema kojoj rade svi motori.

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;

Ovo je binarni protokol, čiji je najbliži analog protobuf. Shema unaprijed propisuje opcijska polja, složene tipove - proširenja ugrađenih skalara i upite. Sve radi po ovom protokolu.

RPC preko TL preko TCP/UDP… UDP?

Imamo RPC protokol za izvršavanje zahtjeva motora koji radi povrh TL sheme. Sve ovo radi preko TCP/UDP veze. TCP je razumljiv, ali zašto nam često treba UDP?

UDP pomaže izbjeći problem velikog broja veza između poslužitelja. Ako svaki poslužitelj ima RPC proxy i, općenito, može ići na bilo koji mehanizam, tada postoje deseci tisuća TCP veza po poslužitelju. Ima tereta, ali je beskoristan. U slučaju UDP-a ovaj problem ne postoji.

Nema suvišnog TCP rukovanja. Ovo je tipičan problem: kada se pokrene novi mehanizam ili novi poslužitelj, mnoge TCP veze se uspostavljaju odjednom. Za male lagane zahtjeve, na primjer, UDP korisni teret, sva komunikacija između koda i motora je dva UDP paketa: jedan leti u jednom smjeru, drugi u drugom. Jedno povratno putovanje - i kod je dobio odgovor od motora bez rukovanja.

Da, sve jednostavno radi s vrlo malim postotkom gubitka paketa. Protokol ima podršku za ponovni prijenos i timeout, ali ako izgubimo puno, dobit ćemo gotovo TCP, što nije dobro. Ne vozimo UDP preko oceana.

Imamo tisuće takvih poslužitelja, a shema je ista: na svaki fizički poslužitelj instaliran je paket motora. Uglavnom su jednonitni kako bi radili što je brže moguće bez blokiranja i podijeljeni su kao jednonitna rješenja. U isto vrijeme, nemamo ništa pouzdanije od ovih motora, a puno se pažnje posvećuje trajnoj pohrani podataka.

Trajna pohrana podataka

Motori pišu binlogove. Binlog je datoteka na kraj koje se dodaje događaj za promjenu stanja ili podataka. U različitim rješenjima naziva se drugačije: binarni dnevnik, WAL, AOF, ali princip je isti.

Kako bi spriječili da motor godinama ponovno čita cijeli binlog prilikom ponovnog pokretanja, motori pišu snimke - trenutno stanje. Ako je potrebno, prvo čitaju iz njega, a zatim završavaju čitanje iz binloga. Svi binlogi su napisani u istom binarnom formatu - prema TL shemi, tako da ih administratori mogu ravnopravno administrirati koristeći svoje alate. Nema takve potrebe za snimkama. Postoji opće zaglavlje koje pokazuje čija je snimka int, magija motora i koje tijelo nikome nije važno. Ovo je problem s motorom koji je snimio snimku.

Na brzinu ću opisati princip rada. Postoji server na kojem radi motor. Otvara novi prazan binlog za pisanje i u njega upisuje događaj za promjenu.

Često postavljana pitanja o arhitekturi i radu VKontakte

U nekom trenutku ili sam odluči snimiti snimku ili primi signal. Poslužitelj stvara novu datoteku, zapisuje cijelo stanje u nju, dodaje trenutnu veličinu binloga - pomak - na kraj datoteke i nastavlja pisati dalje. Novi binlog se ne stvara.

Često postavljana pitanja o arhitekturi i radu VKontakte

U nekom trenutku, kada se motor ponovno pokrene, na disku će biti i binlog i snimka. Motor čita cijelu snimku i podiže svoje stanje u određenom trenutku.

Često postavljana pitanja o arhitekturi i radu VKontakte

Čita poziciju koja je bila u vrijeme kada je snimka stvorena i veličinu binloga.

Često postavljana pitanja o arhitekturi i radu VKontakte

Čita kraj binloga kako bi dobio trenutno stanje i nastavlja pisati daljnje događaje. Ovo je jednostavna shema, svi naši motori rade po njoj.

Replikacija podataka

Kao rezultat toga, replikacija podataka u našem temeljen na izjavama — upisujemo u binlog ne bilo kakve promjene stranice, već naime zahtjevi za promjenama. Vrlo slično onome što dolazi preko mreže, samo malo modificirano.

Ista se shema koristi ne samo za replikaciju, već i za stvaranje sigurnosnih kopija. Imamo motor - majstor pisanja koji piše u binlog. Na bilo kojem drugom mjestu gdje ga administratori postave, ovaj binlog se kopira i to je to - imamo rezervnu kopiju.

Često postavljana pitanja o arhitekturi i radu VKontakte

Ako je potrebno čitanje replikeKako bi se smanjilo opterećenje CPU-a za čitanje, jednostavno se pokreće mehanizam za čitanje, koji čita kraj binloga i izvršava te naredbe lokalno.

Zaostatak je ovdje vrlo mali, a moguće je saznati koliko replika zaostaje za majstorom.

Dijeljenje podataka u RPC proxyju

Kako funkcionira dijeljenje? Kako proxy razumije kojem klasteru treba poslati? Kod ne kaže: "Pošalji po 15 krhotina!" - ne, to radi opunomoćenik.

Najjednostavnija shema je firstint — prvi broj u zahtjevu.

get(photo100_500) => 100 % N.

Ovo je primjer za jednostavan memcached tekstualni protokol, ali, naravno, upiti mogu biti složeni i strukturirani. Primjer uzima prvi broj u upitu i ostatak kada se podijeli s veličinom klastera.

Ovo je korisno kada želimo imati lokalitet podataka jednog entiteta. Recimo da je 100 ID korisnika ili grupe i želimo da svi podaci jednog entiteta budu na jednom shardu za složene upite.

Ako nas nije briga kako su zahtjevi raspoređeni po klasteru, postoji još jedna opcija - raspršivanje cijelog šarda.

hash(photo100_500) => 3539886280 % N

Dobivamo i hash, ostatak dijeljenja i broj komada.

Obje ove opcije funkcioniraju samo ako smo spremni na činjenicu da ćemo, kada povećamo veličinu klastera, podijeliti ili povećati višestruko. Na primjer, imali smo 16 krhotina, nemamo dovoljno, želimo više - možemo sigurno dobiti 32 ​​bez zastoja. Ako želimo povećati ne višestruko, bit će zastoja, jer nećemo moći sve točno podijeliti bez gubitaka. Ove opcije su korisne, ali ne uvijek.

Ako trebamo dodati ili ukloniti proizvoljan broj poslužitelja, koristimo Dosljedno haširanje na prstenu a la Ketama. Ali u isto vrijeme, potpuno gubimo lokalitet podataka; moramo spojiti zahtjev prema klasteru tako da svaki dio vrati vlastiti mali odgovor, a zatim spojiti odgovore proxyju.

Postoje superspecifični zahtjevi. To izgleda ovako: RPC proxy prima zahtjev, određuje u koji će klaster ići i određuje shard. Zatim postoje ili masteri za pisanje ili, ako klaster ima podršku za replike, šalje replici na zahtjev. Sve to radi proxy.

Često postavljana pitanja o arhitekturi i radu VKontakte

Dnevnici

Dnevnike pišemo na nekoliko načina. Najočitiji i najjednostavniji je pisati zapise u memcache.

ring-buffer: prefix.idx = line

Postoji prefiks ključa - naziv dnevnika, linija, i postoji veličina ovog dnevnika - broj redaka. Uzimamo slučajni broj od 0 do broja redaka minus 1. Ključ u memcacheu je prefiks spojen s ovim slučajnim brojem. Spremamo redak dnevnika i trenutno vrijeme u vrijednost.

Kada je potrebno očitavanje dnevnika, vršimo Multi Get sve ključeve, sortirane po vremenu, i tako dobiti proizvodni dnevnik u stvarnom vremenu. Shema se koristi kada trebate otkloniti pogreške u nečemu u proizvodnji u stvarnom vremenu, a da ništa ne pokvarite, bez zaustavljanja ili dopuštanja prometa drugim strojevima, ali ovaj dnevnik ne traje dugo.

Za pouzdano skladištenje trupaca imamo motor trupci-motor. Upravo zbog toga je stvoren, i široko se koristi u ogromnom broju klastera. Najveći klaster za koji znam pohranjuje 600 TB zapakiranih zapisa.

Motor je jako star, ima klastera starih već 6-7 godina. Postoje problemi s njim koje pokušavamo riješiti, na primjer, počeli smo aktivno koristiti ClickHouse za pohranu zapisa.

Prikupljanje logova u ClickHouseu

Ovaj dijagram pokazuje kako ulazimo u naše motore.

Često postavljana pitanja o arhitekturi i radu VKontakte

Postoji kod koji ide lokalno preko RPC-a do RPC-proxyja i on razumije gdje treba ići do stroja. Ako želimo pisati logove u ClickHouse, moramo promijeniti dva dijela u ovoj shemi:

  • zamijenite neki motor s ClickHouseom;
  • zamijenite RPC proxy, koji ne može pristupiti ClickHouseu, nekim rješenjem koje može, i to putem RPC-a.

Motor je jednostavan - zamjenjujemo ga serverom ili klasterom servera s ClickHouseom.

I otišli smo u ClickHouse KittenHouse. Ako odemo izravno iz KittenHousea u ClickHouse, neće se nositi. Čak i bez zahtjeva, zbraja se iz HTTP veza ogromnog broja strojeva. Da bi shema radila, na poslužitelju s ClickHousom podignut je lokalni obrnuti proxy, koji je napisan na takav način da može izdržati potrebne količine veza. Također može relativno pouzdano čuvati podatke unutar sebe.

Često postavljana pitanja o arhitekturi i radu VKontakte

Ponekad ne želimo implementirati RPC shemu u nestandardna rješenja, na primjer, u nginx. Stoga KittenHouse ima mogućnost primanja zapisa putem UDP-a.

Često postavljana pitanja o arhitekturi i radu VKontakte

Ako pošiljatelj i primatelj zapisa rade na istom stroju, tada je vjerojatnost gubitka UDP paketa unutar lokalnog glavnog računala prilično mala. Kao kompromis između potrebe za implementacijom RPC-a u rješenju treće strane i pouzdanosti, jednostavno koristimo UDP slanje. Kasnije ćemo se vratiti na ovu shemu.

nadgledanje

Imamo dvije vrste zapisa: one koje prikupljaju administratori na svojim poslužiteljima i one koje pišu programeri iz koda. Odgovaraju dvjema vrstama metrike: sustav i proizvod.

Sustavna metrika

Radi na svim našim serverima netdata, koji prikuplja statistiku i šalje je na Grafitni ugljik. Stoga se kao sustav za pohranu koristi ClickHouse, a ne npr. Whisper. Ako je potrebno, možete izravno čitati iz ClickHousea ili koristiti grafana za metriku, grafikone i izvješća. Kao programeri imamo dovoljno pristupa Netdati i Grafani.

Mjerni podaci proizvoda

Radi praktičnosti, napisali smo puno stvari. Na primjer, postoji skup običnih funkcija koje vam omogućuju pisanje vrijednosti Counts, UniqueCounts u statistiku, koje se šalju negdje dalje.

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

$stats = statlogsStatData($params)

Nakon toga možemo koristiti filtre za sortiranje i grupiranje i raditi sve što želimo od statistike - graditi grafikone, konfigurirati Watchdoge.

Pišemo vrlo mnoge metrike broj događaja je od 600 milijardi do 1 bilijun dnevno. Međutim, mi ih želimo zadržati barem par godinarazumjeti trendove u metrici. Sve to skupa je veliki problem koji još nismo riješili. Reći ću vam kako je to funkcioniralo zadnjih nekoliko godina.

Imamo funkcije koje pišu ove metrike u lokalni memcachekako biste smanjili broj unosa. Jednom u kratkom vremenskom razdoblju lokalno lansiran stats-daemon prikuplja sve zapise. Zatim, demon spaja metriku u dva sloja poslužitelja sakupljači trupaca, koji skuplja statistike iz hrpe naših strojeva tako da sloj iza njih ne umre.

Često postavljana pitanja o arhitekturi i radu VKontakte

Ako je potrebno, možemo pisati izravno sakupljačima zapisa.

Često postavljana pitanja o arhitekturi i radu VKontakte

Ali pisanje iz koda izravno u kolektore, zaobilazeći stas-daemom, slabo je skalabilno rješenje jer povećava opterećenje kolektora. Rješenje je prikladno samo ako iz nekog razloga ne možemo pokrenuti memcache stats-daemon na stroju ili se srušio pa smo otišli izravno.

Zatim, sakupljači zapisa spajaju statistiku u mijauDB - ovo je naša baza podataka, koja također može pohraniti metriku.

Često postavljana pitanja o arhitekturi i radu VKontakte

Tada možemo napraviti binarne "near-SQL" odabire iz koda.

Često postavljana pitanja o arhitekturi i radu VKontakte

Eksperiment

U ljeto 2018. imali smo interni hackathon i došla je ideja da crveni dio dijagrama pokušamo zamijeniti nečim što bi moglo pohranjivati ​​metrike u ClickHouse. Imamo zapisnike na ClickHouseu - zašto ne isprobati?

Često postavljana pitanja o arhitekturi i radu VKontakte

Imali smo shemu koja je pisala dnevnike kroz KittenHouse.

Često postavljana pitanja o arhitekturi i radu VKontakte

Odlučili smo dodajte još jednu “*Kuću” na dijagram, koji će primiti točno metriku u formatu u kojem ih naš kod zapisuje putem UDP-a. Zatim ih ova *Kuća pretvara u umetke, poput balvana, što KittenHouse razumije. On savršeno može dostaviti te zapise ClickHouseu, koji bi ih trebao moći pročitati.

Često postavljana pitanja o arhitekturi i radu VKontakte

Shema s bazom podataka memcache, stats-daemon i logs-collectors zamijenjena je ovom.

Često postavljana pitanja o arhitekturi i radu VKontakte

Shema s bazom podataka memcache, stats-daemon i logs-collectors zamijenjena je ovom.

  • Ovdje je otprema koda, koji je napisan lokalno u StatsHouse.
  • StatsHouse zapisuje UDP metriku, već pretvorenu u SQL umetke, u KittenHouse u serijama.
  • KittenHouse ih šalje u ClickHouse.
  • Ako ih želimo čitati, onda ih čitamo zaobilazeći StatsHouse - izravno iz ClickHousea koristeći obični SQL.

Je li još uvijek eksperiment, ali sviđa nam se kako je ispalo. Ako riješimo probleme sa shemom, možda ćemo se potpuno prebaciti na nju. Osobno se nadam.

Shema ne štedi željezo. Potrebno je manje poslužitelja, nisu potrebni lokalni stats-daemoni i log-collectors, ali ClickHouse zahtijeva veći poslužitelj od onih u trenutnoj shemi. Potrebno je manje poslužitelja, ali moraju biti skuplji i moćniji.

Rasporedi

Prvo, pogledajmo implementaciju PHP-a. Razvijamo se u git: koristiti GitLab и TeamCity za raspoređivanje. Razvojne grane spajaju se u master granu, iz mastera za testiranje spajaju se u staging, a iz staginga u proizvodnju.

Prije postavljanja uzimaju se trenutna proizvodna grana i prethodna, te se u njima razmatraju diff datoteke - promjene: kreirane, obrisane, promijenjene. Ova se promjena bilježi u binlogu posebnog copyfast motora, koji može brzo replicirati promjene na cijelu našu flotu poslužitelja. Ono što se ovdje koristi nije izravno kopiranje, već trač replikacija, kada jedan poslužitelj šalje promjene svojim najbližim susjedima, oni svojim susjedima, i tako dalje. To vam omogućuje ažuriranje koda u desecima i jedinicama sekundi u cijeloj floti. Kada promjena dođe do lokalne replike, ona primjenjuje ove zakrpe na svoju lokalni datotečni sustav. Povratak se također provodi prema istoj shemi.

Također često implementiramo kPHP i on također ima vlastiti razvoj git prema gornjem dijagramu. Od ovoga Binarni HTTP poslužitelj, tada ne možemo proizvesti diff - binarna datoteka izdanja teži stotine MB. Stoga, ovdje postoji još jedna opcija - verzija je napisana binlog copyfast. Sa svakom gradnjom se povećava, a tijekom vraćanja također se povećava. Verzija replicirano na poslužitelje. Lokalni copyfasti vide da je nova verzija ušla u binlog, i istom trač replikacijom preuzimaju najnoviju verziju binarne datoteke za sebe, ne zamarajući naš glavni poslužitelj, već pažljivo raspoređujući opterećenje po mreži. Što slijedi graciozno ponovno pokretanje za novu verziju.

Za naše motore, koji su također u biti binarni, shema je vrlo slična:

  • git master grana;
  • binarni in debitant;
  • verzija je napisana u binlog copyfast;
  • replicirano na poslužitelje;
  • poslužitelj izvlači novi .dep;
  • dpkg -i;
  • graciozno ponovno pokretanje na novu verziju.

Razlika je u tome što je naša binarna datoteka zapakirana u arhive debitant, a kod ispumpavanja oni dpkg -i postavljaju se na sustav. Zašto je kPHP raspoređen kao binarni, a motori su raspoređeni kao dpkg? Dogodilo se tako. Djeluje - ne diraj ga.

Korisni linkovi:

Alexey Akulovich je jedan od onih koji, kao dio Programskog odbora, pomaže PHP Rusija 17. svibnja postat će najveći događaj za PHP programere u posljednje vrijeme. Pogledajte kakav cool PC imamo, što zvučnici (dva od njih razvijaju PHP jezgru!) - čini se kao nešto što ne možete propustiti ako pišete PHP.

Izvor: www.habr.com

Dodajte komentar