Kirjoita VKontakte-viestitietokanta uudelleen tyhjästä ja selviydy

Käyttäjämme kirjoittavat toisilleen viestejä väsymättä.
Kirjoita VKontakte-viestitietokanta uudelleen tyhjästä ja selviydy
Se on aika paljon. Jos aiot lukea kaikkien käyttäjien kaikki viestit, siihen kuluisi yli 150 tuhatta vuotta. Edellyttäen, että olet melko edistynyt lukija ja käytät enintään sekunnin jokaiseen viestiin.

Tällaisella tietomäärällä on tärkeää, että logiikka sen tallentamiseksi ja käyttämiseksi on rakennettu optimaalisesti. Muuten yhdessä ei niin ihmeellisessä hetkessä voi käydä selväksi, että kaikki menee pian pieleen.

Meille tämä hetki koitti puolitoista vuotta sitten. Miten päädyimme tähän ja mitä lopulta tapahtui - kerromme järjestyksessä.

sairauskertomus

Ensimmäisessä toteutuksessa VKontakte-viestit toimivat PHP-taustajärjestelmän ja MySQL:n yhdistelmällä. Tämä on täysin normaali ratkaisu pienelle opiskelijasivustolle. Tämä sivusto kuitenkin kasvoi hallitsemattomasti ja alkoi vaatia tietorakenteiden optimointia itselleen.

Vuoden 2009 lopussa kirjoitettiin ensimmäinen tekstikonevarasto, johon siirrettiin vuonna 2010 viestit.

Tekstikoneessa viestit tallennettiin luetteloihin - eräänlaisiin "postilaatikoihin". Jokaisen tällaisen luettelon määrittää käyttäjätunnus - käyttäjä, joka omistaa kaikki nämä viestit. Viestillä on joukko attribuutteja: keskustelukumppanin tunniste, teksti, liitteet ja niin edelleen. Viestitunniste "laatikon" sisällä on local_id, se ei muutu koskaan ja se määrätään peräkkäin uusille viesteille. "Laatikot" ovat riippumattomia, eikä niitä ole synkronoitu keskenään moottorin sisällä, vaan niiden välinen kommunikaatio tapahtuu PHP-tasolla. Voit tarkastella tekstimoottorin tietorakennetta ja ominaisuuksia sisältäpäin täällä.
Kirjoita VKontakte-viestitietokanta uudelleen tyhjästä ja selviydy
Tämä riitti kahden käyttäjän väliseen kirjeenvaihtoon. Arvaa mitä tapahtui seuraavaksi?

Toukokuussa 2011 VKontakte aloitti keskustelut useiden osallistujien kanssa - multi-chatin. Työskennelläksemme heidän kanssaan loimme kaksi uutta klusteria - jäsen-chatit ja chat-jäsenet. Ensimmäinen tallentaa tietoja käyttäjien keskusteluista, toinen tallentaa tietoja käyttäjistä keskustelujen mukaan. Itse listojen lisäksi tämä sisältää esimerkiksi kutsuvan käyttäjän ja ajan, jolloin hänet lisättiin chatiin.

"PHP, laitetaan viesti chattiin", käyttäjä sanoo.
"Tule, {username}", sanoo PHP.
Kirjoita VKontakte-viestitietokanta uudelleen tyhjästä ja selviydy
Tässä järjestelmässä on haittoja. Synkronointi on edelleen PHP:n vastuulla. Suuret chatit ja käyttäjät, jotka lähettävät heille samanaikaisesti viestejä, ovat vaarallinen tarina. Koska tekstimoottorin ilmentymä riippuu käyttäjätunnuksesta, chatin osallistujat voivat saada saman viestin eri aikoina. Tämän kanssa voisi elää, jos kehitys pysähtyisi. Mutta niin ei tapahdu.

Vuoden 2015 lopussa julkaisimme yhteisöviestit ja vuoden 2016 alussa sovellusliittymän niille. Suurten chatbottien tultua käyttöön yhteisöissä oli mahdollista unohtaa tasainen kuorman jakautuminen.

Hyvä botti tuottaa useita miljoonia viestejä päivässä - edes puheliasimmat käyttäjät eivät voi ylpeillä tästä. Tämä tarkoittaa, että jotkin tekstimoottorit, joissa tällaiset robotit asuivat, alkoivat kärsiä täysin.

Viestikoneet vuonna 2016 ovat 100 chat-jäsen- ja jäsen-chatia sekä 8000 tekstimoottoria. Niitä isännöi tuhat palvelinta, joista jokaisessa oli 64 Gt muistia. Ensimmäisenä hätätoimenpiteenä lisäsimme muistia vielä 32 Gt. Arvioimme ennusteet. Ilman radikaaleja muutoksia tämä riittäisi noin vuodeksi. Sinun on joko hankittava laitteisto tai optimoitava itse tietokannat.

Arkkitehtuurin luonteesta johtuen on järkevää lisätä laitteistoa vain kerrannaisina. Eli autojen määrän ainakin kaksinkertaistaminen - ilmeisesti tämä on melko kallis polku. Optimoimme.

Uusi konsepti

Uuden lähestymistavan keskeinen ydin on chat. Chatissa on luettelo siihen liittyvistä viesteistä. Käyttäjällä on luettelo keskusteluista.

Vaadittu vähimmäismäärä on kaksi uutta tietokantaa:

  • chat-moottori. Tämä on keskusteluvektoreiden arkisto. Jokaisessa chatissa on siihen liittyviä viestejä. Jokaisella viestillä on teksti ja yksilöllinen viestin tunniste chatissa - chat_local_id.
  • käyttäjämoottori. Tämä on käyttäjien vektoreiden tallennus - linkkejä käyttäjiin. Jokaisella käyttäjällä on peer_id-vektori (keskustelukumppanit - muut käyttäjät, multi-chat tai yhteisöt) ja viestivektori. Jokaisella peer_id:llä on siihen liittyvien viestien vektori. Jokaisella viestillä on chat_local_id ja yksilöllinen viestitunnus kyseiselle käyttäjälle - user_local_id.

Kirjoita VKontakte-viestitietokanta uudelleen tyhjästä ja selviydy
Uudet klusterit kommunikoivat keskenään TCP:n avulla - tämä varmistaa, että pyyntöjen järjestys ei muutu. Itse pyynnöt ja niiden vahvistukset tallennetaan kiintolevylle - joten voimme palauttaa jonon tilan milloin tahansa vian tai moottorin uudelleenkäynnistyksen jälkeen. Koska käyttäjämoottori ja chat-moottori ovat kumpikin 4 tuhatta sirpaleita, pyyntöjono klusterien välillä jakautuu tasaisesti (mutta todellisuudessa sitä ei ole ollenkaan - ja se toimii erittäin nopeasti).

Levyn kanssa työskentely tietokantoissamme perustuu useimmissa tapauksissa muutosten binäärilokin (binlog), staattisten tilannekuvien ja muistissa olevan osittaisen kuvan yhdistelmään. Päivän aikana tehdyt muutokset kirjoitetaan binlogiin, ja nykyisestä tilasta luodaan ajoittain tilannekuva. Tilannekuva on kokoelma tietorakenteita, jotka on optimoitu tarkoituksiinmme. Se koostuu otsikosta (kuvan metaindeksistä) ja joukosta metatiedostoja. Otsikko tallennetaan pysyvästi RAM-muistiin, ja se osoittaa, mistä tilannekuvan tietoja etsitään. Jokainen metatiedosto sisältää tietoja, joita todennäköisesti tarvitaan lähiaikoina – esimerkiksi yksittäiseen käyttäjään liittyen. Kun teet kyselyn tietokannasta tilannevedoksen otsikon avulla, vaadittu metatiedosto luetaan ja sitten otetaan huomioon tilannevedoksen luomisen jälkeen tapahtuneet muutokset binlogissa. Voit lukea lisää tämän lähestymistavan eduista täällä.

Samanaikaisesti itse kiintolevyn tiedot muuttuvat vain kerran päivässä - myöhään illalla Moskovassa, kun kuormitus on minimaalinen. Tämän ansiosta (tietäen, että levyn rakenne on vakio koko päivän), meillä on varaa korvata vektorit kiinteän kokoisilla matriiseilla - ja tämän ansiosta lisää muistia.

Viestin lähettäminen uudessa järjestelmässä näyttää tältä:

  1. PHP-taustaosa ottaa yhteyttä käyttäjäkoneeseen ja pyytää lähettämään viestin.
  2. user-engine välittää pyynnön haluttuun chat-engine-instanssiin, joka palaa käyttäjän moottorin chat_local_id-tunnukseen - tämän keskustelun uuden viestin yksilölliseen tunnisteeseen. Tämän jälkeen chat_engine lähettää viestin kaikille chatissa oleville vastaanottajille.
  3. user-engine vastaanottaa chat_local_id chat-engineltä ja palauttaa user_local_id PHP:lle - tämän käyttäjän yksilöllisen viestitunnisteen. Tätä tunnistetta käytetään sitten esimerkiksi viestien käsittelyyn API:n kautta.

Kirjoita VKontakte-viestitietokanta uudelleen tyhjästä ja selviydy
Mutta viestien lähettämisen lisäksi sinun on otettava käyttöön muutama tärkeä asia:

  • Alaluettelot ovat esimerkiksi viimeisimmät viestit, jotka näet keskusteluluetteloa avattaessa. Lukemattomat viestit, viestit, joissa on tunnisteita ("Tärkeää", "Roskaposti" jne.).
  • Viestien pakkaaminen chat-moottorissa
  • Viestien tallentaminen välimuistiin käyttäjäkoneessa
  • Hae (kaikista valintaikkunoista ja tietyn ikkunan sisällä).
  • Reaaliaikainen päivitys (Longpolling).
  • Tallennetaan historiaa välimuistin käyttöönottamiseksi mobiiliasiakkailla.

Kaikki alaluettelot ovat nopeasti muuttuvia rakenteita. Käytämme työskennelläksemme heidän kanssaan Splay-puut. Tämä valinta selittyy sillä, että puun yläosaan tallennetaan joskus kokonaisen segmentin viestejä tilannevedosta - esimerkiksi öisen uudelleenindeksoinnin jälkeen puu koostuu yhdestä yläosasta, joka sisältää kaikki aliluettelon viestit. Splay-puun avulla on helppo sijoittaa tällaisen kärjen keskelle ilman, että sinun tarvitsee ajatella tasapainottamista. Lisäksi Splay ei tallenna tarpeettomia tietoja, mikä säästää muistia.

Viestit sisältävät suuren määrän tietoa, enimmäkseen tekstiä, josta on hyötyä pakattaessa. On tärkeää, että voimme purkaa tarkasti jopa yhden yksittäisen viestin. Käytetään viestien pakkaamiseen Huffmanin algoritmi omalla heuristiikallamme - esimerkiksi tiedämme, että viesteissä sanat vuorottelevat "ei-sanojen" kanssa - välilyönnit, välimerkit - ja muistamme myös joitain venäjän kielen symbolien käytön erityispiirteitä.

Koska käyttäjiä on paljon vähemmän kuin chatteja, tallennamme viestit välimuistiin käyttäjäkoneen satunnaiskäyttölevypyyntöjen tallentamiseksi.

Viestihaku toteutetaan diagonaalisena kyselynä käyttäjämoottorista kaikkiin chat-moottoriin, jotka sisältävät tämän käyttäjän keskusteluja. Tulokset yhdistetään itse käyttäjämoottorissa.

No, kaikki yksityiskohdat on otettu huomioon, jäljellä on vain siirtyä uuteen järjestelmään - ja mieluiten ilman, että käyttäjät huomaavat sitä.

Tiedonsiirto

Meillä on siis tekstikone, joka tallentaa viestit käyttäjien mukaan, sekä kaksi chat-jäsenten ja jäsenkeskustelujen klusteria, jotka tallentavat tietoja useista chat-huoneista ja niissä olevista käyttäjistä. Kuinka siirtyä tästä uuteen käyttäjä- ja chat-moottoriin?

Jäsen-chatia vanhassa järjestelmässä käytettiin ensisijaisesti optimointiin. Siirsimme siitä nopeasti tarvittavat tiedot chat-jäsenille, jolloin se ei enää osallistunut siirtoprosessiin.

Jono chat-jäsenille. Se sisältää 100 esiintymää, kun taas chat-moottorissa on 4 tuhatta. Tietojen siirtämiseksi sinun on saatettava ne vaatimusten mukaisiksi - tätä varten chat-jäsenet jaettiin samoihin 4 XNUMX kopioon, ja sitten chat-jäsenten binlogin lukeminen otettiin käyttöön chat-moottorissa.
Kirjoita VKontakte-viestitietokanta uudelleen tyhjästä ja selviydy
Nyt chat-moottori tietää multi-chatista chat-jäseniltä, ​​mutta se ei vielä tiedä mitään dialogista kahden keskustelukumppanin kanssa. Tällaiset dialogit sijaitsevat tekstimoottorissa käyttäjiin viitaten. Tässä otimme tiedot "otsaan": jokainen chat-moottorin ilmentymä kysyi kaikilta tekstimoottorin esiintymiltä, ​​oliko heillä sen tarvitsema dialogi.

Hienoa - chat-moottori tietää, mitä multi-chat-keskusteluja on olemassa, ja tietää, mitä dialogeja siellä on.
Sinun on yhdistettävä viestit multi-chat-keskusteluissa, jotta saat jokaisessa keskustelussa luettelon viesteistä. Ensin chat-moottori hakee tekstimoottorista kaikki käyttäjien viestit tästä keskustelusta. Joissakin tapauksissa niitä on melko paljon (jopa satoja miljoonia), mutta erittäin harvoja poikkeuksia lukuun ottamatta chat mahtuu kokonaan RAM-muistiin. Meillä on tilaamattomia viestejä, kutakin useana kappaleena - ne onhan ne kaikki poimittu eri käyttäjiä vastaavista tekstikoneista. Tavoitteena on lajitella viestejä ja päästä eroon turhaa tilaa vievistä kopioista.

Jokaisella viestillä on aikaleima, joka sisältää lähetysajan ja tekstin. Käytämme aikaa lajitteluun - asetamme osoittimia multichatin osallistujien vanhimpiin viesteihin ja vertailemme hajautusarvoja tarkoitettujen kopioiden tekstistä siirtyen kohti aikaleiman kasvattamista. On loogista, että kopioilla on sama hash ja aikaleima, mutta käytännössä näin ei aina ole. Kuten muistat, synkronoinnin vanhassa järjestelmässä suoritti PHP - ja harvoissa tapauksissa saman viestin lähetysaika vaihteli eri käyttäjillä. Näissä tapauksissa annoimme itsemme muokata aikaleimaa - yleensä sekunnissa. Toinen ongelma on viestien erilainen järjestys eri vastaanottajille. Tällaisissa tapauksissa sallimme ylimääräisen kopion luomisen, jossa oli erilaisia ​​tilausvaihtoehtoja eri käyttäjille.

Tämän jälkeen tiedot multichatin viesteistä lähetetään käyttäjäkoneelle. Ja tässä tulee tuoduista viesteistä epämiellyttävä ominaisuus. Normaalissa toiminnassa moottorille tulevat viestit järjestetään tiukasti nousevassa järjestyksessä user_local_id-tunnuksen mukaan. Vanhasta moottorista käyttäjämoottoriin tuodut viestit menettivät tämän hyödyllisen ominaisuuden. Samanaikaisesti testaamisen helpottamiseksi sinun on voitava päästä niihin nopeasti käsiksi, etsiä niistä jotain ja lisätä uusia.

Käytämme erityistä tietorakennetta tuotujen viestien tallentamiseen.

Se edustaa koon vektoria Kirjoita VKontakte-viestitietokanta uudelleen tyhjästä ja selviydymissä kaikki ovat Kirjoita VKontakte-viestitietokanta uudelleen tyhjästä ja selviydy - ovat erilaisia ​​ja alenevassa järjestyksessä, elementtien erityisjärjestyksessä. Jokaisessa segmentissä indekseillä Kirjoita VKontakte-viestitietokanta uudelleen tyhjästä ja selviydy elementit lajitellaan. Elementin etsiminen tällaisesta rakenteesta vie aikaa Kirjoita VKontakte-viestitietokanta uudelleen tyhjästä ja selviydy kautta Kirjoita VKontakte-viestitietokanta uudelleen tyhjästä ja selviydy binäärihakuja. Elementin lisäys poistetaan Kirjoita VKontakte-viestitietokanta uudelleen tyhjästä ja selviydy.

Joten keksimme kuinka siirtää tietoja vanhoista moottoreista uusiin. Mutta tämä prosessi kestää useita päiviä - ja on epätodennäköistä, että näinä päivinä käyttäjämme luopuisivat tavasta kirjoittaa toisilleen. Jotta et menetä viestejä tänä aikana, siirrymme työmalliin, joka käyttää sekä vanhoja että uusia klustereita.

Tiedot kirjoitetaan chat-jäsenille ja käyttäjäkoneelle (eikä tekstimoottorille, kuten normaalissa toiminnassa vanhan kaavan mukaan). user-engine välittää pyynnön chat-enginelle - ja tässä käyttäytyminen riippuu siitä, onko tämä keskustelu jo yhdistetty vai ei. Jos chattia ei ole vielä yhdistetty, chat-kone ei kirjoita viestiä itselleen, vaan sen käsittely tapahtuu vain tekstikoneessa. Jos chat on jo yhdistetty chat-moottoriin, se palauttaa chat_local_id käyttäjämoottorille ja lähettää viestin kaikille vastaanottajille. user-engine välittää kaikki tiedot tekstimoottoriin - jotta jos jotain tapahtuu, voimme aina peruuttaa, koska kaikki nykyiset tiedot ovat vanhassa moottorissa. text-engine palauttaa user_local_id, jonka käyttäjäkone tallentaa ja palauttaa taustajärjestelmään.
Kirjoita VKontakte-viestitietokanta uudelleen tyhjästä ja selviydy
Tämän seurauksena siirtymäprosessi näyttää tältä: yhdistämme tyhjät käyttäjä- ja chat-moottoriklusterit. chat-engine lukee koko chat-jäsenten binlogin, jonka jälkeen välityspalvelin alkaa yllä kuvatun kaavan mukaisesti. Siirrämme vanhat tiedot ja saamme kaksi synkronoitua klusteria (vanha ja uusi). Jäljelle jää vain vaihtaa lukeminen tekstimoottorista käyttäjämoottoriin ja poistaa välityspalvelin käytöstä.

Tulokset

Uuden lähestymistavan ansiosta moottoreiden kaikkia suorituskykymittareita on parannettu ja tietojen johdonmukaisuuteen liittyvät ongelmat on ratkaistu. Nyt voimme nopeasti ottaa uusia ominaisuuksia viesteihin (ja olemme jo aloittaneet tämän - lisäsimme chatin osallistujien enimmäismäärää, otimme käyttöön edelleenlähetettyjen viestien haun, käynnistimme kiinnitetyt viestit ja nostimme viestien kokonaismäärää käyttäjää kohti) .

Logiikkamuutokset ovat todella valtavia. Ja haluaisin huomauttaa, että tämä ei aina tarkoita kokonaisia ​​vuosia valtavan tiimin kehitystä ja lukemattomia koodirivejä. chat-moottori ja käyttäjämoottori sekä kaikki lisätarinat, kuten Huffman viestien pakkaamiseen, Splay-puut ja tuotujen viestien rakenne, on alle 20 tuhatta koodiriviä. Ja ne ovat kirjoittaneet 3 kehittäjää vain 10 kuukaudessa (on kuitenkin syytä pitää mielessä, että kaikki kolme kehittäjä - maailmanmestareita urheiluohjelmissa).

Lisäksi sen sijaan, että kaksinkertaistaisimme palvelimien määrän, vähennimme niiden määrää puoleen - nyt käyttäjä- ja chat-moottori toimivat 500 fyysisellä koneella, kun taas uudessa järjestelmässä on suuri kuormitusvara. Säästimme paljon rahaa laitteissa - noin 5 miljoonaa dollaria + 750 tuhatta dollaria vuodessa käyttökuluissa.

Pyrimme löytämään parhaat ratkaisut monimutkaisimpiin ja suuriin ongelmiin. Meillä on niitä runsaasti – ja siksi etsimme lahjakkaita kehittäjiä tietokantaosastolle. Jos rakastat ja osaat ratkaista tällaisia ​​ongelmia, sinulla on erinomainen tietämys algoritmeista ja tietorakenteista, kutsumme sinut mukaan tiimiin. Ota yhteyttä meihin HRyksityiskohtia varten.

Vaikka tämä tarina ei koske sinua, huomaa, että arvostamme suosituksia. Kerro kaverille asiasta avoimia kehittäjäpaikkoja, ja jos hän suorittaa koeajan onnistuneesti, saat 100 tuhannen ruplan bonuksen.

Lähde: will.com

Lisää kommentti