Meie kasutajad kirjutavad ĂŒksteisele sĂ”numeid tundmata vĂ€simust.

Seda on pĂ€ris palju. Kui kavatsete lugeda kĂ”igi kasutajate kĂ”iki sĂ”numeid, kuluks selleks rohkem kui 150 tuhat aastat. Eeldusel, et olete ĂŒsna kogenud lugeja ja ei kuluta igale sĂ”numile rohkem kui sekundi.
Sellise andmemahu puhul on ĂŒlioluline, et nende salvestamise ja juurdepÀÀsu loogika oleks ĂŒles ehitatud optimaalselt. Muidu vĂ”ib ĂŒhel mitte just imelisel hetkel selguda, et peagi lĂ€heb kĂ”ik viltu.
Meie jaoks saabus see hetk poolteist aastat tagasi. Kuidas me selleni jÔudsime ja mis lÔpuks juhtus - rÀÀgime teile jÀrjekorras.
haiguslugu
Esimeses rakenduses töötasid VKontakte sÔnumid PHP taustaprogrammi ja MySQL kombinatsioonil. See on vÀikese tudengiveebi jaoks tÀiesti tavaline lahendus. See sait aga kasvas kontrollimatult ja hakkas nÔudma enda jaoks andmestruktuuride optimeerimist.
2009. aasta lĂ”pus kirjutati esimene tekstimootori repositoorium, kuhu 2010. aastal kanti ĂŒle sĂ”numid.
Tekstimootoris salvestati sĂ”numid loenditesse - omamoodi postkastidesse. Iga sellise loendi mÀÀrab uid - kasutaja, kellele kĂ”ik need sĂ”numid kuuluvad. SĂ”numil on atribuutide komplekt: vestluspartneri identifikaator, tekst, manused ja nii edasi. SĂ”numi identifikaator âkastiâ sees on local_id, see ei muutu kunagi ja mÀÀratakse uute sĂ”numite jaoks jĂ€rjestikku. "Kastid" on sĂ”ltumatud ja neid ei sĂŒnkroonita ĂŒksteisega mootori sees, nendevaheline suhtlus toimub PHP tasemel. Saate vaadata tekstimootori andmestruktuuri ja vĂ”imalusi seestpoolt .

Sellest piisas kahe kasutaja kirjavahetuseks tÀiesti. Arvake Àra, mis edasi juhtus?
2011. aasta mais tutvustas VKontakte vestlusi mitme osalejaga â multivestlust. Nendega töötamiseks lĂ”ime kaks uut klastrit â liikmevestlused ja vestlusliikmed. Esimene salvestab andmeid kasutajate vestluste kohta, teine ââsalvestab andmed kasutajate kohta vestluste kaupa. Lisaks loenditele endile hĂ”lmab see nĂ€iteks kutsuvat kasutajat ja tema vestlusesse lisamise aega.
"PHP, saadame vestlusele sĂ”numi," ĂŒtleb kasutaja.
"Tule nĂŒĂŒd, {username}," ĂŒtleb PHP.

Sellel skeemil on puudusi. SĂŒnkroonimise eest vastutab endiselt PHP. Suured vestlused ja kasutajad, kes saadavad neile samaaegselt sĂ”numeid, on ohtlik lugu. Kuna tekstimootori eksemplar sĂ”ltub kasutajatunnusest, vĂ”ivad vestluses osalejad saada sama sĂ”numi erinevatel aegadel. Sellega vĂ”iks elada, kui areng seisaks. Aga seda ei juhtu.
2015. aasta lĂ”pus lansseerisime kogukonnasĂ”numid ja 2016. aasta alguses nende jaoks API. Suurte vestlusrobotite tulekuga kogukondadesse oli vĂ”imalik unustada koormuse ĂŒhtlane jaotus.
Hea bot genereerib mitu miljonit sĂ”numit pĂ€evas â isegi kĂ”ige jutukamad kasutajad ei saa sellega kiidelda. See tĂ€hendab, et mĂ”ned tekstimootori juhtumid, millel sellised robotid elasid, hakkasid tĂ€iel mÀÀral kannatama.
2016. aasta sĂ”numimootorid on 100 vestlusliikme ja liikme vestluse eksemplari ning 8000 tekstimootorit. Neid majutati tuhandel serveril, millest igaĂŒhel oli 64 GB mĂ€lu. Esimese hĂ€daabinĂ”una suurendasime mĂ€lu veel 32 GB vĂ”rra. Hindasime prognoose. Ilma drastiliste muudatusteta piisaks sellest veel umbes aastaks. Peate hankima riistvara vĂ”i optimeerima andmebaase ise.
Arhitektuuri olemusest tulenevalt on riistvara mĂ”tet suurendada vaid kordades. Ehk siis autode arvu vĂ€hemalt kahekordistamine â ilmselgelt on see ĂŒsna kallis tee. Me optimeerime.
Uus kontseptsioon
Uue lÀhenemisviisi keskne olemus on vestlus. Vestlusel on sellega seotud sÔnumite loend. Kasutajal on vestluste loend.
NÔutav miinimum on kaks uut andmebaasi:
- vestlusmootor. See on vestlusvektorite hoidla. Igal vestlusel on sellega seotud sÔnumite vektor. Igal sÔnumil on vestluses tekst ja kordumatu sÔnumi identifikaator - chat_local_id.
- kasutaja mootor. See on kasutajate vektorite salvestus â kasutajate lingid. Igal kasutajal on peer_id vektor (vestluspartnerid - teised kasutajad, multivestlus vĂ”i kogukonnad) ja sĂ”numite vektor. Igal peer_id-l on sellega seotud sĂ”numite vektor. Igal kirjal on chat_local_id ja selle kasutaja kordumatu sĂ”numi ID â user_local_id.

Uued klastrid suhtlevad omavahel TCP abil â see tagab, et pĂ€ringute jĂ€rjekord ei muutu. PĂ€ringud ise ja nende kinnitused salvestatakse kĂ”vakettale â nii saame pĂ€rast mootori riket vĂ”i taaskĂ€ivitamist igal ajal jĂ€rjekorra oleku taastada. Kuna kasutajamootor ja vestlusmootor on kumbki 4 tuhat killust, jaotatakse pĂ€ringujĂ€rjekord klastrite vahel ĂŒhtlaselt (kuid tegelikult pole seda ĂŒldse - ja see töötab vĂ€ga kiiresti).
Meie andmebaasides kettaga töötamine pĂ”hineb enamikul juhtudel muudatuste binaarlogi (binlog), staatiliste hetktĂ”mmiste ja mĂ€lus oleva osalise kujutise kombinatsioonil. PĂ€eva jooksul tehtud muudatused kirjutatakse binlogi ja perioodiliselt luuakse hetkeseisu hetketĂ”mmis. HetktĂ”mmis on meie eesmĂ€rkide jaoks optimeeritud andmestruktuuride kogum. See koosneb pĂ€isest (pildi metaindeks) ja metafailide komplektist. PĂ€is salvestatakse pĂŒsivalt RAM-i ja see nĂ€itab, kust hetktĂ”mmise andmeid otsida. Iga metafail sisaldab andmeid, mida tĂ”enĂ€oliselt lĂ€heb vaja lĂ€hiajal â nĂ€iteks seoses ĂŒhe kasutajaga. Kui teete andmebaasist pĂ€ringu hetktĂ”mmise pĂ€ise abil, loetakse vajalik metafail ja seejĂ€rel vĂ”etakse arvesse pĂ€rast hetktĂ”mmise loomist toimunud binlogis toimunud muudatusi. Lisateavet selle lĂ€henemisviisi eeliste kohta saate lugeda .
Samal ajal muutuvad kĂ”vaketta enda andmed ainult ĂŒks kord pĂ€evas - Moskvas hilisĂ”htul, kui koormus on minimaalne. TĂ€nu sellele (teades, et ketta struktuur on pĂ€eva jooksul konstantne) saame lubada vektorite asendamist fikseeritud suurusega massiividega - ja tĂ€nu sellele mĂ€lu suurenemist.
SÔnumi saatmine uues skeemis nÀeb vÀlja selline:
- PHP taustaprogramm vĂ”tab kasutajamootoriga ĂŒhendust sĂ”numi saatmise taotlusega.
- user-engine puhverserverib pĂ€ringu soovitud vestlusmootori eksemplarile, mis naaseb kasutajamootori chat_local_id-sse â selles vestluses uue sĂ”numi kordumatuks identifikaatoriks. Chat_engine edastab seejĂ€rel sĂ”numi kĂ”igile vestluses osalevatele adressaatidele.
- user-engine saab vestlusmootorilt chat_local_id ja tagastab PHP-le user_local_id â selle kasutaja kordumatu sĂ”numiidentifikaatori. Seda identifikaatorit kasutatakse siis nĂ€iteks API kaudu sĂ”numitega töötamiseks.

Kuid lisaks sÔnumite saatmisele peate rakendama veel mitmeid olulisi asju:
- Alamloendid on nÀiteks kÔige vÀrskemad sÔnumid, mida nÀete vestlusloendi avamisel. Lugemata kirjad, siltidega kirjad ("TÀhtis", "RÀmpspost" jne).
- SÔnumite tihendamine vestlusmootoris
- SÔnumite vahemÀllu salvestamine kasutajamootoris
- Otsi (kÔigis dialoogides ja konkreetses dialoogis).
- Reaalajas vÀrskendus (Longpolling).
- Ajaloo salvestamine mobiiliklientide vahemÀllu salvestamiseks.
KĂ”ik alamloendid on kiiresti muutuvate struktuuridega. Nendega töötamiseks kasutame . See valik on seletatav asjaoluga, et puu ĂŒlaossa salvestame mĂ”nikord terve segmendi hetktĂ”mmise sĂ”numeid â nĂ€iteks pĂ€rast igaĂ”htust uuesti indekseerimist koosneb puu ĂŒhest tipust, mis sisaldab kĂ”iki alamloendi teateid. Splay puu abil on lihtne sisestada sellise tipu keskele, ilma tasakaalustamisele mĂ”tlemata. Lisaks ei salvesta Splay tarbetuid andmeid, mis sÀÀstab meie mĂ€lu.
SĂ”numid sisaldavad suurt hulka teavet, enamasti teksti, mis on kasulik tihendamiseks. On oluline, et saaksime tĂ€pselt dearhiveerida isegi ĂŒhe ĂŒksiku sĂ”numi. Kasutatakse sĂ”numite tihendamiseks oma heuristikaga - nĂ€iteks teame, et sĂ”numites vahelduvad sĂ”nad "mittesĂ”nadega" - tĂŒhikud, kirjavahemĂ€rgid - ja meenuvad ka mĂ”ned vene keele sĂŒmbolite kasutamise iseĂ€rasused.
Kuna kasutajaid on palju vÀhem kui vestlusi, salvestame juhusliku juurdepÀÀsuga kettapÀringute salvestamiseks vestlusmootorisse sÔnumid vahemÀllu.
SÔnumiotsing rakendatakse diagonaalse pÀringuna kasutajamootorist kÔikidesse vestlusmootori eksemplaridesse, mis sisaldavad selle kasutaja vestlusi. Tulemused kombineeritakse kasutajamootoris endas.
Noh, kĂ”ik ĂŒksikasjad on arvesse vĂ”etud, jÀÀb ĂŒle minna ĂŒle uuele skeemile - ja eelistatavalt ilma, et kasutajad seda mĂ€rkaksid.
Andmete migratsioon
Seega on meil tekstimootor, mis salvestab sÔnumeid kasutajate kaupa, ja kaks klastrit vestlusliikmed ja liikmevestlused, mis salvestavad andmeid mitme jututubade ja neis olevate kasutajate kohta. Kuidas liikuda sellelt uuele kasutaja- ja vestlusmootorile?
Vana skeemi liikmevestlusi kasutati peamiselt optimeerimiseks. Edastasime sealt kiiresti vajalikud andmed chat-liikmetele ja seejÀrel ta enam migratsiooniprotsessis ei osalenud.
JÀrjekord vestlusliikmetele. See sisaldab 100 eksemplari, vestlusmootoril aga 4 tuhat. Andmete edastamiseks peate need vastavusse viima - selleks jagati vestlusliikmed samasse 4 tuhandesse eksemplari ja seejÀrel lubati vestlusmootoris vestlusliikmete binlogi lugemine.

NĂŒĂŒd teab chat-mootor vestlusliikmete multivestlust, kuid ei tea veel midagi kahe vestluskaaslasega peetavast dialoogist. Sellised dialoogid asuvad tekstimootoris, viidates kasutajatele. Siin vĂ”tsime andmed otse ette: iga vestlusmootori eksemplar kĂŒsis kĂ”igilt tekstimootori eksemplaridelt, kas neil on vajalik dialoog.
SuurepĂ€rane â vestlusmootor teab, millised multi-chat-vestlused on olemas, ja teab, millised dialoogid seal on.
Peate kombineerima sĂ”numid mitme vestlusega vestlustes, nii et saate igas vestluses kirjade loendi. Esiteks hangib vestlusmootor tekstimootorist kĂ”ik kasutajate sĂ”numid sellest vestlusest. MĂ”nel juhul on neid ĂŒsna palju (kuni sadu miljoneid), kuid vĂ€ga harvade eranditega mahub vestlus tĂ€ielikult RAM-i. Meil on jĂ€rjestamata sĂ”numeid, millest igaĂŒks on mitmes eksemplaris â lĂ”ppude lĂ”puks on need kĂ”ik vĂ”etud erinevatest kasutajatele vastavatest tekstimootori eksemplaridest. EesmĂ€rk on sorteerida sĂ”numeid ja vabaneda koopiatest, mis vĂ”tavad tarbetult ruumi.
Igal sĂ”numil on ajatempel, mis sisaldab saatmisaega ja teksti. Kasutame aega sorteerimiseks â asetame viidad multivestluses osalejate vanimatele sĂ”numitele ja vĂ”rdleme kavandatavate koopiate tekstide rĂ€si, liikudes ajatempli suurendamise suunas. On loogiline, et koopiatel on sama rĂ€si ja ajatempel, kuid praktikas pole see alati nii. Nagu mĂ€letate, viis vanas skeemis sĂŒnkroonimise lĂ€bi PHP - ja harvadel juhtudel oli sama sĂ”numi saatmise aeg erinevatel kasutajatel erinev. Sellistel juhtudel lubasime ajatemplit muuta â tavaliselt sekundi jooksul. Teine probleem on sĂ”numite erinev jĂ€rjestus erinevatele adressaatidele. Sellistel juhtudel lubasime luua lisakoopia, millel on erinevatele kasutajatele erinevad tellimisvĂ”imalused.
PÀrast seda saadetakse andmed multivestluse sÔnumite kohta kasutajamootorisse. Ja siit tuleb imporditud sÔnumite ebameeldiv omadus. Tavatöös jÀrjestatakse mootorisse saabuvad sÔnumid kasutaja_kohalik_id jÀrgi rangelt kasvavas jÀrjekorras. Vanast mootorist kasutajamootorisse imporditud sÔnumid kaotasid selle kasuliku omaduse. Samas peab testimise mugavuse huvides saama neile kiiresti ligi pÀÀseda, sealt midagi otsida ja uusi lisada.
Imporditud sÔnumite salvestamiseks kasutame spetsiaalset andmestruktuuri.
See tÀhistab suuruse vektorit
kus kÔik on
- on erinevad ja jÀrjestatud kahanevas jÀrjekorras, elementide erijÀrjekorraga. Igas segmendis koos indeksitega
elemendid on sorteeritud. Sellises struktuuris elemendi otsimine vÔtab aega
lÀbi
binaarsed otsingud. Elemendi lisandumine amortiseeritakse ĂŒle
.
Niisiis, mĂ”tlesime vĂ€lja, kuidas andmeid vanadelt mootoritelt uutele ĂŒle kanda. Kuid see protsess vĂ”tab mitu pĂ€eva â ja on ebatĂ”enĂ€oline, et nende pĂ€evade jooksul meie kasutajad ĂŒksteisele kirjutamise harjumusest loobuksid. Et selle aja jooksul sĂ”numeid mitte kaotada, lĂ€heme ĂŒle tööskeemile, mis kasutab nii vanu kui ka uusi klastreid.
Andmed kirjutatakse vestlusliikmetele ja kasutajamootorisse (ja mitte tekstimootorisse, nagu vana skeemi jĂ€rgi tavatöös). user-engine puhverdab taotluse chat-mootorile â ja siin sĂ”ltub kĂ€itumine sellest, kas see vestlus on juba liidetud vĂ”i mitte. Kui vestlust pole veel liidetud, ei kirjuta vestlusmootor sĂ”numit endale ja selle töötlemine toimub ainult tekstimootoris. Kui vestlus on juba vestlusmootoriga liidetud, tagastab see kasutajamootorile chat_local_id ja saadab sĂ”numi kĂ”igile adressaatidele. user-engine puhverdab kĂ”ik andmed tekstimootorisse â nii et kui midagi juhtub, saame alati tagasi kerida, kuna kĂ”ik praegused andmed on vanas mootoris. text-engine tagastab user_local_id, mille kasutajamootor salvestab ja naaseb taustaprogrammi.

Selle tulemusena nĂ€eb ĂŒleminekuprotsess vĂ€lja jĂ€rgmine: ĂŒhendame tĂŒhjad kasutaja-mootori ja vestlusmootori klastrid. chat-mootor loeb kogu vestlusliikmete binlogi, seejĂ€rel algab puhverserver vastavalt ĂŒlalkirjeldatud skeemile. Edastame vanad andmed ja saame kaks sĂŒnkroniseeritud klastrit (vana ja uus). JÀÀb vaid lĂŒlitada lugemine tekstimootorilt kasutajamootorile ja keelata puhverserver.
JĂ€reldused
TĂ€nu uuele lĂ€henemisele on tĂ€iustatud mootorite kĂ”iki jĂ”udlusnĂ€itajaid ja lahendatud probleemid andmete jĂ€rjepidevusega. NĂŒĂŒd saame sĂ”numitesse kiiresti uusi funktsioone juurutada (ja oleme seda juba tegema hakanud â suurendasime vestluses osalejate maksimaalset arvu, rakendasime edasisaadetud sĂ”numite otsingu, kĂ€ivitasime kinnitatud sĂ”numid ja tĂ”stsime kasutaja kohta sĂ”numite koguarvu limiiti) .
Muutused loogikas on tÔesti tohutud. Ja ma tahaksin mÀrkida, et see ei tÀhenda alati terveid aastaid tohutu meeskonna arendustööd ja lugematuid koodiridu. vestlusmootor ja kasutajamootor koos kÔigi lisalugudega, nagu Huffman sÔnumite tihendamiseks, esituspuud ja imporditud sÔnumite struktuur, on alla 20 tuhande koodirea. Ja need kirjutasid 3 arendajat vaid 10 kuuga (tasub aga meeles pidada, et - maailmameistrid ).
Veelgi enam, serverite arvu kahekordistamise asemel vĂ€hendasime nende arvu poole vĂ”rra â nĂŒĂŒd töötavad kasutaja- ja vestlusmootor 500 fĂŒĂŒsilisel masinal, samas kui uuel skeemil on palju koormust. SÀÀstsime palju raha seadmete pealt â umbes 5 miljonit dollarit + 750 tuhat dollarit aastas tegevuskuludelt.
PĂŒĂŒame leida parimaid lahendusi kĂ”ige keerukamatele ja suuremahulistele probleemidele. Meil on neid palju â seepĂ€rast otsime andmebaasiosakonda andekaid arendajaid. Kui Sulle meeldib ja oskad selliseid probleeme lahendada, tunned suurepĂ€raselt algoritme ja andmestruktuurisid, kutsume Sind meeskonnaga liituma. VĂ”tke meiega ĂŒhendust ĂŒksikasjade saamiseks.
Isegi kui see lugu ei puuduta teid, pange tÀhele, et hindame soovitusi. RÀÀgi sellest sÔbrale , ja kui ta katseaja edukalt lÀbib, saate boonust 100 tuhat rubla.
Allikas: www.habr.com
