VKontakte xabarlar bazasini noldan qayta yozing va omon qoling

Bizning foydalanuvchilarimiz charchoqni bilmasdan bir-birlariga xabar yozishadi.
VKontakte xabarlar bazasini noldan qayta yozing va omon qoling
Bu juda ko'p. Agar siz barcha foydalanuvchilarning barcha xabarlarini o'qishga kirishgan bo'lsangiz, bu 150 ming yildan ko'proq vaqtni oladi. Agar siz juda rivojlangan o'quvchi bo'lsangiz va har bir xabarga bir soniyadan ko'proq vaqt sarflamasangiz.

Bunday hajmdagi ma'lumotlar bilan ularni saqlash va ularga kirish mantig'i optimal tarzda tuzilganligi juda muhimdir. Aks holda, unchalik ajoyib bo'lmagan bir daqiqada hamma narsa tez orada noto'g'ri ketishi aniq bo'lishi mumkin.

Biz uchun bu daqiqa bir yarim yil oldin keldi. Biz bunga qanday keldik va oxirida nima bo'ldi - biz sizga tartibda aytamiz.

ishi tarixi

Birinchi amalga oshirishda VKontakte xabarlari PHP backend va MySQL kombinatsiyasida ishladi. Bu kichik talaba veb-sayti uchun mutlaqo normal yechim. Biroq, bu sayt nazoratsiz o'sdi va o'zi uchun ma'lumotlar tuzilmalarini optimallashtirishni talab qila boshladi.

2009 yil oxirida birinchi matnli vosita ombori yozildi va 2010 yilda unga xabarlar o'tkazildi.

Matnli tizimda xabarlar ro'yxatlarda - "pochta qutilari" turida saqlangan. Har bir bunday ro'yxat uid tomonidan belgilanadi - bu barcha xabarlarga ega bo'lgan foydalanuvchi. Xabar bir qator atributlarga ega: suhbatdosh identifikatori, matn, qo'shimchalar va boshqalar. "Quti" ichidagi xabar identifikatori local_id bo'lib, u hech qachon o'zgarmaydi va yangi xabarlar uchun ketma-ket tayinlanadi. "Qutilar" mustaqil va dvigatel ichida bir-biri bilan sinxronlashtirilmaydi, ular orasidagi aloqa PHP darajasida sodir bo'ladi. Siz matn mexanizmining ma'lumotlar tuzilishi va imkoniyatlarini ichkaridan ko'rishingiz mumkin shu yerda.
VKontakte xabarlar bazasini noldan qayta yozing va omon qoling
Bu ikki foydalanuvchi o'rtasidagi yozishmalar uchun etarli edi. Tasavvur qiling, keyin nima bo'ldi?

2011 yil may oyida "VKontakte" bir nechta ishtirokchilar bilan suhbatlarni taqdim etdi - ko'p suhbat. Ular bilan ishlash uchun biz ikkita yangi klaster yaratdik - a'zo-chatlar va chat-a'zolari. Birinchisi foydalanuvchilarning suhbatlari haqidagi ma'lumotlarni saqlaydi, ikkinchisi chatlar orqali foydalanuvchilar haqidagi ma'lumotlarni saqlaydi. Ro'yxatlarning o'ziga qo'shimcha ravishda, bu, masalan, taklif qiluvchi foydalanuvchi va ular suhbatga qo'shilgan vaqtni o'z ichiga oladi.

"PHP, keling, chatga xabar yuboramiz", deydi foydalanuvchi.
β€œKeling, {username}”, deydi PHP.
VKontakte xabarlar bazasini noldan qayta yozing va omon qoling
Ushbu sxemaning kamchiliklari mavjud. Sinxronizatsiya hali ham PHP ning javobgarligi. Katta chatlar va ularga bir vaqtning o'zida xabar yuboradigan foydalanuvchilar xavfli voqeadir. Matn mexanizmi namunasi foydalanuvchi identifikatoriga bog'liq bo'lganligi sababli, chat ishtirokchilari bir xil xabarni turli vaqtlarda olishlari mumkin. Agar taraqqiyot to'xtamasa, bu bilan yashash mumkin edi. Lekin bu sodir bo'lmaydi.

2015-yil oxirida biz hamjamiyat xabarlarini ishga tushirdik va 2016-yil boshida biz ular uchun API-ni ishga tushirdik. Jamiyatlarda katta chatbotlarning paydo bo'lishi bilan, hatto yuk taqsimotini ham unutish mumkin edi.

Yaxshi bot kuniga bir necha million xabarlarni ishlab chiqaradi - hatto eng suhbatdosh foydalanuvchilar ham bu bilan maqtana olmaydi. Bu shuni anglatadiki, bunday botlar yashagan matn mexanizmining ba'zi holatlari to'liq azob cheka boshladi.

2016-yilda xabar mexanizmlari chat a'zolari va a'zolar chatlarining 100 ta nusxasi va 8000 matnli mexanizmlardir. Ular har biri 64 Gb xotiraga ega bo'lgan mingta serverda joylashtirilgan. Birinchi favqulodda chora sifatida biz xotirani yana 32 GB ga oshirdik. Biz prognozlarni baholadik. Keskin o'zgarishlarsiz bu yana bir yil uchun etarli bo'ladi. Uskunani qo'lga kiritishingiz yoki ma'lumotlar bazalarini optimallashtirishingiz kerak.

Arxitekturaning tabiatiga ko'ra, faqat apparatni bir necha marta oshirish mantiqan. Ya'ni, mashinalar sonini kamida ikki baravar oshirish - shubhasiz, bu juda qimmat yo'l. Biz optimallashtiramiz.

Yangi kontseptsiya

Yangi yondashuvning markaziy mohiyati suhbatdir. Chatda unga tegishli xabarlar ro'yxati mavjud. Foydalanuvchi chatlar ro'yxatiga ega.

Minimal talab - ikkita yangi ma'lumotlar bazasi:

  • suhbat mexanizmi. Bu chat vektorlari ombori. Har bir suhbatda unga tegishli xabarlar vektori mavjud. Har bir xabarda matn va chat ichida noyob xabar identifikatori mavjud - chat_local_id.
  • foydalanuvchi dvigateli. Bu foydalanuvchi vektorlarini saqlash joyi - foydalanuvchilarga havolalar. Har bir foydalanuvchi peer_id vektori (suhbatdoshlar - boshqa foydalanuvchilar, multi-chat yoki jamoalar) va xabarlar vektoriga ega. Har bir peer_id o'ziga tegishli xabarlar vektoriga ega. Har bir xabarda chat_local_id va ushbu foydalanuvchi uchun noyob xabar identifikatori mavjud - user_local_id.

VKontakte xabarlar bazasini noldan qayta yozing va omon qoling
Yangi klasterlar TCP yordamida bir-biri bilan muloqot qiladi - bu so'rovlar tartibi o'zgarmasligini ta'minlaydi. So'rovlarning o'zi va ular uchun tasdiqlar qattiq diskda qayd etiladi - shuning uchun biz dvigatelning ishlamay qolishi yoki qayta ishga tushirilishidan keyin istalgan vaqtda navbat holatini tiklashimiz mumkin. Foydalanuvchi dvigateli va chat-motori har biri 4 ming parcha bo'lganligi sababli, klasterlar orasidagi so'rovlar navbati teng ravishda taqsimlanadi (lekin aslida ular umuman yo'q - va u juda tez ishlaydi).

Bizning ma'lumotlar bazalarimizda disk bilan ishlash ko'p hollarda o'zgarishlarning ikkilik jurnali (binlog), statik suratlar va xotiradagi qisman tasvirning kombinatsiyasiga asoslanadi. Kun davomidagi o'zgarishlar binlogga yoziladi va vaqti-vaqti bilan joriy holatning surati yaratiladi. Snapshot - bu bizning maqsadlarimiz uchun optimallashtirilgan ma'lumotlar tuzilmalari to'plami. U sarlavha (tasvir metaindeksi) va metafayllar to'plamidan iborat. Sarlavha doimiy ravishda RAMda saqlanadi va oniy tasvirdan ma'lumotlarni qaerdan qidirish kerakligini ko'rsatadi. Har bir metafayl yaqin vaqtda kerak bo'lishi mumkin bo'lgan ma'lumotlarni o'z ichiga oladi, masalan, bitta foydalanuvchi bilan bog'liq. Surat sarlavhasi yordamida ma'lumotlar bazasiga so'rov o'tkazganingizda, kerakli metafayl o'qiladi va keyin oniy tasvir yaratilgandan keyin binlogdagi o'zgarishlar hisobga olinadi. Ushbu yondashuvning afzalliklari haqida ko'proq o'qishingiz mumkin shu yerda.

Shu bilan birga, qattiq diskdagi ma'lumotlarning o'zi kuniga bir marta o'zgaradi - Moskvada kech tunda, yuk minimal bo'lganda. Buning yordamida (diskdagi tuzilma kun davomida doimiy bo'lishini bilgan holda) biz vektorlarni qat'iy o'lchamdagi massivlar bilan almashtirishimiz mumkin - va bu tufayli xotirani oshirish.

Yangi sxemada xabar yuborish quyidagicha ko'rinadi:

  1. PHP serveri foydalanuvchi dvigateliga xabar yuborish so'rovi bilan murojaat qiladi.
  2. user-motori so'rovni kerakli chat-motori namunasiga proksi-server qiladi, u foydalanuvchi mexanizmi chat_local_id-ga qaytadi - bu chat ichidagi yangi xabarning noyob identifikatori. Keyin chat_engine xabarni chatdagi barcha qabul qiluvchilarga uzatadi.
  3. user-engine chat-engine-dan chat_local_id-ni oladi va user_local_id-ni PHP-ga qaytaradi - bu foydalanuvchi uchun yagona xabar identifikatori. Keyinchalik bu identifikator, masalan, API orqali xabarlar bilan ishlash uchun ishlatiladi.

VKontakte xabarlar bazasini noldan qayta yozing va omon qoling
Ammo haqiqatan ham xabarlarni yuborishdan tashqari, yana bir nechta muhim narsalarni amalga oshirishingiz kerak:

  • Qo'shimcha ro'yxatlar, masalan, suhbatlar ro'yxatini ochganda ko'radigan eng so'nggi xabarlardir. O'qilmagan xabarlar, tegli xabarlar ("Muhim", "Spam" va boshqalar).
  • Chat-motorida xabarlarni siqish
  • Foydalanuvchi dvigatelida xabarlarni keshlash
  • Qidiruv (barcha dialog oynalari orqali va ma'lum birida).
  • Haqiqiy vaqtda yangilash (Longpolling).
  • Mobil mijozlarda keshlashni amalga oshirish uchun tarixni saqlash.

Barcha pastki ro'yxatlar tez o'zgaruvchan tuzilmalardir. Ular bilan ishlash uchun biz foydalanamiz Yorqin daraxtlar. Ushbu tanlov daraxtning tepasida biz ba'zan oniy rasmdan olingan xabarlarning butun segmentini saqlashimiz bilan izohlanadi - masalan, tungi qayta indekslashdan so'ng, daraxt pastki ro'yxatning barcha xabarlarini o'z ichiga olgan bitta tepadan iborat. Splay daraxti muvozanat haqida o'ylamasdan, bunday cho'qqining o'rtasiga kiritishni osonlashtiradi. Bundan tashqari, Splay keraksiz ma'lumotlarni saqlamaydi, bu bizni xotirani tejaydi.

Xabarlar katta hajmdagi ma'lumotlarni, asosan matnni o'z ichiga oladi, ularni siqish uchun foydalidir. Muhimi, hatto bitta alohida xabarni ham aniq arxivdan chiqarishimiz mumkin. Xabarlarni siqish uchun ishlatiladi Huffman algoritmi o'z evristikamiz bilan - masalan, biz xabarlarda so'zlar "so'z bo'lmagan" - bo'shliqlar, tinish belgilari bilan almashinishini bilamiz va biz rus tili uchun belgilardan foydalanishning ba'zi o'ziga xos xususiyatlarini eslaymiz.

Chatlardan ko'ra foydalanuvchilar ancha kam bo'lganligi sababli, chat-motorida tasodifiy kirish disk so'rovlarini saqlash uchun biz xabarlarni foydalanuvchi dvigatelida keshlaymiz.

Xabarlarni qidirish diagonal so'rov sifatida foydalanuvchi mexanizmidan ushbu foydalanuvchining chatlarini o'z ichiga olgan barcha chat mexanizmi misollarigacha amalga oshiriladi. Natijalar foydalanuvchi dvigatelining o'zida birlashtiriladi.

Xo'sh, barcha tafsilotlar hisobga olindi, qolgan narsa yangi sxemaga o'tish - va afzalroq, foydalanuvchilar buni sezmasdan.

Ma'lumotlarni ko'chirish

Shunday qilib, bizda foydalanuvchi xabarlarini saqlaydigan matn mexanizmi va ko'p suhbat xonalari va ulardagi foydalanuvchilar haqidagi ma'lumotlarni saqlaydigan ikkita klaster chat-a'zolari va a'zo-chatlar mavjud. Bundan yangi foydalanuvchi va chat mexanizmiga qanday o'tish mumkin?

Eski sxemadagi a'zo suhbatlari asosan optimallashtirish uchun ishlatilgan. Biz undan kerakli ma'lumotlarni tezda chat a'zolariga o'tkazdik, keyin u endi migratsiya jarayonida ishtirok etmadi.

Chat a'zolari uchun navbat. U 100 ta misolni o'z ichiga oladi, chat-motorida esa 4 ming. Ma'lumotlarni uzatish uchun siz uni moslashtirishingiz kerak - buning uchun chat a'zolari bir xil 4 ming nusxaga bo'lingan, keyin chat-motorida chat a'zolarining binlogini o'qish yoqilgan.
VKontakte xabarlar bazasini noldan qayta yozing va omon qoling
Endi chat-motori chat a'zolaridan ko'p chat haqida biladi, lekin u hali ikki suhbatdosh bilan muloqot haqida hech narsa bilmaydi. Bunday dialoglar foydalanuvchilarga havola qilingan matn-motorda joylashgan. Bu erda biz ma'lumotlarni "to'g'ridan-to'g'ri" oldik: har bir chat mexanizmi barcha matn mexanizmi misollaridan kerakli dialogga ega yoki yo'qligini so'radi.

Ajoyib - chat-motori qanday ko'p chatli chatlar borligini biladi va qanday dialoglar borligini biladi.
Har bir chatda xabarlar ro'yxatini olish uchun siz ko'p chatli chatlarda xabarlarni birlashtirishingiz kerak. Birinchidan, chat-motori ushbu chatdagi barcha foydalanuvchi xabarlarini matnli dvigateldan oladi. Ba'zi hollarda ular juda ko'p (yuzlab millionlargacha), lekin juda kamdan-kam holatlardan tashqari, suhbat to'liq RAMga mos keladi. Bizda tartibsiz xabarlar bor, ularning har biri bir necha nusxada - ularning barchasi foydalanuvchilarga mos keladigan turli xil matn mexanizmi misollaridan olingan. Maqsad - xabarlarni tartiblash va keraksiz joy egallagan nusxalardan xalos bo'lish.

Har bir xabarda yuborilgan vaqt va matnni o'z ichiga olgan vaqt belgisi mavjud. Biz tartiblash uchun vaqtdan foydalanamiz - biz multichat ishtirokchilarining eng qadimgi xabarlariga ko'rsatgichlarni joylashtiramiz va vaqt tamg'asini oshirishga qarab mo'ljallangan nusxalar matnidan xeshlarni solishtiramiz. Nusxalar bir xil xesh va vaqt tamg'asiga ega bo'lishi mantiqan to'g'ri, lekin amalda bu har doim ham shunday emas. Esingizda bo'lsa, eski sxemada sinxronizatsiya PHP tomonidan amalga oshirilgan - va kamdan-kam hollarda, bir xil xabarni yuborish vaqti turli foydalanuvchilar orasida farq qiladi. Bunday hollarda, biz o'zimizga vaqt tamg'asini tahrirlashga ruxsat berdik - odatda bir soniya ichida. Ikkinchi muammo - turli xil qabul qiluvchilar uchun turli xil xabarlar tartibi. Bunday hollarda biz turli foydalanuvchilar uchun turli xil buyurtma variantlari bilan qo'shimcha nusxa yaratishga ruxsat berdik.

Shundan so'ng, multichatdagi xabarlar haqidagi ma'lumotlar foydalanuvchi dvigateliga yuboriladi. Va bu erda import qilingan xabarlarning noxush xususiyati keladi. Oddiy ishlashda dvigatelga kelgan xabarlar qat'iy ravishda user_local_id tomonidan ortib boruvchi tartibda tartibga solinadi. Eski dvigateldan foydalanuvchi dvigateliga import qilingan xabarlar ushbu foydali xususiyatni yo'qotdi. Shu bilan birga, sinovdan o'tkazish qulayligi uchun siz ularga tezda kirishingiz, ulardan nimanidir izlashingiz va yangilarini qo'shishingiz kerak.

Import qilingan xabarlarni saqlash uchun maxsus ma'lumotlar strukturasidan foydalanamiz.

U kattalik vektorini ifodalaydi VKontakte xabarlar bazasini noldan qayta yozing va omon qoling, qaerda, barcha VKontakte xabarlar bazasini noldan qayta yozing va omon qoling - har xil va kamayish tartibida, elementlarning maxsus tartibi bilan tartiblangan. Har bir segmentda indekslar bilan VKontakte xabarlar bazasini noldan qayta yozing va omon qoling elementlar tartiblangan. Bunday strukturadagi elementni izlash vaqt talab etadi VKontakte xabarlar bazasini noldan qayta yozing va omon qoling ichidan VKontakte xabarlar bazasini noldan qayta yozing va omon qoling ikkilik qidiruvlar. Element qo'shilishi amortizatsiya qilinadi VKontakte xabarlar bazasini noldan qayta yozing va omon qoling.

Shunday qilib, biz ma'lumotlarni eski dvigatellardan yangilariga qanday o'tkazishni aniqladik. Ammo bu jarayon bir necha kun davom etadi - va shu kunlarda foydalanuvchilarimiz bir-biriga yozish odatidan voz kechishlari dargumon. Bu vaqt ichida xabarlarni yo'qotmaslik uchun biz eski va yangi klasterlardan foydalanadigan ish sxemasiga o'tamiz.

Ma'lumotlar chat a'zolariga va foydalanuvchi dvigateliga yoziladi (eski sxema bo'yicha normal ishda bo'lgani kabi matnli dvigatelga emas). foydalanuvchi dvigateli chat-motoriga so'rovni proksi-server qiladi - va bu erda xatti-harakatlar ushbu chat allaqachon birlashtirilganmi yoki yo'qligiga bog'liq. Agar suhbat hali birlashtirilmagan bo'lsa, suhbat mexanizmi xabarni o'ziga yozmaydi va uni qayta ishlash faqat matn mexanizmida sodir bo'ladi. Agar chat allaqachon chat-motoriga birlashtirilgan bo'lsa, u chat_local_id-ni foydalanuvchi mexanizmiga qaytaradi va xabarni barcha qabul qiluvchilarga yuboradi. foydalanuvchi dvigateli barcha ma'lumotlarni matnli dvigatelga proksi-server qiladi - shunday qilib, agar biror narsa sodir bo'lsa, biz eski dvigatelda barcha joriy ma'lumotlarga ega bo'lgan holda har doim orqaga qaytishimiz mumkin. text-engine user_local_id ni qaytaradi, bu foydalanuvchi dvigateli saqlaydi va backendga qaytadi.
VKontakte xabarlar bazasini noldan qayta yozing va omon qoling
Natijada, o'tish jarayoni quyidagicha ko'rinadi: biz bo'sh foydalanuvchi-dvigatel va chat-motor klasterlarini bog'laymiz. chat-engine butun chat-a'zolarining binlogini o'qiydi, keyin proksi-server yuqorida tavsiflangan sxema bo'yicha boshlanadi. Biz eski ma'lumotlarni uzatamiz va ikkita sinxronlashtirilgan klasterni olamiz (eski va yangi). O'qishni matnli dvigateldan foydalanuvchi dvigateliga o'tkazish va proksi-serverni o'chirish qoladi.

Natijalar

Yangi yondashuv tufayli dvigatellarning barcha ishlash ko'rsatkichlari yaxshilandi va ma'lumotlarning izchilligi bilan bog'liq muammolar hal qilindi. Endi biz xabarlarda yangi xususiyatlarni tezda amalga oshirishimiz mumkin (va buni allaqachon boshladik - biz chat ishtirokchilarining maksimal sonini ko'paytirdik, yo'naltirilgan xabarlarni qidirishni amalga oshirdik, qadalgan xabarlarni ishga tushirdik va har bir foydalanuvchi uchun umumiy xabarlar soniga cheklovni oshirdik) .

Mantiqdagi o'zgarishlar haqiqatan ham juda katta. Shuni ta'kidlashni istardimki, bu har doim ham ulkan jamoa va son-sanoqsiz kod satrlari tomonidan butun yillar davomida rivojlanishni anglatmaydi. Xabarlarni siqish uchun Huffman, Splay daraxtlari va import qilingan xabarlar uchun struktura kabi barcha qo'shimcha hikoyalar bilan bir qatorda chat-motori va foydalanuvchi dvigateli 20 ming satrdan kamroq kodni tashkil qiladi. Va ular 3 ta ishlab chiquvchi tomonidan atigi 10 oy ichida yozilgan (ammo shuni yodda tutish kerakki, hamma uchta dasturchi - jahon chempionlari sport dasturlarida).

Bundan tashqari, serverlar sonini ikki baravar oshirish o'rniga, biz ularning sonini ikki baravar kamaytirdik - endi foydalanuvchi dvigateli va chat-motori 500 ta jismoniy mashinada ishlaydi, yangi sxemada yuklash uchun katta joy mavjud. Biz asbob-uskunalar uchun juda ko'p pulni tejadik - taxminan 5 million dollar + yiliga 750 ming dollar operatsion xarajatlar.

Biz eng murakkab va keng ko'lamli muammolar uchun eng yaxshi echimlarni topishga intilamiz. Bizda ular juda ko'p - va shuning uchun biz ma'lumotlar bazasi bo'limida iqtidorli dasturchilarni qidirmoqdamiz. Agar siz bunday muammolarni qanday hal qilishni yaxshi ko'rsangiz va bilsangiz, algoritmlar va ma'lumotlar tuzilmalarini mukammal bilsangiz, sizni jamoaga qo'shilishga taklif qilamiz. Biz bilan bog'laning HRtafsilotlar uchun.

Bu hikoya siz haqingizda bo'lmasa ham, biz tavsiyalarni qadrlashimizni unutmang. Do'stingizga ayting ishlab chiquvchi bo'sh ish o'rinlari, va agar u sinov muddatini muvaffaqiyatli yakunlasa, siz 100 ming rubl miqdorida bonus olasiz.

Manba: www.habr.com

a Izoh qo'shish