Andika upya hifadhidata ya ujumbe wa VKontakte kutoka mwanzo na uishi

Watumiaji wetu huandikiana ujumbe bila kujua uchovu.
Andika upya hifadhidata ya ujumbe wa VKontakte kutoka mwanzo na uishi
Hiyo ni mengi sana. Ikiwa ungepanga kusoma jumbe zote za watumiaji wote, itachukua zaidi ya miaka 150 elfu. Isipokuwa wewe ni msomaji wa hali ya juu na usitumie zaidi ya sekunde moja kwa kila ujumbe.

Kwa idadi kama hiyo ya data, ni muhimu kwamba mantiki ya kuhifadhi na kuipata ijengwe kikamilifu. Vinginevyo, katika wakati mmoja sio wa kushangaza, inaweza kuwa wazi kuwa kila kitu kitaenda vibaya hivi karibuni.

Kwa sisi, wakati huu ulikuja mwaka mmoja na nusu uliopita. Jinsi tulivyofika kwa hili na kile kilichotokea mwishoni - tunakuambia kwa utaratibu.

Asili

Katika utekelezaji wa kwanza kabisa, ujumbe wa VKontakte ulifanya kazi kwenye mchanganyiko wa PHP backend na MySQL. Hili ni suluhisho la kawaida kabisa kwa tovuti ndogo ya wanafunzi. Hata hivyo, tovuti hii ilikua bila kudhibitiwa na kuanza kudai uboreshaji wa miundo ya data yenyewe.

Mwisho wa 2009, kumbukumbu ya kwanza ya injini ya maandishi iliandikwa, na mnamo 2010 ujumbe ulihamishiwa kwake.

Katika injini ya maandishi, ujumbe ulihifadhiwa katika orodha - aina ya "sanduku za barua". Kila orodha kama hii inaamuliwa na uid - mtumiaji ambaye anamiliki jumbe hizi zote. Ujumbe una seti ya sifa: kitambulisho cha interlocutor, maandishi, viambatisho, na kadhalika. Kitambulisho cha ujumbe ndani ya "kisanduku" ni local_id, hakibadiliki na huwekwa kwa mpangilio kwa ujumbe mpya. "Sanduku" ni huru na hazijasawazishwa na kila mmoja ndani ya injini; mawasiliano kati yao hutokea kwa kiwango cha PHP. Unaweza kuangalia muundo wa data na uwezo wa injini ya maandishi kutoka ndani hapa.
Andika upya hifadhidata ya ujumbe wa VKontakte kutoka mwanzo na uishi
Hii ilitosha kwa mawasiliano kati ya watumiaji wawili. Nadhani nini kilifanyika baadaye?

Mnamo Mei 2011, VKontakte ilianzisha mazungumzo na washiriki kadhaa-mazungumzo mengi. Ili kufanya kazi nao, tulikuza makundi mawili mapya - gumzo za wanachama na wanachama wa gumzo. Ya kwanza huhifadhi data kuhusu gumzo na watumiaji, ya pili huhifadhi data kuhusu watumiaji kwa gumzo. Mbali na orodha zenyewe, hii inajumuisha, kwa mfano, mtumiaji anayealika na wakati waliongezwa kwenye gumzo.

"PHP, wacha tutume ujumbe kwenye gumzo," mtumiaji anasema.
"Njoo, {jina la mtumiaji}," inasema PHP.
Andika upya hifadhidata ya ujumbe wa VKontakte kutoka mwanzo na uishi
Kuna hasara za mpango huu. Usawazishaji bado ni jukumu la PHP. Gumzo kubwa na watumiaji ambao hutuma ujumbe kwao kwa wakati mmoja ni hadithi hatari. Kwa kuwa mfano wa injini ya maandishi hutegemea uid, washiriki wa gumzo wanaweza kupokea ujumbe sawa kwa nyakati tofauti. Mtu anaweza kuishi na hii ikiwa maendeleo yangesimama. Lakini hilo halitafanyika.

Mwishoni mwa 2015, tulizindua jumbe za jumuiya, na mwanzoni mwa 2016, tulizindua API kwa ajili yao. Pamoja na ujio wa chatbots kubwa katika jamii, iliwezekana kusahau kuhusu usambazaji wa mzigo.

Kijibu kizuri hutoa ujumbe milioni kadhaa kwa siku - hata watumiaji wanaozungumza zaidi hawawezi kujivunia hili. Hii ina maana kwamba baadhi ya matukio ya injini ya maandishi, ambayo roboti hizo ziliishi, zilianza kuteseka kwa ukamilifu.

Mitambo ya kutuma ujumbe mwaka wa 2016 ni matukio 100 ya wanachat na gumzo za wanachama, na injini za maandishi 8000. Walikaribishwa kwenye seva elfu, kila moja ikiwa na kumbukumbu ya 64 GB. Kama hatua ya kwanza ya dharura, tuliongeza kumbukumbu kwa GB 32 nyingine. Tulikadiria utabiri. Bila mabadiliko makubwa, hii ingetosha kwa takriban mwaka mwingine. Unahitaji ama kupata vifaa au kuboresha hifadhidata zenyewe.

Kwa sababu ya asili ya usanifu, ni mantiki tu kuongeza vifaa katika anuwai. Hiyo ni, angalau mara mbili ya idadi ya magari - ni wazi, hii ni njia ya gharama kubwa. Tutaboresha.

Dhana mpya

Kiini kikuu cha mbinu mpya ni gumzo. Gumzo lina orodha ya ujumbe unaohusiana nayo. Mtumiaji ana orodha ya mazungumzo.

Kima cha chini kinachohitajika ni hifadhidata mbili mpya:

  • injini ya mazungumzo. Hili ni hifadhi ya vekta za gumzo. Kila soga ina vekta ya ujumbe unaohusiana nayo. Kila ujumbe una maandishi na kitambulisho cha kipekee cha ujumbe ndani ya gumzo - chat_local_id.
  • injini ya mtumiaji. Hii ni hifadhi ya vekta za watumiaji - viungo kwa watumiaji. Kila mtumiaji ana vekta ya peer_id (interlocutors - watumiaji wengine, gumzo nyingi au jumuiya) na vekta ya ujumbe. Kila peer_id ina vekta ya ujumbe unaohusiana nayo. Kila ujumbe una kitambulisho_cha_cha_cha_cha_cha_chat_na kitambulisho cha kipekee cha ujumbe kwa mtumiaji huyo - kitambulisho_cha_cha_cha_cha_cha_cha_cha_cha_cha_cha_cha_cha________

Andika upya hifadhidata ya ujumbe wa VKontakte kutoka mwanzo na uishi
Vikundi vipya vinawasiliana kwa kutumia TCP - hii inahakikisha kwamba mpangilio wa maombi haubadilika. Maombi yenyewe na uthibitisho kwao yameandikwa kwenye gari ngumu - ili tuweze kurejesha hali ya foleni wakati wowote baada ya kushindwa au kuanzisha upya injini. Kwa kuwa injini ya mtumiaji na injini ya mazungumzo ni shards elfu 4 kila moja, foleni ya ombi kati ya nguzo itasambazwa sawasawa (lakini kwa kweli hakuna kabisa - na inafanya kazi haraka sana).

Kufanya kazi na diski katika hifadhidata zetu mara nyingi kunategemea mchanganyiko wa logi ya mabadiliko (binlog), vijipicha tuli na picha ya sehemu kwenye kumbukumbu. Mabadiliko wakati wa mchana yameandikwa kwa binlog, na muhtasari wa hali ya sasa huundwa mara kwa mara. Muhtasari ni mkusanyiko wa miundo ya data iliyoboreshwa kwa madhumuni yetu. Inajumuisha kichwa (metaindex ya picha) na seti ya metafiles. Kijajuu kinahifadhiwa kwenye RAM na kinaonyesha mahali pa kutafuta data kutoka kwa muhtasari. Kila metafile inajumuisha data ambayo ina uwezekano wa kuhitajika kwa wakati unaofaaβ€”kwa mfano, inayohusiana na mtumiaji mmoja. Unapouliza hifadhidata kwa kutumia kichwa cha snapshot, metafile inayohitajika inasomwa, na kisha mabadiliko katika binlog yaliyotokea baada ya snapshot kuundwa yanazingatiwa. Unaweza kusoma zaidi juu ya faida za njia hii hapa.

Wakati huo huo, data kwenye gari ngumu yenyewe hubadilika mara moja tu kwa siku - mwishoni mwa usiku huko Moscow, wakati mzigo ni mdogo. Shukrani kwa hili (tukijua kwamba muundo kwenye diski ni mara kwa mara siku nzima), tunaweza kumudu kuchukua nafasi ya vectors na safu za ukubwa uliowekwa - na kutokana na hili, kupata kumbukumbu.

Kutuma ujumbe katika mpango mpya kunaonekana kama hii:

  1. Mazingira ya nyuma ya PHP huwasiliana na injini ya mtumiaji na ombi la kutuma ujumbe.
  2. injini ya mtumiaji huwakilisha ombi kwa mfano unaohitajika wa injini ya gumzo, ambayo inarudi kwa mtumiaji-injini chat_local_id - kitambulisho cha kipekee cha ujumbe mpya ndani ya gumzo hili. Chat_engine kisha inatangaza ujumbe kwa wapokeaji wote kwenye gumzo.
  3. user-engine hupokea chat_local_id kutoka kwa chat-engine na kurudisha user_local_id kwa PHP - kitambulisho cha kipekee cha ujumbe kwa mtumiaji huyu. Kitambulisho hiki kisha hutumiwa, kwa mfano, kufanya kazi na ujumbe kupitia API.

Andika upya hifadhidata ya ujumbe wa VKontakte kutoka mwanzo na uishi
Lakini pamoja na kutuma ujumbe, unahitaji kutekeleza mambo machache muhimu zaidi:

  • Orodha ndogo ni, kwa mfano, jumbe za hivi punde zaidi unazoziona unapofungua orodha ya mazungumzo. Ujumbe ambao haujasomwa, ujumbe wenye lebo ("Muhimu", "Taka", nk).
  • Kufinyiza ujumbe katika injini ya gumzo
  • Inahifadhi ujumbe katika injini ya mtumiaji
  • Tafuta (kupitia mazungumzo yote na ndani ya moja maalum).
  • Sasisho la wakati halisi (Longpolling).
  • Kuhifadhi historia ili kutekeleza akiba kwenye wateja wa simu.

Orodha zote ndogo ni miundo inayobadilika haraka. Kufanya kazi nao tunatumia Splay miti. Chaguo hili linafafanuliwa na ukweli kwamba juu ya mti sisi wakati mwingine huhifadhi sehemu nzima ya ujumbe kutoka kwa muhtasari - kwa mfano, baada ya kuashiria tena usiku, mti una sehemu moja ya juu, ambayo ina ujumbe wote wa orodha ndogo. Mti wa Splay hufanya iwe rahisi kuingiza katikati ya vertex kama hiyo bila kufikiria kusawazisha. Kwa kuongeza, Splay haihifadhi data isiyohitajika, ambayo inatuokoa kumbukumbu.

Ujumbe unahusisha kiasi kikubwa cha habari, hasa maandishi, ambayo ni muhimu kuweza kubana. Ni muhimu kwamba tunaweza kufuta kwa usahihi hata ujumbe mmoja wa mtu binafsi. Inatumika kubana ujumbe Algorithm ya Huffman na heuristics zetu wenyewe - kwa mfano, tunajua kuwa katika ujumbe maneno hubadilishana na "yasiyo ya maneno" - nafasi, alama za uakifishaji - na pia tunakumbuka sifa zingine za kutumia alama kwa lugha ya Kirusi.

Kwa kuwa kuna watumiaji wachache zaidi kuliko gumzo, ili kuhifadhi maombi ya diski ya ufikiaji bila mpangilio katika injini ya gumzo, tunahifadhi ujumbe katika injini ya mtumiaji.

Utafutaji wa ujumbe unatekelezwa kama swali la mshazari kutoka kwa injini ya mtumiaji hadi matukio yote ya injini ya gumzo ambayo yana soga za mtumiaji huyu. Matokeo yanajumuishwa katika injini ya mtumiaji yenyewe.

Kweli, maelezo yote yamezingatiwa, kilichobaki ni kubadili kwa mpango mpya - na ikiwezekana bila watumiaji kugundua.

Uhamiaji wa data

Kwa hivyo, tunayo injini ya maandishi ambayo huhifadhi ujumbe kulingana na mtumiaji, na vikundi viwili vya wanachama wa gumzo na gumzo za wanachama ambazo huhifadhi data kuhusu vyumba vya gumzo nyingi na watumiaji waliomo. Jinsi ya kuhama kutoka kwa hii hadi kwa injini mpya ya mtumiaji na injini ya gumzo?

gumzo za wanachama katika mpango wa zamani zilitumika kimsingi kwa uboreshaji. Tulihamisha kwa haraka data muhimu kutoka kwayo hadi kwa wanachat, na kisha haikushiriki tena katika mchakato wa uhamiaji.

Foleni kwa wanachat. Inajumuisha matukio 100, wakati injini ya mazungumzo ina 4 elfu. Ili kuhamisha data, unahitaji kuileta katika kufuata - kwa hili, washiriki wa gumzo waligawanywa katika nakala sawa elfu 4, na kisha usomaji wa binlog ya washiriki wa gumzo uliwezeshwa kwenye injini ya gumzo.
Andika upya hifadhidata ya ujumbe wa VKontakte kutoka mwanzo na uishi
Sasa injini ya gumzo inajua kuhusu gumzo nyingi kutoka kwa washiriki wa gumzo, lakini bado haijui chochote kuhusu mazungumzo na waingiliaji wawili. Mijadala kama hii iko kwenye injini ya maandishi kwa kurejelea watumiaji. Hapa tulichukua data "kichwa": kila mfano wa injini ya gumzo uliuliza matukio yote ya injini ya maandishi ikiwa walikuwa na mazungumzo yanayohitaji.

Kubwa - injini ya gumzo inajua ni gumzo gani za gumzo nyingi na inajua mazungumzo yaliyopo.
Unahitaji kuchanganya ujumbe katika gumzo la gumzo nyingi ili upate orodha ya ujumbe katika kila soga. Kwanza, injini ya gumzo hurejesha kutoka kwa injini ya maandishi ujumbe wote wa mtumiaji kutoka kwenye gumzo hili. Katika baadhi ya matukio kuna mengi sana (hadi mamia ya mamilioni), lakini isipokuwa nadra sana mazungumzo yanafaa kabisa kwenye RAM. Tuna ujumbe ambao haujapangwa, kila moja katika nakala kadhaa - baada ya yote, zote hutolewa kutoka kwa matukio tofauti ya injini ya maandishi yanayolingana na watumiaji. Lengo ni kupanga ujumbe na kuondoa nakala zinazochukua nafasi isiyo ya lazima.

Kila ujumbe una muhuri wa muda ulio na muda uliotumwa na maandishi. Tunatumia wakati kupanga - tunaweka viashiria kwa jumbe kongwe zaidi za washiriki wa gumzo nyingi na kulinganisha heshi kutoka kwa maandishi ya nakala zinazokusudiwa, tukielekea kwenye muhuri wa muda unaoongezeka. Ni sawa kwamba nakala zitakuwa na hashi sawa na muhuri wa wakati, lakini kwa mazoezi hii sio hivyo kila wakati. Kama unavyokumbuka, maingiliano katika mpango wa zamani ulifanywa na PHP - na katika hali nadra, wakati wa kutuma ujumbe huo ulitofautiana kati ya watumiaji tofauti. Katika hali hizi, tulijiruhusu kuhariri muhuri wa muda - kwa kawaida ndani ya sekunde moja. Tatizo la pili ni mpangilio tofauti wa ujumbe kwa wapokeaji tofauti. Katika hali kama hizi, tuliruhusu nakala ya ziada kuundwa, na chaguo tofauti za kuagiza kwa watumiaji tofauti.

Baada ya hayo, data kuhusu ujumbe katika multichat hutumwa kwa injini ya mtumiaji. Na hapa inakuja kipengele kisichopendeza cha ujumbe ulioingizwa. Katika utendakazi wa kawaida, jumbe zinazokuja kwa injini hupangwa kwa utaratibu wa kupanda na user_local_id. Ujumbe ulioingizwa kutoka kwa injini kuu hadi injini ya mtumiaji ulipoteza sifa hii muhimu. Wakati huo huo, kwa urahisi wa kupima, unahitaji kuwa na uwezo wa kuzifikia haraka, tafuta kitu ndani yao na kuongeza mpya.

Tunatumia muundo maalum wa data kuhifadhi ujumbe ulioingizwa.

Inawakilisha vector ya ukubwa Andika upya hifadhidata ya ujumbe wa VKontakte kutoka mwanzo na uishikila mtu yuko wapi Andika upya hifadhidata ya ujumbe wa VKontakte kutoka mwanzo na uishi - ni tofauti na kuamuru kwa utaratibu wa kushuka, na utaratibu maalum wa vipengele. Katika kila sehemu na fahirisi Andika upya hifadhidata ya ujumbe wa VKontakte kutoka mwanzo na uishi vipengele vimepangwa. Kutafuta kipengele katika muundo huo huchukua muda Andika upya hifadhidata ya ujumbe wa VKontakte kutoka mwanzo na uishi kupitia Andika upya hifadhidata ya ujumbe wa VKontakte kutoka mwanzo na uishi utafutaji wa binary. Nyongeza ya kipengele imepunguzwa Andika upya hifadhidata ya ujumbe wa VKontakte kutoka mwanzo na uishi.

Kwa hivyo, tuligundua jinsi ya kuhamisha data kutoka kwa injini za zamani hadi mpya. Lakini mchakato huu unachukua siku kadhaa - na hakuna uwezekano kwamba wakati wa siku hizi watumiaji wetu wataacha tabia ya kuandika kwa kila mmoja. Ili usipoteze ujumbe wakati huu, tunabadilisha hadi mpango wa kazi unaotumia makundi ya zamani na mapya.

Data imeandikwa kwa wanachama-chat na user-injini (na si kwa maandishi-injini, kama katika operesheni ya kawaida kulingana na mpango wa zamani). injini ya mtumiaji huwakilisha ombi la injini ya gumzo - na hapa tabia inategemea kama soga hii tayari imeunganishwa au la. Ikiwa mazungumzo bado hayajaunganishwa, injini ya mazungumzo haiandiki ujumbe yenyewe, na usindikaji wake hutokea tu kwenye injini ya maandishi. Ikiwa soga tayari imeunganishwa kuwa chat-engine, inarudisha chat_local_id kwa mtumiaji-injini na kutuma ujumbe kwa wapokeaji wote. watumiaji-injini ya seva proksi data zote kwa injini ya maandishi - ili jambo likitokea, tunaweza kurudi nyuma kila wakati, tukiwa na data yote ya sasa katika injini ya zamani. text-engine hurejesha user_local_id, ambayo mtumiaji-injini huhifadhi na kurudi nyuma.
Andika upya hifadhidata ya ujumbe wa VKontakte kutoka mwanzo na uishi
Kwa hivyo, mchakato wa mpito unaonekana kama hii: tunaunganisha makundi tupu ya injini ya mtumiaji na injini ya gumzo. chat-engine husoma binlog nzima ya washiriki wa gumzo, kisha uwakilishi huanza kulingana na mpango uliofafanuliwa hapo juu. Tunahamisha data ya zamani na kupata nguzo mbili zilizosawazishwa (zamani na mpya). Kilichosalia ni kubadili usomaji kutoka kwa injini ya maandishi hadi injini ya mtumiaji na kuzima utumishi wa seva mbadala.

Matokeo

Shukrani kwa mbinu mpya, vipimo vyote vya utendaji vya injini vimeboreshwa na matatizo ya uwiano wa data yametatuliwa. Sasa tunaweza kutekeleza vipengele vipya kwa haraka katika ujumbe (na tayari tumeanza kufanya hivi - tuliongeza idadi ya juu zaidi ya washiriki wa gumzo, tukatekeleza utafutaji wa ujumbe uliotumwa, tukazindua ujumbe uliobandikwa na kuongeza kikomo cha idadi ya ujumbe kwa kila mtumiaji) .

Mabadiliko katika mantiki ni makubwa sana. Na ningependa kutambua kuwa hii haimaanishi kila wakati miaka nzima ya maendeleo na timu kubwa na maelfu ya mistari ya nambari. injini ya gumzo na injini ya mtumiaji pamoja na hadithi zote za ziada kama vile Huffman ya kubana ujumbe, Splay miti na muundo wa ujumbe ulioagizwa ni chini ya mistari elfu 20 ya msimbo. Na ziliandikwa na watengenezaji 3 ndani ya miezi 10 tu (hata hivyo, inafaa kukumbuka kuwa wote tatu msanidi programu - mabingwa wa dunia katika programu za michezo).

Zaidi ya hayo, badala ya kuongeza idadi ya seva mara mbili, tulipunguza idadi yao kwa nusu - sasa injini ya mtumiaji na injini ya mazungumzo inaishi kwenye mashine 500 za kawaida, wakati mpango mpya una chumba kikubwa cha kupakia. Tuliokoa pesa nyingi kwenye vifaa - karibu dola milioni 5 + $ 750 kwa mwaka katika gharama za uendeshaji.

Tunajitahidi kupata suluhisho bora kwa shida ngumu zaidi na kubwa. Tunayo mengi - na ndiyo maana tunatafuta watengenezaji wenye vipaji katika idara ya hifadhidata. Ikiwa unapenda na unajua jinsi ya kutatua matatizo kama haya, kuwa na ujuzi bora wa algoriti na miundo ya data, tunakualika ujiunge na timu. Wasiliana nasi HRkwa maelezo.

Hata kama hadithi hii haikuhusu, tafadhali kumbuka kuwa tunathamini mapendekezo. Mwambie rafiki kuhusu nafasi za kazi za msanidi programu, na ikiwa atamaliza kipindi cha majaribio kwa mafanikio, utapokea bonasi ya rubles elfu 100.

Chanzo: mapenzi.com

Kuongeza maoni