UKK VKontakten arkkitehtuurista ja työstä

VKontakten luomisen historia on Wikipediassa, sen kertoi Pavel itse. Näyttää siltä, ​​​​että kaikki tuntevat hänet jo. Tietoja sivuston sisäosista, arkkitehtuurista ja rakenteesta HighLoad++ Pavelissa kertoi minulle jo vuonna 2010. Sen jälkeen monet palvelimet ovat vuotaneet, joten päivitämme tiedot: puretaan, irrotetaan sisäosat, punnitaan ja katsotaan VK-laitetta teknisestä näkökulmasta.

UKK VKontakten arkkitehtuurista ja työstä

Aleksei Akulovitš (AterCattus) taustakehittäjä VKontakte-tiimissä. Tämän raportin transkriptio on kollektiivinen vastaus usein kysyttyihin kysymyksiin alustan toiminnasta, infrastruktuurista, palvelimista ja niiden välisestä vuorovaikutuksesta, mutta ei kehityksestä, nimittäin raudasta. Erikseen tietokannoista ja siitä, mitä VK:lla sen sijaan on, lokien keräämisestä ja koko projektin seurannasta kokonaisuutena. Yksityiskohdat leikkauksen alla.



Yli neljän vuoden ajan olen hoitanut kaikenlaisia ​​taustajärjestelmään liittyviä tehtäviä.

  • Median lataaminen, tallennus, käsittely, jakelu: video, suoratoisto, ääni, valokuvat, asiakirjat.
  • Infrastruktuuri, alusta, kehittäjien valvonta, lokit, alueelliset välimuistit, CDN, oma RPC-protokolla.
  • Integrointi ulkoisiin palveluihin: push-ilmoitukset, ulkoisten linkkien jäsennys, RSS-syöte.
  • Kollegoiden auttaminen erilaisissa kysymyksissä, joiden vastaukset vaativat sukellusta tuntemattomaan koodiin.

Tänä aikana minulla oli käsissäni monia sivuston osia. Haluan jakaa tämän kokemuksen.

Yleinen arkkitehtuuri

Kaikki, kuten tavallista, alkaa palvelimesta tai palvelinryhmästä, joka hyväksyy pyynnöt.

Etupalvelin

Etupalvelin hyväksyy pyynnöt HTTPS:n, RTMP:n ja WSS:n kautta.

HTTPS - Nämä ovat pyyntöjä sivuston pää- ja mobiiliverkkoversioille: vk.com ja m.vk.com sekä muille API:mme virallisille ja epävirallisille asiakkaille: mobiiliasiakkaille, lähettiläille. Meillä on vastaanotto RTMP-liikennettä suorille lähetyksille erillisillä etupalvelimilla ja WSS- yhteydet Streaming API:lle.

Palvelimien HTTPS:lle ja WSS:lle se kannattaa Nginx. RTMP-lähetysten osalta siirryimme äskettäin omaan ratkaisuumme kive, mutta se ei kuulu raportin soveltamisalaan. Vikasietoisuuden vuoksi nämä palvelimet mainostavat yhteisiä IP-osoitteita ja toimivat ryhmissä, jotta käyttäjien pyynnöt eivät katoa, jos jollakin palvelimista ilmenee ongelma. HTTPS:ssä ja WSS:ssä nämä samat palvelimet salaavat liikenteen ottaakseen osan suorittimen kuormituksesta itselleen.

Emme puhu enempää WSS:stä ja RTMP:stä, vaan vain tavallisista HTTPS-pyynnöistä, jotka yleensä liittyvät verkkoprojektiin.

taustaosa

Etuosan takana on yleensä taustapalvelimet. He käsittelevät pyynnöt, jotka etupalvelin vastaanottaa asiakkailta.

Se kPHP-palvelimet, jossa HTTP-demoni on käynnissä, koska HTTPS:n salaus on jo purettu. kPHP on palvelin, joka toimii prefork mallit: käynnistää pääprosessin, joukko lapsiprosesseja, välittää heille kuunteluliitännät ja he käsittelevät heidän pyyntönsä. Tässä tapauksessa prosesseja ei käynnistetä uudelleen jokaisen käyttäjän pyynnön välillä, vaan niiden tila yksinkertaisesti palautetaan alkuperäiseen nolla-arvoon - pyyntö pyynnön jälkeen uudelleenkäynnistyksen sijaan.

Kuorman jakautuminen

Kaikki taustajärjestelmämme eivät ole suuri joukko koneita, jotka pystyvät käsittelemään minkä tahansa pyynnön. Me heidät jaettu erillisiin ryhmiin: yleinen, mobiili, api, video, lavastus... Erillisen koneryhmän ongelma ei vaikuta kaikkiin muihin. Jos videon kanssa on ongelmia, musiikkia kuunteleva käyttäjä ei edes tiedä ongelmista. Mihin taustajärjestelmään pyyntö lähetetään, päättää nginx etupuolella konfiguraation mukaan.

Mittareiden kerääminen ja tasapainottaminen

Ymmärtääksemme kuinka monta autoa meillä on kussakin ryhmässä, me älä luota QPS:ään. Taustaohjelmat ovat erilaisia, niillä on erilaiset pyynnöt, jokaisella pyynnöllä on erilainen QPS-laskennan monimutkaisuus. Siksi me Toimimme palvelimen kuormituksen käsitteellä kokonaisuutena - CPU:ssa ja perf.

Meillä on tuhansia tällaisia ​​palvelimia. Jokainen fyysinen palvelin käyttää kPHP-ryhmää kaikkien ytimien kierrättämiseksi (koska kPHP on yksisäikeinen).

Sisältöpalvelin

CS tai sisältöpalvelin on tallennustila. CS on palvelin, joka tallentaa tiedostoja ja käsittelee myös ladattuja tiedostoja ja kaikenlaisia ​​taustasynkronisia tehtäviä, jotka pääverkkokäyttöliittymä määrittää sille.

Meillä on kymmeniä tuhansia fyysisiä palvelimia, jotka tallentavat tiedostoja. Käyttäjät rakastavat tiedostojen lataamista, ja me rakastamme niiden tallentamista ja jakamista. Jotkut näistä palvelimista on suljettu erityisillä pu/pp-palvelimilla.

pu/pp

Jos avasit verkkovälilehden VK:ssa, näit pu/pp.

UKK VKontakten arkkitehtuurista ja työstä

Mikä on pu/pp? Jos suljemme palvelimet toisensa jälkeen, on kaksi vaihtoehtoa tiedoston lataamiseen ja lataamiseen suljetulle palvelimelle: suoraan kautta http://cs100500.userapi.com/path tai välipalvelimen kautta - http://pu.vk.com/c100500/path.

Pu on valokuvalatauksen historiallinen nimi, ja pp on valokuvan välityspalvelin. Toisin sanoen yksi palvelin on kuvien ja toinen kuvien lataamiseen. Nyt ei vain kuvia ladata, vaan nimi on säilytetty.

Nämä palvelimet lopettaa HTTPS-istunnotprosessorin kuormituksen poistamiseksi tallennustilasta. Lisäksi, koska käyttäjätiedostoja käsitellään näillä palvelimilla, mitä vähemmän arkaluonteisia tietoja näille koneille tallennetaan, sitä parempi. Esimerkiksi HTTPS-salausavaimet.

Koska muut koneemme ovat sulkeneet koneet, meillä on varaa olla antamatta niille "valkoisia" ulkoisia IP-osoitteita, ja anna "harmaa". Näin säästimme IP-poolissa ja taatusimme suojaamme koneet ulkopuoliselta pääsyltä - siihen ei yksinkertaisesti ole IP-osoitetta.

Jaettujen IP-osoitteiden sietokyky. Vikasietokyvyn suhteen malli toimii samalla tavalla - useilla fyysisillä palvelimilla on yhteinen fyysinen IP, ja niiden edessä oleva laitteisto valitsee, minne pyyntö lähetetään. Kerron muista vaihtoehdoista myöhemmin.

Kiistanalainen kohta on, että tässä tapauksessa asiakas säilyttää vähemmän yhteyksiä. Jos usealla koneella on sama IP-osoite - samalla isännällä: pu.vk.com tai pp.vk.com, asiakasselaimella on raja samaan aikaan yhdelle isännälle lähetettävien pyyntöjen määrälle. Mutta arjen HTTP/2:n aikana uskon, että tämä ei ole enää niin relevanttia.

Järjestelmän ilmeinen haittapuoli on, että sen on pakko pumppaa kaiken liikenteen, joka menee tallennustilaan toisen palvelimen kautta. Koska pumppaamme liikennettä koneiden kautta, emme voi vielä pumpata raskasta liikennettä, esimerkiksi videota, samalla kaavalla. Välitämme sen suoraan - erillinen suora yhteys erillisille tallennustiloille erityisesti videota varten. Välitämme kevyempää sisältöä välityspalvelimen kautta.

Ei kauan sitten saimme välityspalvelimen parannetun version. Nyt kerron sinulle, kuinka ne eroavat tavallisista ja miksi tämä on välttämätöntä.

aurinko

Syyskuussa 2017 Oracle, joka oli aiemmin ostanut Sunin, irtisanoi valtavan määrän Sunin työntekijöitä. Voidaan sanoa, että tällä hetkellä yritys lakkasi olemasta. Valitessaan nimeä uudelle järjestelmälle järjestelmänvalvojamme päättivät osoittaa kunnioitusta tämän yrityksen muistolle ja antoivat uuden järjestelmän nimeksi Sun. Kutsumme häntä keskenämme yksinkertaisesti "auringoiksi".

UKK VKontakten arkkitehtuurista ja työstä

pp:llä oli muutamia ongelmia. Yksi IP per ryhmä - tehoton välimuisti. Useilla fyysisillä palvelimilla on yhteinen IP-osoite, eikä ole mahdollista hallita, mille palvelimelle pyyntö lähetetään. Siksi, jos eri käyttäjät hakevat samaa tiedostoa, niin jos näillä palvelimilla on välimuisti, tiedosto päätyy kunkin palvelimen välimuistiin. Tämä on erittäin tehoton järjestelmä, mutta mitään ei voida tehdä.

Näin ollen - emme voi murskata sisältöä, koska emme voi valita tälle ryhmälle tiettyä palvelinta - niillä on yhteinen IP. Myös joistakin sisäisistä syistä meillä on tällaisia ​​palvelimia ei ollut mahdollista asentaa alueille. He seisoivat vain Pietarissa.

Auringon myötä muutimme valintajärjestelmää. Nyt meillä on anycast-reititys: dynaaminen reititys, anycast, itsetarkistusdemoni. Jokaisella palvelimella on oma yksilöllinen IP-osoite, mutta yhteinen aliverkko. Kaikki on määritetty siten, että jos yksi palvelin epäonnistuu, liikenne jakautuu automaattisesti saman ryhmän muiden palvelimien kesken. Nyt on mahdollista valita tietty palvelin, ei ylimääräistä välimuistia, eikä se vaikuttanut luotettavuuteen.

Painon tuki. Nyt meillä on varaa asentaa eri tehoisia koneita tarpeen mukaan, ja myös tilapäisten ongelmien sattuessa vaihtaa työskentelyn "auringon" painoja niiden kuormituksen vähentämiseksi, jotta ne "lepäävät" ja alkavat taas toimia.

Jakaminen sisältötunnuksen mukaan. Hassu asia sirpaleessa: yleensä sirpaamme sisältöä niin, että eri käyttäjät menevät samaan tiedostoon saman "auringon" kautta, jotta heillä on yhteinen välimuisti.

Julkaisimme hiljattain Clover-sovelluksen. Tämä on online-tietokilpailu suorassa lähetyksessä, jossa isäntä kysyy kysymyksiä ja käyttäjät vastaavat reaaliajassa valitessaan vaihtoehtoja. Sovelluksessa on chat, jossa käyttäjät voivat keskustella. Voi samanaikaisesti muodostaa yhteyden lähetykseen yli 100 tuhatta ihmistä. He kaikki kirjoittavat viestejä, jotka lähetetään kaikille osallistujille, ja viestin mukana tulee avatar. Jos 100 tuhatta ihmistä tulee yhdelle avatarille yhdessä "auringossa", se voi joskus rullata pilven takana.

Kestääksemme samaa tiedostoa koskevia pyyntöpurskeita, otamme tietyntyyppiselle sisällölle käyttöön typerän järjestelmän, joka levittää tiedostoja kaikkiin alueen käytettävissä oleviin "auringoihin".

Aurinko sisältä

Käänteinen välityspalvelin nginxissä, välimuisti joko RAM-muistissa tai nopeilla Optane/NVMe-levyillä. Esimerkki: http://sun4-2.userapi.com/c100500/path — linkki "aurinkoon", joka sijaitsee neljännellä alueella, toisessa palvelinryhmässä. Se sulkee polkutiedoston, joka sijaitsee fyysisesti palvelimella 100500.

Kätkö

Lisäämme arkkitehtoniseen malliimme vielä yhden solmun - välimuistiympäristön.

UKK VKontakten arkkitehtuurista ja työstä

Alla on asettelukaavio alueelliset kätköt, niitä on noin 20. Nämä ovat paikkoja, joissa sijaitsevat kätköt ja "auringot", jotka voivat tallentaa liikennettä välimuistiin itsensä läpi.

UKK VKontakten arkkitehtuurista ja työstä

Tämä on multimediasisällön välimuistia; tähän ei tallenneta käyttäjätietoja - vain musiikkia, videoita, valokuvia.

Määrittelemme käyttäjän alueen keräämme alueilla ilmoitettuja BGP-verkkoetuliitteitä. Varaustapauksessa meidän on myös jäsennettävä geoip-tietokanta, jos emme löytäneet IP-osoitetta etuliitteillä. Määritämme alueen käyttäjän IP-osoitteen perusteella. Koodissa voimme tarkastella yhtä tai useampaa käyttäjän aluetta - niitä pisteitä, joita hän on maantieteellisesti lähimpänä.

Miten se toimii?

Laskemme tiedostojen suosion alueittain. Siellä on useita alueellisia välimuistia, joissa käyttäjä sijaitsee, ja tiedostotunniste - otamme tämän parin ja lisäämme luokitusta jokaisella latauksella.

Samaan aikaan demonit - palvelut alueilla - tulevat aika ajoin API:lle ja sanovat: "Olen sellainen ja sellainen välimuisti, anna minulle luettelo alueeni suosituimmista tiedostoista, jotka eivät vielä ole minulla. ” API toimittaa joukon tiedostoja luokituksen mukaan lajiteltuina, demoni lataa ne, vie ne alueille ja toimittaa tiedostot sieltä. Tämä on perustavanlaatuinen ero pu/pp:n ja Sunin välillä välimuistista: ne antavat tiedoston välittömästi itsensä kautta, vaikka tämä tiedosto ei olisikaan välimuistissa, ja välimuisti lataa tiedoston ensin itselleen ja alkaa sitten palauttaa sitä.

Tässä tapauksessa saamme sisältöä lähempänä käyttäjiä ja hajauttaa verkon kuormitusta. Esimerkiksi vain Moskovan välimuistista jaamme ruuhka-aikoina enemmän kuin 1 Tbit/s.

Mutta ongelmia on - välimuistipalvelimet eivät ole kumia. Supersuositulla sisällöllä joskus ei ole tarpeeksi verkkoa erilliselle palvelimelle. Välimuistipalvelimemme ovat 40-50 Gbit/s, mutta on sisältöä, joka tukkii tällaisen kanavan kokonaan. Pyrimme ottamaan käyttöön useamman kuin yhden kopion tallennuksen alueella suosituista tiedostoista. Toivon, että saamme sen käyttöön vuoden loppuun mennessä.

Katsoimme yleistä arkkitehtuuria.

  • Etupalvelimet, jotka hyväksyvät pyynnöt.
  • Taustaohjelmat, jotka käsittelevät pyyntöjä.
  • Varastot, jotka suljetaan kahden tyyppisten välityspalvelinten avulla.
  • Alueelliset välimuistit.

Mitä tästä kaaviosta puuttuu? Tietenkin tietokannat, joihin tallennamme tietoja.

Tietokannat tai moottorit

Emme kutsu niitä tietokannoiksi, vaan moottoreiksi - moottoreiksi, koska meillä ei käytännössä ole tietokantoja yleisesti hyväksytyssä merkityksessä.

UKK VKontakten arkkitehtuurista ja työstä

Tämä on välttämätön toimenpide.. Tämä tapahtui, koska vuosina 2008-2009, kun VK:n suosio kasvoi räjähdysmäisesti, projekti toimi kokonaan MySQL:n ja Memcachen kanssa ja siinä oli ongelmia. MySQL rakasti kaatumista ja korruptoi tiedostoja, minkä jälkeen se ei palautunut, ja Memcachen suorituskyky heikkeni vähitellen ja se oli käynnistettävä uudelleen.

Kävi ilmi, että yhä suositumpi projekti sisältää jatkuvaa tallennustilaa, joka turmelee tietoja, ja välimuistia, joka hidastaa. Tällaisissa olosuhteissa kasvavan hankkeen kehittäminen on vaikeaa. Päätettiin yrittää kirjoittaa uudelleen ne kriittiset asiat, joihin projekti keskittyi omiin pyöriimme.

Ratkaisu onnistui. Tähän oli mahdollisuus ja äärimmäinen välttämättömyys, koska muita skaalaustapoja ei tuolloin ollut olemassa. Ei ollut joukko tietokantoja, NoSQL:ää ei ollut vielä olemassa, oli vain MySQL, Memcache, PostrgreSQL - ja siinä se.

Universaali toiminta. Kehitystä johti C-kehittäjien tiimimme ja kaikki tehtiin johdonmukaisesti. Moottorista riippumatta niillä kaikilla oli suunnilleen sama tiedostomuoto kirjoitettuna levylle, samat käynnistysparametrit, käsiteltiin signaaleja samalla tavalla ja ne käyttäytyivät suunnilleen samalla tavalla reunatilanteissa ja ongelmissa. Moottoreiden lisääntyessä järjestelmänvalvojien on kätevää käyttää järjestelmää - eläintarhaa ei ole ylläpidettävä, ja heidän on opeteltava uudelleen käyttämään jokaista uutta kolmannen osapuolen tietokantaa, mikä mahdollisti nopean ja lisätä niiden määrää kätevästi.

Moottorityypit

Tiimi kirjoitti aika monta moottoria. Tässä on vain joitain niistä: ystävä, vihjeet, kuva, ipdb, kirjeet, luettelot, lokit, välimuisti, meowdb, uutiset, nostradamus, valokuva, soittolistat, pmemcached, hiekkalaatikko, haku, tallennus, tykkäykset, tehtävät,…

Jokaiselle tehtävälle, joka vaatii tietyn tietorakenteen tai käsittelee epätyypillisiä pyyntöjä, C-tiimi kirjoittaa uuden moottorin. Miksi ei.

Meillä on erillinen moottori memcached, joka on samanlainen kuin tavallinen, mutta jossa on paljon herkkuja ja joka ei hidasta. Ei ClickHouse, mutta se myös toimii. Saatavana erikseen pmemcached - Onko jatkuvasti muistissa, joka voi myös tallentaa tietoja levylle, lisäksi se mahtuu RAM-muistiin, jotta tietoja ei menetetä uudelleenkäynnistettäessä. Yksittäisiin tehtäviin on erilaisia ​​moottoreita: jonoja, luetteloita, sarjoja - kaikkea mitä projektimme vaatii.

Klusterit

Koodinäkökulmasta katsottuna moottoreita tai tietokantoja ei tarvitse ajatella prosesseina, kokonaisuuksina tai ilmentyminä. Koodi toimii erityisesti klustereiden, moottoriryhmien kanssa - yksi tyyppi klusteria kohden. Oletetaan, että on välimuistiin tallennettu klusteri - se on vain joukko koneita.

Koodin ei tarvitse tietää lainkaan palvelimien fyysistä sijaintia, kokoa tai lukumäärää. Hän menee klusteriin käyttämällä tiettyä tunnistetta.

Jotta tämä toimisi, sinun on lisättävä vielä yksi entiteetti, joka sijaitsee koodin ja moottoreiden välissä - valtuutettu.

RPC-välityspalvelin

Välityspalvelin yhdistävä bussi, jolla lähes koko sivusto toimii. Samaan aikaan meillä on palvelua ei löydy — Sen sijaan tälle välityspalvelimelle on konfiguraatio, joka tietää kaikkien klusterien sijainnin ja kaikki tämän klusterin sirpaleet. Näin järjestelmänvalvojat tekevät.

Ohjelmoijat eivät välitä lainkaan, kuinka paljon, missä ja mitä se maksaa - he menevät vain klusteriin. Tämä mahdollistaa meille paljon. Pyynnön vastaanottaessaan välityspalvelin uudelleenohjaa pyynnön tietäen minne - se määrittää tämän itse.

UKK VKontakten arkkitehtuurista ja työstä

Tässä tapauksessa välityspalvelin on suojapiste palveluvikoja vastaan. Jos jokin moottori hidastuu tai kaatuu, välityspalvelin ymmärtää tämän ja reagoi vastaavasti asiakaspuolelle. Tämän avulla voit poistaa aikakatkaisun - koodi ei odota moottorin vastausta, vaan ymmärtää, että se ei toimi ja sen on toimittava jotenkin eri tavalla. Koodi on varauduttava siihen, että tietokannat eivät aina toimi.

Erityiset toteutukset

Joskus vielä todella halutaan saada moottoriksi jonkinlainen epätyypillinen ratkaisu. Samalla päätettiin olla käyttämättä valmista rpc-välityspalvelinta, joka on luotu erityisesti moottoreihimme, vaan tehdä tehtävää varten erillinen proxy.

MySQL:lle, jota meillä on edelleen siellä täällä, käytämme db-välityspalvelinta, ja ClickHousessa - Kissanpentu.

Se toimii yleensä näin. On tietty palvelin, se käyttää kPHP:tä, Goa, Pythonia - yleensä mitä tahansa koodia, joka voi käyttää RPC-protokollaamme. Koodi toimii paikallisesti RPC-välityspalvelimella - jokainen palvelin, jossa koodi sijaitsee, käyttää omaa paikallista välityspalvelinta. Pyynnöstä välityspalvelin ymmärtää minne mennä.

UKK VKontakten arkkitehtuurista ja työstä

Jos yksi moottori haluaa siirtyä toiseen, vaikka se olisi naapuri, se kulkee välityspalvelimen kautta, koska naapuri voi olla toisessa datakeskuksessa. Moottorin ei pitäisi luottaa siihen, että se tietää minkään muun kuin itsensä sijainnin - tämä on vakioratkaisumme. Mutta toki poikkeuksiakin löytyy :)

Esimerkki TL-järjestelmästä, jonka mukaan kaikki moottorit toimivat.

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;

Tämä on binääriprotokolla, jonka lähin analogi on protobuf. Kaava määrittelee ennalta valinnaiset kentät, monimutkaiset tyypit - sisäänrakennettujen skalaarien laajennukset ja kyselyt. Kaikki toimii tämän protokollan mukaan.

RPC yli TL yli TCP/UDP… UDP?

Meillä on RPC-protokolla moottoripyyntöjen suorittamiseen, joka toimii TL-järjestelmän päällä. Tämä kaikki toimii TCP/UDP-yhteyden kautta. TCP on ymmärrettävää, mutta miksi tarvitsemme usein UDP:tä?

UDP auttaa välttää valtavan määrän yhteyksiä palvelimien välillä. Jos jokaisella palvelimella on RPC-välityspalvelin ja yleensä se voi mennä mihin tahansa moottoriin, palvelinta kohti on kymmeniä tuhansia TCP-yhteyksiä. Kuormaa on, mutta se on turha. UDP:n tapauksessa tätä ongelmaa ei ole.

Ei ylimääräistä TCP-kättelyä. Tämä on tyypillinen ongelma: kun uusi moottori tai uusi palvelin käynnistetään, useita TCP-yhteyksiä muodostetaan kerralla. Pienissä kevyissä pyynnöissä, esimerkiksi UDP-hyötykuorma, kaikki viestintä koodin ja moottorin välillä on kaksi UDP-pakettia: yksi lentää yhteen suuntaan, toinen toiseen. Yksi edestakainen matka - ja koodi sai vastauksen moottorilta ilman kättelyä.

Kyllä, kaikki vain toimii erittäin pienellä prosenttiosuudella pakettihäviöitä. Protokolla tukee uudelleenlähetyksiä ja aikakatkaisuja, mutta jos häviämme paljon, saamme melkein TCP: n, mikä ei ole kannattavaa. Emme aja UDP:tä valtamerten yli.

Meillä on tuhansia tällaisia ​​palvelimia, ja järjestelmä on sama: jokaiselle fyysiselle palvelimelle on asennettu moottoripaketti. Ne ovat enimmäkseen yksisäikeisiä toimiakseen mahdollisimman nopeasti ilman estoa, ja ne on sirpaloitu yksisäikeisiksi ratkaisuiksi. Samaan aikaan meillä ei ole mitään luotettavampaa kuin nämä moottorit, ja jatkuvaan tiedontallennukseen kiinnitetään paljon huomiota.

Pysyvä tietojen tallennus

Moottorit kirjoittavat binlogeja. Binlogi on tiedosto, jonka loppuun lisätään tapahtuma tilan tai tietojen muutoksesta. Eri ratkaisuissa sitä kutsutaan eri tavalla: binääriloki, WAL, POIS, mutta periaate on sama.

Moottorit kirjoittavat, jotta moottori ei lukisi koko binlogia uudelleen useiden vuosien ajan uudelleenkäynnistyksen yhteydessä tilannekuvat - nykyinen tila. Tarvittaessa he lukevat ensin siitä ja sitten lopettavat lukemisen binlogista. Kaikki binlogit kirjoitetaan samassa binäärimuodossa - TL-järjestelmän mukaisesti, jotta järjestelmänvalvojat voivat hallita niitä samalla tavalla työkaluillaan. Sellaista tarvetta tilannekuville ei ole. Siellä on yleinen otsikko, joka osoittaa, kenen tilannekuva on int, moottorin taika ja mikä runko ei ole tärkeä kenellekään. Tämä on tilannekuvan tallentaneen moottorin ongelma.

Kuvaan nopeasti toimintaperiaatteen. Siellä on palvelin, jolla moottori toimii. Hän avaa uuden tyhjän binlogin kirjoittamista varten ja kirjoittaa tapahtuman muutosta varten.

UKK VKontakten arkkitehtuurista ja työstä

Jossain vaiheessa hän joko päättää ottaa tilannekuvan itse tai vastaanottaa signaalin. Palvelin luo uuden tiedoston, kirjoittaa siihen koko tilan, liittää tiedoston loppuun nykyisen binlog-koon - offset - ja jatkaa kirjoittamista. Uutta binlogia ei luoda.

UKK VKontakten arkkitehtuurista ja työstä

Jossain vaiheessa, kun moottori käynnistyy uudelleen, levyllä on sekä binlog että tilannekuva. Moottori lukee koko tilannekuvan ja nostaa tilaansa tietyssä kohdassa.

UKK VKontakten arkkitehtuurista ja työstä

Lukee sijainnin, joka oli tilannevedoksen luomishetkellä, ja binlogin koon.

UKK VKontakten arkkitehtuurista ja työstä

Lukee binlogin lopun saadakseen nykyisen tilan ja jatkaa muiden tapahtumien kirjoittamista. Tämä on yksinkertainen kaavio; kaikki moottorimme toimivat sen mukaan.

Tietojen replikointi

Tämän seurauksena tietojen replikointi meidän lausuntoon perustuva - emme kirjoita binlogiin mitään sivumuutoksia, vaan nimittäin muutospyynnöt. Hyvin samanlainen kuin verkon kautta, vain hieman muokattu.

Samaa järjestelmää ei käytetä vain replikointiin, vaan myös varmuuskopioiden luomiseen. Meillä on moottori - kirjoitusmestari, joka kirjoittaa binlogiin. Missä tahansa muussa paikassa, johon järjestelmänvalvojat ovat määrittäneet sen, tämä binlog kopioidaan, ja siinä kaikki - meillä on varmuuskopio.

UKK VKontakten arkkitehtuurista ja työstä

Tarvittaessa replikan lukeminenSuorittimen lukukuormituksen vähentämiseksi yksinkertaisesti käynnistetään lukumoottori, joka lukee binlogin lopun ja suorittaa nämä komennot paikallisesti.

Viive täällä on hyvin pieni, ja on mahdollista selvittää, kuinka paljon jäljennös on jäljessä masterista.

Tietojen jakaminen RPC-välityspalvelimessa

Miten jakaminen toimii? Miten välityspalvelin ymmärtää, mihin klusterin sirpale lähettää? Koodi ei sano: "Lähetä 15 sirpaleella!" - ei, tämän tekee välityspalvelin.

Yksinkertaisin kaava on firstint — pyynnön ensimmäinen numero.

get(photo100_500) => 100 % N.

Tämä on esimerkki yksinkertaisesta välimuistissa olevasta tekstiprotokollasta, mutta kyselyt voivat tietysti olla monimutkaisia ​​ja jäsenneltyjä. Esimerkki ottaa kyselyn ensimmäisen luvun ja loppuosan, kun se jaetaan klusterin koolla.

Tämä on hyödyllistä, kun haluamme yhden kokonaisuuden datapaikan. Oletetaan, että 100 on käyttäjä- tai ryhmätunnus, ja haluamme, että yhden entiteetin kaikki tiedot ovat yhdellä sirpaleella monimutkaisia ​​kyselyitä varten.

Jos emme välitä siitä, miten pyynnöt jakautuvat klusterin kesken, on toinen vaihtoehto - tiivistää koko sirpaleen.

hash(photo100_500) => 3539886280 % N

Saamme myös hashin, jaon loppuosan ja sirpaleen numeron.

Molemmat vaihtoehdot toimivat vain, jos olemme varautuneet siihen, että kun lisäämme klusterin kokoa, jaamme sen tai lisäämme sen moninkertaiseksi. Meillä oli esimerkiksi 16 sirpaletta, meillä ei ole tarpeeksi, haluamme lisää - saamme turvallisesti 32 ilman seisokkeja. Jos haluamme kasvattaa ei moninkertaisia, tulee seisokkeja, koska emme pysty jakamaan kaikkea tarkasti ilman tappioita. Nämä vaihtoehdot ovat hyödyllisiä, mutta eivät aina.

Jos meidän on lisättävä tai poistettava mielivaltainen määrä palvelimia, käytämme sitä Johdonmukainen hajautus sormuksessa a la Ketama. Mutta samalla menetämme täysin tietojen paikallisuuden; meidän on yhdistettävä pyyntö klusteriin niin, että jokainen pala palauttaa oman pienen vastauksensa, ja yhdistä sitten vastaukset välityspalvelimeen.

On superspesifisiä pyyntöjä. Se näyttää tältä: RPC-välityspalvelin vastaanottaa pyynnön, määrittää mihin klusteriin mennään ja määrittää sirpaleen. Sitten on joko kirjoituspäälliköitä, tai jos klusterilla on replikatuki, se lähettää kopiolle pyynnöstä. Välityspalvelin tekee kaiken tämän.

UKK VKontakten arkkitehtuurista ja työstä

Lokit

Kirjoitamme lokeja useilla tavoilla. Ilmeisin ja yksinkertaisin on kirjoittaa lokit memcacheen.

ring-buffer: prefix.idx = line

Siellä on avainetuliite - lokin nimi, viiva ja tämän lokin koko - rivien lukumäärä. Otetaan satunnaisluku 0:sta rivien lukumäärään miinus 1. Välimuistin avain on etuliite, joka on ketjutettu tähän satunnaisnumeroon. Tallennamme lokirivin ja nykyisen ajan arvoon.

Kun on tarpeen lukea lokit, suoritamme Multi Get kaikki avaimet ajan mukaan lajiteltuina, jolloin saat tuotantolokin reaaliajassa. Kaavaa käytetään, kun joudut korjaamaan jotain tuotannossa reaaliajassa, rikkomatta mitään, pysäyttämättä tai sallimatta liikennettä muille koneille, mutta tämä loki ei kestä kauan.

Puun luotettavaan varastointiin meillä on moottori hirsi-moottori. Juuri tästä syystä se luotiin ja sitä käytetään laajalti valtavassa määrässä klustereita. Suurin tuntemani klusteri säilyttää 600 TB pakattua puuta.

Moottori on hyvin vanha, on klustereita, jotka ovat jo 6-7 vuotta vanhoja. Siinä on ongelmia, joita yritämme ratkaista, esimerkiksi aloimme aktiivisesti käyttää ClickHousea lokien tallentamiseen.

Lokien kerääminen ClickHousessa

Tämä kaavio näyttää, kuinka astumme moottoreihimme.

UKK VKontakten arkkitehtuurista ja työstä

Siellä on koodi, joka kulkee paikallisesti RPC:n kautta RPC-välityspalvelimelle, ja se ymmärtää minne mennä moottoriin. Jos haluamme kirjoittaa lokeja ClickHousessa, meidän on muutettava kaksi osaa tässä mallissa:

  • vaihda osa moottorista ClickHousella;
  • korvaa RPC-välityspalvelin, joka ei voi käyttää ClickHousea, jollain ratkaisulla, joka pystyy, ja RPC:n kautta.

Moottori on yksinkertainen - korvaamme sen palvelimella tai palvelinklusterilla ClickHousella.

Ja menimme ClickHouseen Kitten House. Jos siirrymme suoraan KittenHousesta ClickHouseen, se ei selviä. Jopa ilman pyyntöjä se muodostuu valtavan määrän koneiden HTTP-yhteyksistä. Jotta järjestelmä toimisi, palvelimella, jossa on ClickHouse paikallinen käänteinen välityspalvelin nostetaan, joka on kirjoitettu siten, että se kestää tarvittavat liitäntämäärät. Se voi myös puskuroida tietoja itsessään suhteellisen luotettavasti.

UKK VKontakten arkkitehtuurista ja työstä

Joskus emme halua toteuttaa RPC-mallia epästandardeissa ratkaisuissa, esimerkiksi nginxissä. Siksi KittenHouse pystyy vastaanottamaan lokeja UDP:n kautta.

UKK VKontakten arkkitehtuurista ja työstä

Jos lokien lähettäjä ja vastaanottaja työskentelevät samalla koneella, UDP-paketin katoamisen todennäköisyys paikallisessa isännässä on melko pieni. Käytämme yksinkertaisesti UDP-lähetystä kompromissina tarpeen ottaa RPC käyttöön kolmannen osapuolen ratkaisussa ja luotettavuuden välillä. Palaamme tähän kaavaan myöhemmin.

seuranta

Meillä on kahdentyyppisiä lokeja: järjestelmänvalvojien palvelimilleen keräämät ja kehittäjien koodista kirjoittamat lokit. Ne vastaavat kahden tyyppisiä mittareita: järjestelmä ja tuote.

Järjestelmän mittarit

Se toimii kaikilla palvelimillamme netdata, joka kerää tilastoja ja lähettää ne osoitteeseen Grafiittihiili. Siksi tallennusjärjestelmänä käytetään ClickHousea, ei esimerkiksi Whisperiä. Tarvittaessa voit lukea suoraan ClickHousesta tai käyttää grafana mittareita, kaavioita ja raportteja varten. Kehittäjänä meillä on tarpeeksi pääsyä Netdataan ja Grafanaan.

Tuotemittarit

Mukavuuden vuoksi olemme kirjoittaneet paljon asioita. Esimerkiksi on joukko tavallisia toimintoja, joiden avulla voit kirjoittaa Counts-, UniqueCounts-arvoja tilastoihin, jotka lähetetään jonnekin pidemmälle.

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

$stats = statlogsStatData($params)

Tämän jälkeen voimme käyttää lajittelu- ja ryhmittelysuodattimia ja tehdä tilastoista kaiken haluamamme - rakentaa kaavioita, määrittää vahtikoiria.

Kirjoitamme erittäin monia mittareita tapahtumien määrä on 600 miljardista 1 biljoonaan päivässä. Haluamme kuitenkin säilyttää ne ainakin pari vuottaymmärtää mittareiden trendejä. Kaiken yhdistäminen on suuri ongelma, jota emme ole vielä ratkaisseet. Kerron teille, kuinka se on toiminut viime vuosina.

Meillä on funktioita, jotka kirjoittavat nämä mittarit paikalliseen muistimuistiinvähentääksesi merkintöjen määrää. Kerran lyhyessä ajassa käynnistetty paikallisesti stats-daemon kerää kaikki tietueet. Seuraavaksi demoni yhdistää mittarit kahteen palvelinkerrokseen tukkien kerääjät, joka kokoaa tilastot useista koneistamme, jotta niiden takana oleva kerros ei kuole.

UKK VKontakten arkkitehtuurista ja työstä

Tarvittaessa voimme kirjoittaa suoraan lokinkeräilijöille.

UKK VKontakten arkkitehtuurista ja työstä

Mutta koodin kirjoittaminen suoraan keräilijöille ohittamalla stas-daemom on huonosti skaalautuva ratkaisu, koska se lisää kerääjän kuormitusta. Ratkaisu sopii vain, jos emme jostain syystä pysty nostamaan koneen memcache stats-daemonia tai se kaatui ja menimme suoraan.

Seuraavaksi lokit-kerääjät yhdistävät tilastot meowDB - Tämä on tietokantamme, johon voidaan myös tallentaa mittareita.

UKK VKontakten arkkitehtuurista ja työstä

Sitten voimme tehdä koodista binaarisia "lähes SQL:n" valintoja.

UKK VKontakten arkkitehtuurista ja työstä

Kokeilu

Kesällä 2018 meillä oli sisäinen hackathon, ja syntyi idea yrittää korvata kaavion punainen osa jollain, joka voisi tallentaa mittareita ClickHouseen. Meillä on lokit ClickHousessa - miksi et kokeilisi sitä?

UKK VKontakten arkkitehtuurista ja työstä

Meillä oli järjestelmä, joka kirjoitti lokit KittenHousen kautta.

UKK VKontakten arkkitehtuurista ja työstä

Me päätimme lisää kaavioon toinen "*talo"., joka vastaanottaa täsmälleen tiedot siinä muodossa kuin koodimme kirjoittaa ne UDP:n kautta. Sitten tämä *House muuttaa ne lisäkkeiksi, kuten tukiksi, jotka KittenHouse ymmärtää. Hän pystyy täydellisesti toimittamaan nämä lokit ClickHouselle, jonka pitäisi pystyä lukemaan ne.

UKK VKontakten arkkitehtuurista ja työstä

Järjestelmä, jossa on memcache, stats-daemon ja logs-collectors -tietokanta, korvataan tällä.

UKK VKontakten arkkitehtuurista ja työstä

Järjestelmä, jossa on memcache, stats-daemon ja logs-collectors -tietokanta, korvataan tällä.

  • Täällä on lähetys koodista, joka on kirjoitettu paikallisesti StatsHousessa.
  • StatsHouse kirjoittaa UDP-mittauksia, jotka on jo muutettu SQL-lisäkkeiksi, KittenHouseen erissä.
  • KittenHouse lähettää ne ClickHouselle.
  • Jos haluamme lukea ne, luemme ne ohittamalla StatsHousen - suoraan ClickHousesta tavallisella SQL:llä.

Onko se vielä kokeilu, mutta pidämme siitä, miten se osoittautuu. Jos korjaamme järjestelmän ongelmat, ehkä siirrymme siihen kokonaan. Henkilökohtaisesti toivon niin.

ohjelma ei säästä rautaa. Tarvitaan vähemmän palvelimia, paikallisia tilasto-daemoneja ja lokienkerääjiä ei tarvita, mutta ClickHouse vaatii suuremman palvelimen kuin nykyisessä järjestelmässä. Tarvitaan vähemmän palvelimia, mutta niiden on oltava kalliimpia ja tehokkaampia.

Ota käyttöön

Katsotaanpa ensin PHP:n käyttöönottoa. Kehitämme sisään mennä: käytä GitLab и TeamCity käyttöönottoa varten. Kehityshaarat yhdistetään master-haaraan, testausta varten master-haaroista ne yhdistetään lavastukseen ja lavastusta tuotantoon.

Ennen käyttöönottoa otetaan nykyinen tuotantohaara ja edellinen, ja niissä otetaan huomioon diff-tiedostot - muutokset: luotu, poistettu, muutettu. Tämä muutos tallennetaan erityisen copyfast-moottorin binlogiin, joka voi nopeasti replikoida muutokset koko palvelinkalustoon. Tässä ei käytetä suoraan kopioimista, vaan juorujen replikointi, kun yksi palvelin lähettää muutoksia lähimmille naapureilleen, ne naapureilleen ja niin edelleen. Tämän avulla voit päivittää koodin kymmenissä ja sekunneissa koko laivastossa. Kun muutos saavuttaa paikallisen replikan, se käyttää näitä korjaustiedostoja siihen paikallinen tiedostojärjestelmä. Myös palautus suoritetaan saman järjestelmän mukaisesti.

Käytämme myös paljon kPHP:tä ja sillä on myös oma kehitystyönsä mennä yllä olevan kaavion mukaan. Tästä lähtien HTTP-palvelin binaari, silloin emme voi tuottaa erotusta - julkaisubinaari painaa satoja megatavuja. Siksi tässä on toinen vaihtoehto - versio kirjoitetaan binlog copyfast. Jokaisella rakennuksella se kasvaa, ja palautuksen aikana se myös kasvaa. Versio replikoitu palvelimille. Paikalliset copyfastit näkevät, että uusi versio on saapunut binlogiin, ja samalla juorujen replikaatiolla he ottavat itselleen binääriversion viimeisimmän version väsyttämättä pääpalvelintamme, vaan jakavat kuorman huolellisesti verkon yli. Mitä seuraa siro uudelleenkäynnistys uudelle versiolle.

Moottoreillemme, jotka ovat myös pohjimmiltaan binaarisia, järjestelmä on hyvin samanlainen:

  • git master haara;
  • binääri sisään debytantti;
  • versio kirjoitetaan binlog copyfastiin;
  • replikoitu palvelimille;
  • palvelin hakee uuden .dep;
  • dpkg -i;
  • siro uudelleenkäynnistys uuteen versioon.

Erona on, että binaarimme on pakattu arkistoon debytanttija pumpattaessa niitä pois dpkg -i asetetaan järjestelmään. Miksi kPHP otetaan käyttöön binäärimuodossa ja moottorit dpkg-muodossa? Näin kävi. Se toimii - älä koske siihen.

Hyödyllisiä linkkejä:

Alexey Akulovich on yksi niistä, jotka osana ohjelmakomiteaa auttavat PHP Venäjä 17. toukokuuta tulee viime aikojen suurin tapahtuma PHP-kehittäjille. Katsokaa, mikä hieno PC meillä on kaiuttimet (kaksi heistä kehittää PHP-ydintä!) - näyttää siltä, ​​​​että et voi missata, jos kirjoitat PHP:tä.

Lähde: will.com

Lisää kommentti