NewSQL = NoSQL+ACID

NewSQL = NoSQL+ACID
Yaqin vaqtgacha Odnoklassniki SQL Serverda real vaqt rejimida qayta ishlangan 50 TBga yaqin maʼlumotlarni saqlagan. Bunday hajm uchun SQL DBMS yordamida tez va ishonchli va hatto ma'lumotlar markazining ishlamay qolishi mumkin bo'lgan kirishni ta'minlash deyarli mumkin emas. Odatda, bunday hollarda NoSQL omborlaridan biri ishlatiladi, lekin hamma narsani NoSQL-ga o'tkazib bo'lmaydi: ba'zi ob'ektlar ACID tranzaksiya kafolatlarini talab qiladi.

Bu bizni NewSQL xotirasidan, ya'ni NoSQL tizimlarining nosozliklarga chidamliligi, masshtabliligi va ishlashini ta'minlovchi, lekin ayni paytda klassik tizimlarga tanish bo'lgan ACID kafolatlarini saqlab turuvchi ma'lumotlar bazasidan foydalanishga olib keldi. Ushbu yangi sinfning ishlaydigan sanoat tizimlari kam, shuning uchun biz bunday tizimni o'zimiz amalga oshirdik va uni tijorat maqsadlarida foydalanishga topshirdik.

Bu qanday ishlaydi va nima bo'ldi - kesish ostida o'qing.

Bugungi kunda Odnoklassniki-ning oylik auditoriyasi 70 milliondan ortiq noyob tashrif buyuruvchilarni tashkil etadi. Biz Biz kuchli beshlikka kirdik dunyodagi eng yirik ijtimoiy tarmoqlar va foydalanuvchilar eng ko'p vaqt sarflaydigan yigirmata sayt orasida. OK infratuzilmasi juda katta yuklarni ko'rib chiqadi: har bir frontda bir milliondan ortiq HTTP so'rovlari / soniya. 8000 dan ortiq bo'laklardan iborat serverlar parkining qismlari bir-biriga yaqin joylashgan - to'rtta Moskva ma'lumot markazlarida, bu ular orasidagi tarmoqning kechikishi 1 ms dan kam bo'lishiga imkon beradi.

Biz 2010 versiyasidan boshlab 0.6 yildan beri Cassandra-dan foydalanamiz. Bugungi kunda bir necha o'nlab klasterlar faoliyat ko'rsatmoqda. Eng tezkor klaster soniyada 4 milliondan ortiq operatsiyani amalga oshiradi, eng kattasi esa 260 TBni saqlaydi.

Biroq, bularning barchasi saqlash uchun ishlatiladigan oddiy NoSQL klasterlaridir zaif muvofiqlashtirilgan ma'lumotlar. Biz Odnoklassniki tashkil topganidan beri foydalanilgan asosiy doimiy xotirani, Microsoft SQL Serverni almashtirmoqchi edik. Saqlash 300 dan ortiq SQL Server Standard Edition mashinalaridan iborat bo'lib, ularda 50 TB ma'lumotlar - tadbirkorlik sub'ektlari mavjud edi. Ushbu ma'lumotlar ACID tranzaktsiyalarining bir qismi sifatida o'zgartiriladi va talab qilinadi yuqori mustahkamlik.

SQL Server tugunlari bo'ylab ma'lumotlarni tarqatish uchun biz vertikal va gorizontaldan foydalandik qismlarga ajratish (parchalash). Tarixiy jihatdan biz oddiy ma'lumotlarni taqsimlash sxemasidan foydalanganmiz: har bir ob'ekt token bilan bog'langan - ob'ekt identifikatorining funktsiyasi. Xuddi shu tokenga ega ob'ektlar bir xil SQL serveriga joylashtirilgan. Asosiy va asosiy yozuvlarning tokenlari har doim mos keladigan va bir xil serverda joylashgan bo'lishi uchun asosiy-tafsilot munosabatlari amalga oshirildi. Ijtimoiy tarmoqda deyarli barcha yozuvlar foydalanuvchi nomidan yaratiladi - bu bitta funktsional quyi tizimdagi barcha foydalanuvchi ma'lumotlari bitta serverda saqlanadi degan ma'noni anglatadi. Ya'ni, biznes tranzaktsiyasi deyarli har doim bitta SQL serveridagi jadvallarni o'z ichiga oladi, bu esa mahalliy ACID tranzaksiyalari yordamida ma'lumotlarning izchilligini, foydalanishga hojat qoldirmasdan ta'minlash imkonini berdi. sekin va ishonchsiz taqsimlangan ACID tranzaktsiyalari.

Sharding va SQL ni tezlashtirish uchun rahmat:

  • Biz xorijiy kalit cheklovlaridan foydalanmaymiz, chunki shardingda ob'ekt identifikatori boshqa serverda joylashgan bo'lishi mumkin.
  • DBMS protsessoriga qo'shimcha yuklanish tufayli biz saqlangan protseduralar va triggerlardan foydalanmaymiz.
  • Yuqorida aytilganlarning barchasi va diskdan tasodifiy o'qishlar ko'pligi sababli biz JOIN dan foydalanmaymiz.
  • Tranzaksiyadan tashqari, biz blokirovkalarni kamaytirish uchun Read Uncommitted izolyatsiya darajasidan foydalanamiz.
  • Biz faqat qisqa tranzaktsiyalarni amalga oshiramiz (o'rtacha 100 ms dan qisqa).
  • Ko'p qatorli blokirovkalar tufayli biz ko'p qatorli UPDATE va DELETE dan foydalanmaymiz - biz bir vaqtning o'zida faqat bitta yozuvni yangilaymiz.
  • Biz har doim so'rovlarni faqat indekslar bo'yicha bajaramiz - biz uchun to'liq jadvalni skanerlash rejasiga ega so'rov ma'lumotlar bazasini haddan tashqari yuklash va uning ishlamay qolishiga olib keladi.

Ushbu qadamlar bizga SQL serverlarining deyarli maksimal ishlashini siqib chiqarishga imkon berdi. Biroq, muammolar tobora ko'payib bordi. Keling, ularga qaraylik.

SQL bilan bog'liq muammolar

  • Biz o'z-o'zidan yozilgan shardingdan foydalanganimiz sababli, yangi parchalarni qo'shish administratorlar tomonidan qo'lda amalga oshirildi. Bu vaqt davomida kengaytiriladigan ma'lumotlar nusxalari so'rovlarga xizmat ko'rsatmadi.
  • Jadvaldagi yozuvlar soni ortib borishi bilan kiritish va o'zgartirish tezligi pasayadi; mavjud jadvalga indekslarni qo'shganda, tezlik bir necha baravar pasayadi; indekslarni yaratish va qayta yaratish ishlamay qolishi bilan sodir bo'ladi.
  • Ishlab chiqarishda SQL Server uchun Windows-ning oz miqdori mavjudligi infratuzilmani boshqarishni qiyinlashtiradi

Ammo asosiy muammo shundaki

xatolarga chidamlilik

Klassik SQL serveri nosozliklarga chidamliligi past. Aytaylik, sizda faqat bitta ma'lumotlar bazasi serveri bor va u har uch yilda bir marta ishlamay qoladi. Bu vaqt ichida sayt 20 daqiqa davomida ishlamayapti, bu maqbuldir. Agar sizda 64 ta server bo'lsa, sayt har uch haftada bir marta ishlamay qoladi. Va agar sizda 200 ta server bo'lsa, u holda sayt har hafta ishlamaydi. Bu muammo.

SQL serverining xatolarga chidamliligini yaxshilash uchun nima qilish mumkin? Vikipediya bizni qurishga taklif qiladi yuqori darajada mavjud klaster: bu erda biron bir komponent ishlamay qolsa, zaxira nusxasi mavjud.

Bu qimmatbaho uskunalar parkini talab qiladi: ko'p sonli takrorlash, optik tolali, umumiy saqlash va zaxirani kiritish ishonchli ishlamaydi: kommutatsiyalarning taxminan 10% asosiy tugun orqasidagi poezd kabi zaxira tugunining ishdan chiqishi bilan yakunlanadi.

Ammo bunday yuqori darajada mavjud bo'lgan klasterning asosiy kamchiligi, agar u joylashgan ma'lumotlar markazi ishlamay qolsa, nol mavjudlikdir. Odnoklassniki-da to'rtta ma'lumot markazlari mavjud va ulardan birida to'liq ishlamay qolganda ishlashni ta'minlashimiz kerak.

Buning uchun biz foydalanishimiz mumkin Ko'p usta SQL Serverga o'rnatilgan replikatsiya. Ushbu yechim dasturiy ta'minot narxi tufayli ancha qimmat va replikatsiya bilan bog'liq taniqli muammolardan aziyat chekadi - sinxron replikatsiya bilan oldindan aytib bo'lmaydigan tranzaksiya kechikishlari va asinxron replikatsiya bilan replikatsiyalarni qo'llashdagi kechikishlar (va natijada yo'qolgan modifikatsiyalar). Ko'rsatilgan nizolarni qo'lda hal qilish bu variantni biz uchun mutlaqo mos kelmaydigan qiladi.

Bu muammolarning barchasi tubdan hal qilishni talab qildi va biz ularni batafsil tahlil qila boshladik. Bu erda biz SQL Server asosan nima bilan shug'ullanishi - tranzaktsiyalar bilan tanishishimiz kerak.

Oddiy tranzaksiya

Keling, qo'llaniladigan SQL dasturchisi nuqtai nazaridan eng oddiy operatsiyani ko'rib chiqaylik: albomga fotosurat qo'shish. Albomlar va fotosuratlar turli plitalarda saqlanadi. Albomda umumiy foto hisoblagich mavjud. Keyin bunday operatsiya quyidagi bosqichlarga bo'linadi:

  1. Biz albomni kalit bilan qulflaymiz.
  2. Fotosuratlar jadvalida yozuv yarating.
  3. Agar fotosurat ommaviy maqomga ega bo'lsa, albomga umumiy foto hisoblagich qo'shing, yozuvni yangilang va tranzaktsiyani bajaring.

Yoki psevdokodda:

TX.start("Albums", id);
Album album = albums.lock(id);
Photo photo = photos.create(…);

if (photo.status == PUBLIC ) {
    album.incPublicPhotosCount();
}
album.update();

TX.commit();

Biz biznes tranzaktsiyasining eng keng tarqalgan stsenariysi ma'lumotlar bazasidan ma'lumotlarni dastur serveri xotirasiga o'qish, biror narsani o'zgartirish va yangi qiymatlarni ma'lumotlar bazasiga saqlash ekanligini ko'ramiz. Odatda bunday tranzaktsiyada biz bir nechta ob'ektlarni, bir nechta jadvallarni yangilaymiz.

Tranzaktsiyani amalga oshirishda boshqa tizimdan bir xil ma'lumotlarning bir vaqtning o'zida o'zgarishi mumkin. Misol uchun, antispam foydalanuvchi qandaydir tarzda shubhali deb qaror qilishi mumkin va shuning uchun foydalanuvchining barcha fotosuratlari endi ochiq bo'lmasligi kerak, ular moderatsiyaga yuborilishi kerak, bu photo.statusni boshqa qiymatga o'zgartirish va tegishli hisoblagichlarni o'chirishni anglatadi. Shubhasiz, agar ushbu operatsiya qo'llanilishining atomikligi va raqobatdosh modifikatsiyalarning izolyatsiyasi kafolatisiz amalga oshirilsa, masalan ACID, keyin natija kerakli bo'lmaydi - yoki foto hisoblagich noto'g'ri qiymatni ko'rsatadi yoki barcha fotosuratlar moderatsiyaga yuborilmaydi.

Odnoklassniki butun faoliyati davomida bir tranzaksiya doirasida turli tadbirkorlik sub'yektlarini manipulyatsiya qiluvchi ko'plab shunga o'xshash kodlar yozilgan. dan NoSQL ga o'tish tajribasiga asoslangan Yakuniy muvofiqlik Biz bilamizki, eng katta qiyinchilik (va vaqtga investitsiya) ma'lumotlar izchilligini ta'minlash uchun kodni ishlab chiqishdan kelib chiqadi. Shuning uchun biz yangi saqlash uchun asosiy talabni dastur mantig'i uchun haqiqiy ACID tranzaktsiyalarini ta'minlash deb hisobladik.

Bundan kam muhim bo'lmagan boshqa talablar quyidagilar edi:

  • Agar ma'lumotlar markazi ishlamay qolsa, yangi xotiraga o'qish va yozish imkoniyati mavjud bo'lishi kerak.
  • Hozirgi rivojlanish tezligini saqlab qolish. Ya'ni, yangi ombor bilan ishlashda kod miqdori taxminan bir xil bo'lishi kerak, omborga hech narsa qo'shishning hojati yo'q, nizolarni hal qilish algoritmlarini ishlab chiqish, ikkilamchi indekslarni saqlash va hokazo.
  • Yangi saqlash tezligi ma'lumotlarni o'qishda ham, tranzaktsiyalarni qayta ishlashda ham ancha yuqori bo'lishi kerak edi, bu esa akademik jihatdan qat'iy, universal, ammo sekin echimlar, masalan, qo'llanilmasligini anglatadi. ikki fazali majburiyatlar.
  • Avtomatik masshtablash.
  • Oddiy arzon serverlardan foydalanish, ekzotik uskunani sotib olish kerak emas.
  • Kompaniya ishlab chiquvchilari tomonidan saqlashni rivojlantirish imkoniyati. Boshqacha qilib aytadigan bo'lsak, xususiy yoki ochiq manbali echimlarga ustunlik berildi, afzalroq Java.

Qarorlar, qarorlar

Mumkin bo'lgan echimlarni tahlil qilib, biz ikkita mumkin bo'lgan arxitektura tanloviga keldik:

Birinchisi, har qanday SQL serverini olish va talab qilinadigan nosozliklarga chidamlilik, masshtablash mexanizmi, o'zgarmas klaster, nizolarni hal qilish va taqsimlangan, ishonchli va tezkor ACID tranzaktsiyalarini amalga oshirishdir. Biz ushbu variantni juda ahamiyatsiz va mehnat talab qiladigan deb baholadik.

Ikkinchi variant - amalga oshirilgan masshtablash, uzilish klasteri, nizolarni hal qilish va tranzaktsiyalar va SQL-ni o'zingiz amalga oshirish bilan tayyor NoSQL xotirasini olishdir. Bir qarashda, hatto SQL-ni amalga oshirish vazifasi, ACID tranzaktsiyalari haqida gapirmasa ham, yillar davom etadigan vazifaga o'xshaydi. Ammo keyin biz amalda foydalanadigan SQL xususiyatlari to'plami ANSI SQL dan uzoqroq ekanligini angladik Kassandra CQL ANSI SQL dan uzoqda. CQL-ni yanada yaqinroq ko'rib chiqsak, u bizga kerak bo'lgan narsaga juda yaqin ekanligini angladik.

Kassandra va CQL

Xo'sh, Kassandraning nimasi qiziq, u qanday imkoniyatlarga ega?

Birinchidan, bu yerda siz turli xil ma'lumotlar turlarini qo'llab-quvvatlaydigan jadvallarni yaratishingiz mumkin; asosiy kalitda SELECT yoki UPDATE qilishingiz mumkin.

CREATE TABLE photos (id bigint KEY, owner bigint,…);
SELECT * FROM photos WHERE id=?;
UPDATE photos SET … WHERE id=?;

Replikatsiya ma'lumotlarining izchilligini ta'minlash uchun Cassandra foydalanadi kvorum yondashuvi. Eng oddiy holatda, bu shuni anglatadiki, bir qatorning uchta nusxasi klasterning turli tugunlariga joylashtirilganda, agar tugunlarning aksariyati (ya'ni uchtadan ikkitasi) ushbu yozish operatsiyasining muvaffaqiyatini tasdiqlagan bo'lsa, yozish muvaffaqiyatli hisoblanadi. . Agar o'qish paytida ko'pchilik tugunlar so'ralgan va ularni tasdiqlagan bo'lsa, qator ma'lumotlari izchil hisoblanadi. Shunday qilib, uchta nusxada, bitta tugun ishlamay qolsa, to'liq va tezkor ma'lumotlarning mustahkamligi kafolatlanadi. Ushbu yondashuv bizga yanada ishonchli sxemani amalga oshirishga imkon berdi: har doim uchta nusxaga so'rov yuboring, ikkita eng tezkor javobni kuting. Uchinchi nusxaning kech javobi bu holatda o'chiriladi. Javob berishda kechikayotgan tugun jiddiy muammolarga duch kelishi mumkin - tormoz, JVMda axlat yig'ish, Linux yadrosida to'g'ridan-to'g'ri xotirani tiklash, apparatdagi nosozlik, tarmoqdan uzilish. Biroq, bu mijozning operatsiyalari yoki ma'lumotlariga hech qanday ta'sir qilmaydi.

Biz uchta tugun bilan bog'lanib, ikkitadan javob oladigan yondashuv deyiladi spekülasyon: qo'shimcha nusxalar uchun so'rov "tushib ketishidan" oldin ham yuboriladi.

Kassandraning yana bir afzalligi - bu Batchlog, bu mexanizm siz kiritgan o'zgarishlar to'liq qo'llanilishi yoki umuman qo'llanilmasligini ta'minlaydi. Bu bizga A ni ACIDda - atomiklikni qutidan chiqarishga imkon beradi.

Kassandradagi tranzaktsiyalarga eng yaqin narsa bu "engil operatsiyalar". Ammo ular "haqiqiy" ACID tranzaktsiyalaridan uzoqdir: aslida bu imkoniyatdir CAS og'ir vaznli Paxos protokolidan foydalangan holda konsensus yordamida faqat bitta rekorddan olingan ma'lumotlar bo'yicha. Shuning uchun bunday operatsiyalar tezligi past.

Kassandrada nima etishmayotgan edi

Shunday qilib, biz Kassandrada haqiqiy ACID tranzaktsiyalarini amalga oshirishimiz kerak edi. Ulardan foydalanib, biz klassik DBMSning yana ikkita qulay xususiyatini osongina amalga oshirishimiz mumkin edi: doimiy tezkor indekslar, bu bizga ma'lumotlarni tanlashni nafaqat asosiy kalit orqali amalga oshirishga imkon beradi, balki monotonik avtomatik o'sish identifikatorlarining muntazam generatori.

C*Bir

Shunday qilib, yangi ma'lumotlar bazasi yaratildi C*Bir, uchta turdagi server tugunlaridan iborat:

  • Saqlash - mahalliy disklarda ma'lumotlarni saqlash uchun mas'ul bo'lgan (deyarli) standart Cassandra serverlari. Ma'lumotlar yuki va hajmi oshgani sayin, ularning miqdori osonlik bilan o'nlab va yuzlabgacha ko'paytirilishi mumkin.
  • Tranzaksiya koordinatorlari - bitimlarning bajarilishini ta'minlaydi.
  • Mijozlar biznes operatsiyalarini amalga oshiradigan va tranzaktsiyalarni boshlaydigan dastur serverlaridir. Bunday mijozlar minglab bo'lishi mumkin.

NewSQL = NoSQL+ACID

Barcha turdagi serverlar umumiy klasterning bir qismi bo'lib, bir-biri bilan aloqa qilish uchun ichki Cassandra xabar protokolidan foydalaning va G'iybat klaster ma'lumotlarini almashish uchun. Heartbeat yordamida serverlar o'zaro nosozliklar haqida bilib oladilar, yagona ma'lumotlar sxemasini - jadvallar, ularning tuzilishi va replikatsiyasini saqlaydilar; qismlarga ajratish sxemasi, klaster topologiyasi va boshqalar.

Mijozlar

NewSQL = NoSQL+ACID

Standart drayverlar o'rniga Fat Client rejimi qo'llaniladi. Bunday tugun ma'lumotlarni saqlamaydi, lekin so'rovni bajarish bo'yicha koordinator vazifasini bajarishi mumkin, ya'ni Mijozning o'zi uning so'rovlari koordinatori vazifasini bajaradi: u saqlash replikalarini so'raydi va nizolarni hal qiladi. Bu masofaviy koordinator bilan aloqani talab qiladigan standart haydovchiga qaraganda nafaqat ishonchli va tezroq, balki so'rovlarni uzatishni boshqarish imkonini beradi. Mijozda ochiq tranzaksiyadan tashqari, so'rovlar omborlarga yuboriladi. Agar mijoz tranzaktsiyani ochgan bo'lsa, u holda tranzaksiya ichidagi barcha so'rovlar tranzaksiya koordinatoriga yuboriladi.
NewSQL = NoSQL+ACID

C*One tranzaksiya koordinatori

Koordinator - bu biz C*One uchun noldan amalga oshirgan narsamiz. U tranzaktsiyalarni, qulflarni va operatsiyalarni qo'llash tartibini boshqarish uchun javobgardir.

Har bir xizmat ko'rsatilayotgan tranzaksiya uchun koordinator vaqt tamg'asini yaratadi: har bir keyingi tranzaksiya oldingi tranzaksiyadan kattaroqdir. Kassandraning nizolarni hal qilish tizimi vaqt belgilariga asoslanganligi sababli (ikki qarama-qarshi yozuvdan, oxirgi vaqt tamg'asi joriy hisoblanadi), ziddiyat har doim keyingi bitim foydasiga hal qilinadi. Shunday qilib, biz amalga oshirdik Lamport soati - taqsimlangan tizimdagi nizolarni hal qilishning arzon usuli.

Qulflar

Izolyatsiyani ta'minlash uchun biz eng oddiy usuldan foydalanishga qaror qildik - yozuvning asosiy kalitiga asoslangan pessimistik qulflar. Boshqacha qilib aytadigan bo'lsak, tranzaksiyada birinchi navbatda yozuv qulflanishi kerak, shundan keyingina o'qilishi, o'zgartirilishi va saqlanishi kerak. Muvaffaqiyatli majburiyatdan so'nggina rekordni ochish mumkin, shunda raqobatdosh tranzaktsiyalar undan foydalanishi mumkin.

Bunday qulflashni amalga oshirish taqsimlanmagan muhitda oddiy. Tarqalgan tizimda ikkita asosiy variant mavjud: yo klasterda taqsimlangan qulflashni amalga oshirish yoki tranzaktsiyalarni bir xil yozuv bilan bog'liq tranzaktsiyalarga doimo bir xil koordinator tomonidan xizmat ko'rsatishi uchun tarqatish.

Bizning holatlarimizda ma'lumotlar SQL-dagi mahalliy tranzaktsiyalar guruhlari o'rtasida allaqachon taqsimlanganligi sababli, mahalliy tranzaksiya guruhlarini koordinatorlarga belgilashga qaror qilindi: bitta koordinator barcha operatsiyalarni 0 dan 9 gacha tokenlar bilan amalga oshiradi, ikkinchisi - 10 dan 19 gacha tokenlar bilan, va hokazo. Natijada, har bir muvofiqlashtiruvchi instansiya tranzaksiya guruhining ustasiga aylanadi.

Keyin qulflar koordinator xotirasida banal HashMap ko'rinishida amalga oshirilishi mumkin.

Koordinator xatolari

Bitta koordinator faqat tranzaktsiyalar guruhiga xizmat ko'rsatganligi sababli, tranzaktsiyani amalga oshirishga ikkinchi urinish vaqti tugashi uchun uning muvaffaqiyatsizligi faktini tezda aniqlash juda muhimdir. Buni tez va ishonchli qilish uchun biz toʻliq ulangan kvorum eshitish protokolidan foydalandik:

Har bir ma'lumot markazida kamida ikkita koordinator tugunlari mavjud. Vaqti-vaqti bilan har bir koordinator boshqa koordinatorlarga yurak urishi haqidagi xabarni yuboradi va ularning ishlashi, shuningdek, oxirgi marta klasterdagi qaysi koordinatorlardan yurak urishi haqidagi xabarlarni olgani haqida ma'lumot beradi.

NewSQL = NoSQL+ACID

Boshqalardan shunga o'xshash ma'lumotlarni yurak urishi haqidagi xabarlarning bir qismi sifatida qabul qilgan holda, har bir koordinator kvorum printsipiga asoslanib, qaysi klaster tugunlari ishlayotgani va qaysi biri ishlamayotganligini o'zi hal qiladi: agar X tugun klasterdagi ko'pchilik tugunlardan normal holat haqida ma'lumot olgan bo'lsa. Y tugunidan xabarlarni qabul qilish, keyin , Y ishlaydi. Va aksincha, ko'pchilik Y tugunidan xabarlar yo'qolganligi haqida xabar berishi bilanoq, Y rad etdi. Qizig'i shundaki, agar kvorum X tuguniga endi undan xabar olmasligi haqida xabar bersa, X tugunning o'zi o'zini muvaffaqiyatsiz deb hisoblaydi.

Yurak urishi haqidagi xabarlar yuqori chastotada, sekundiga taxminan 20 marta, 50 ms vaqt oralig'ida yuboriladi. Java-da, axlat yig'uvchi tomonidan yuzaga kelgan pauzalarning taqqoslanadigan uzunligi tufayli 50 ms ichida dastur javobini kafolatlash qiyin. Biz ushbu javob vaqtiga G1 axlat yig'uvchisi yordamida erisha oldik, bu bizga GC pauzalarining davomiyligi uchun maqsadni belgilash imkonini beradi. Biroq, ba'zida, juda kamdan-kam hollarda, kollektor pauzalari 50 ms dan oshadi, bu noto'g'ri nosozlikni aniqlashga olib kelishi mumkin. Bunga yo'l qo'ymaslik uchun koordinator masofaviy tugunning birinchi yurak urishi xabari yo'qolganda, uning ishlamay qolishi haqida xabar bermaydi, faqat bir nechtasi ketma-ket g'oyib bo'lgan bo'lsa, biz 200 yilda koordinator tugunidagi nosozlikni aniqlashga muvaffaq bo'ldik. Xonim.

Ammo qaysi tugun ishlashni to'xtatganini tezda tushunish etarli emas. Bu borada biror narsa qilishimiz kerak.

Rezervasyon

Klassik sxema, usta muvaffaqiyatsizlikka uchragan taqdirda, ulardan biri yordamida yangi saylovni boshlashni o'z ichiga oladi moda universal algoritmlar. Biroq, bunday algoritmlar vaqtni yaqinlashtirish va saylov jarayonining o'zi uzoqligi bilan bog'liq taniqli muammolarga ega. Biz to'liq ulangan tarmoqdagi koordinatorni almashtirish sxemasidan foydalanib, bunday qo'shimcha kechikishlarning oldini oldik:

NewSQL = NoSQL+ACID

Aytaylik, biz 50-guruhda tranzaktsiyani amalga oshirmoqchimiz.O'zgartirish sxemasini, ya'ni asosiy koordinator ishlamay qolganda 50-guruhdagi tranzaktsiyalarni qaysi tugunlar bajarishini oldindan aniqlaymiz. Maqsadimiz ma'lumotlar markazi ishlamay qolganda tizim funksionalligini saqlab qolishdir. Aniqlaymizki, birinchi zaxira boshqa ma'lumotlar markazidan tugun bo'ladi va ikkinchi zaxira uchinchidan tugun bo'ladi. Ushbu sxema bir marta tanlanadi va klaster topologiyasi o'zgarmaguncha, ya'ni unga yangi tugunlar kirguncha o'zgarmaydi (bu juda kam uchraydi). Agar eskisi muvaffaqiyatsiz bo'lsa, yangi faol ustani tanlash tartibi har doim shunday bo'ladi: birinchi zaxira faol ustaga aylanadi va agar u ishlashni to'xtatgan bo'lsa, ikkinchi zaxira faol ustaga aylanadi.

Ushbu sxema universal algoritmga qaraganda ishonchliroqdir, chunki yangi ustani faollashtirish uchun eskisining ishdan chiqishini aniqlash kifoya.

Ammo mijozlar hozir qaysi usta ishlayotganini qanday tushunishadi? 50 ms ichida minglab mijozlarga ma'lumot yuborish mumkin emas. Vaziyat, mijoz tranzaktsiyani ochish uchun so'rov yuborganda, bu master endi ishlamay qolganligini va so'rov muddati tugashini bilmagan holda mumkin. Bunga yo'l qo'ymaslik uchun mijozlar spekulyativ ravishda guruh ustasiga va uning ikkala zaxirasiga bir vaqtning o'zida tranzaktsiyani ochish uchun so'rov yuboradilar, ammo bu so'rovga faqat hozirda faol usta bo'lgan kishi javob beradi. Mijoz tranzaksiya doirasidagi barcha keyingi aloqalarni faqat faol usta bilan amalga oshiradi.

Zaxira ustalari ularga tegishli bo'lmagan tranzaktsiyalar bo'yicha olingan so'rovlarni tug'ilmagan tranzaktsiyalar navbatiga qo'yadi, ular bir muncha vaqt saqlanadi. Agar faol master vafot etsa, yangi master o'z navbatdan tranzaktsiyalarni ochish so'rovlarini qayta ishlaydi va mijozga javob beradi. Agar mijoz allaqachon eski usta bilan tranzaktsiyani ochgan bo'lsa, ikkinchi javob e'tiborga olinmaydi (va, shubhasiz, bunday operatsiya tugamaydi va mijoz tomonidan takrorlanadi).

Tranzaktsiya qanday ishlaydi

Aytaylik, mijoz koordinatorga falon ob'ekt uchun falon asosiy kalit bilan tranzaksiya ochish uchun so'rov yubordi. Koordinator ushbu ob'ektni bloklaydi va uni xotiradagi blokirovka jadvaliga joylashtiradi. Agar kerak bo'lsa, koordinator ushbu ob'ektni saqlashdan o'qiydi va natijada olingan ma'lumotlarni koordinator xotirasida tranzaksiya holatida saqlaydi.

NewSQL = NoSQL+ACID

Mijoz tranzaktsiyadagi ma'lumotlarni o'zgartirmoqchi bo'lsa, u koordinatorga ob'ektni o'zgartirish uchun so'rov yuboradi va koordinator yangi ma'lumotlarni tranzaksiya holati jadvaliga xotiraga joylashtiradi. Bu yozib olishni tugatadi - saqlashga hech qanday yozib olinmaydi.

NewSQL = NoSQL+ACID

Mijoz faol tranzaksiyaning bir qismi sifatida o'zining o'zgartirilgan ma'lumotlarini so'raganda, koordinator quyidagicha harakat qiladi:

  • agar identifikator allaqachon tranzaktsiyada bo'lsa, u holda ma'lumotlar xotiradan olinadi;
  • agar xotirada identifikator bo'lmasa, etishmayotgan ma'lumotlar saqlash tugunlaridan o'qiladi, xotirada bo'lganlar bilan birlashtiriladi va natija mijozga beriladi.

Shunday qilib, mijoz o'z o'zgarishlarini o'qiy oladi, ammo boshqa mijozlar bu o'zgarishlarni ko'rmaydilar, chunki ular faqat koordinator xotirasida saqlanadi, ular hali Kassandra tugunlarida emas.

NewSQL = NoSQL+ACID

Mijoz majburiyatni yuborganida, xizmat xotirasida bo'lgan holat koordinator tomonidan jurnalga kiritilgan to'plamda saqlanadi va jurnalga kiritilgan partiya sifatida Cassandra xotirasiga yuboriladi. Do'konlar ushbu paketning atomik (to'liq) qo'llanilishini ta'minlash uchun zarur bo'lgan hamma narsani qiladilar va qulflarni chiqaradigan va mijozga tranzaktsiyaning muvaffaqiyatini tasdiqlovchi koordinatorga javob qaytaradilar.

NewSQL = NoSQL+ACID

Va orqaga qaytarish uchun koordinator faqat tranzaksiya holati egallagan xotirani bo'shatishi kerak.

Yuqoridagi yaxshilanishlar natijasida biz ACID tamoyillarini amalga oshirdik:

  • Atomlik. Bu tizimda hech qanday tranzaksiya qisman qayd etilmasligini kafolatlaydi, uning barcha suboperatsiyalari tugallanadi yoki hech biri tugallanmaydi. Biz ushbu tamoyilga Kassandrada ro'yxatdan o'tgan partiya orqali amal qilamiz.
  • Muvofiqlik. Har bir muvaffaqiyatli bitim, ta'rifiga ko'ra, faqat haqiqiy natijalarni qayd etadi. Agar tranzaktsiyani ochib, operatsiyalarning bir qismini bajargandan so'ng, natija noto'g'ri ekanligi aniqlansa, orqaga qaytarish amalga oshiriladi.
  • Izolyatsiya. Bitim amalga oshirilganda, bir vaqtning o'zida amalga oshirilgan operatsiyalar uning natijasiga ta'sir qilmasligi kerak. Raqobatchi tranzaktsiyalar koordinatorda pessimistik qulflar yordamida ajratiladi. Tranzaksiyadan tashqarida o'qishlar uchun izolyatsiyalash printsipi O'qishni bajarish darajasida kuzatiladi.
  • Barqarorlik. Quyi darajadagi muammolardan qat'iy nazar - tizimning o'chirilishi, apparatning nosozligi - muvaffaqiyatli yakunlangan tranzaksiya natijasida qilingan o'zgarishlar operatsiyalar qayta boshlanganda saqlanib qolishi kerak.

Indekslar bo'yicha o'qish

Keling, oddiy jadvalni olaylik:

CREATE TABLE photos (
id bigint primary key,
owner bigint,
modified timestamp,
…)

Unda ID (asosiy kalit), egasi va o'zgartirish sanasi mavjud. Siz juda oddiy so'rov qilishingiz kerak - "oxirgi kun uchun" o'zgarish sanasi bilan egasi haqidagi ma'lumotlarni tanlang.

SELECT *
WHERE owner=?
AND modified>?

Bunday so'rovni tezda qayta ishlash uchun klassik SQL DBMSda siz ustunlar bo'yicha indeks yaratishingiz kerak (egasi, o'zgartirilgan). Biz buni juda oson qilishimiz mumkin, chunki endi bizda ACID kafolatlari bor!

C* One-dagi indekslar

Yozuv identifikatori asosiy kalit bo'lgan fotosuratlar bilan manba jadvali mavjud.

NewSQL = NoSQL+ACID

Indeks uchun C*One asl nusxaning nusxasi bo'lgan yangi jadval yaratadi. Kalit indeks ifodasi bilan bir xil va u manba jadvalidagi yozuvning asosiy kalitini ham o'z ichiga oladi:

NewSQL = NoSQL+ACID

Endi "oxirgi kun egasi" so'rovi boshqa jadvaldan tanlov sifatida qayta yozilishi mumkin:

SELECT * FROM i1_test
WHERE owner=?
AND modified>?

Manba jadvalidagi fotosuratlar va i1 indeks jadvalidagi ma'lumotlarning muvofiqligi koordinator tomonidan avtomatik ravishda saqlanadi. Faqatgina ma'lumotlar sxemasiga asoslanib, o'zgarish qabul qilinganda, koordinator o'zgarishlarni nafaqat asosiy jadvalda, balki nusxalarda ham yaratadi va saqlaydi. Indeks jadvalida qo'shimcha harakatlar bajarilmaydi, jurnallar o'qilmaydi va hech qanday qulf ishlatilmaydi. Ya'ni, indekslarni qo'shish deyarli hech qanday resurslarni sarflamaydi va o'zgartirishlarni qo'llash tezligiga deyarli ta'sir qilmaydi.

ACID-dan foydalanib, biz SQL-ga o'xshash indekslarni amalga oshirishga muvaffaq bo'ldik. Ular izchil, kengaytiriladigan, tez, tuziladigan va CQL so'rovlar tiliga o'rnatilgan. Indekslarni qo'llab-quvvatlash uchun dastur kodiga hech qanday o'zgartirish kiritish talab qilinmaydi. Hammasi SQLdagi kabi oddiy. Va eng muhimi, indekslar asl tranzaksiya jadvaliga o'zgartirishlarni bajarish tezligiga ta'sir qilmaydi.

Nima bo'ldi

Biz C*One dasturini uch yil oldin ishlab chiqdik va uni tijorat maqsadlarida foydalanishga topshirdik.

Oxirida nima oldik? Keling, buni ijtimoiy tarmoqdagi eng muhim ma'lumotlar turlaridan biri bo'lgan fotosuratlarni qayta ishlash va saqlash quyi tizimi misolida baholaylik. Biz fotosuratlarning o'zlari haqida emas, balki barcha turdagi meta-ma'lumotlar haqida gapiramiz. Hozir Odnoklassniki-da 20 milliardga yaqin bunday yozuvlar mavjud bo'lib, tizim soniyada 80 ming o'qish so'rovlarini, ma'lumotlarni o'zgartirish bilan bog'liq soniyada 8 mingtagacha ACID tranzaksiyalarini qayta ishlaydi.

Biz replikatsiya koeffitsienti = 1 bo'lgan SQL-dan foydalanganimizda (lekin RAID 10-da), fotosuratning meta-ma'lumoti Microsoft SQL Server bilan ishlaydigan 32 ta mashinadan iborat yuqori darajada mavjud klasterda saqlangan (ortiqcha 11 ta zaxira nusxasi). Zaxira nusxalarini saqlash uchun 10 ta server ham ajratilgan. Hammasi bo'lib 50 ta qimmatbaho mashina. Shu bilan birga, tizim zaxirasiz, nominal yukda ishladi.

Yangi tizimga o'tganimizdan so'ng biz replikatsiya omili = 3 - har bir ma'lumot markazida nusxa oldik. Tizim 63 ta Cassandra saqlash tugunlari va 6 ta koordinator mashinasidan, jami 69 ta serverdan iborat. Ammo bu mashinalar ancha arzon, ularning umumiy qiymati SQL tizimi narxining taxminan 30% ni tashkil qiladi. Shu bilan birga, yuk 30% da saqlanadi.

C*One joriy etilishi bilan kechikish ham kamaydi: SQLda yozish jarayoni taxminan 4,5 ms davom etdi. C*One da - taxminan 1,6 ms. Tranzaktsiyaning davomiyligi o'rtacha 40 ms dan kam, majburiyat 2 msda yakunlanadi, o'qish va yozish davomiyligi o'rtacha 2 ms. 99-persentil - atigi 3-3,1 ms, taym-autlar soni 100 baravar kamaydi - bularning barchasi spekulyatsiyaning keng qo'llanilishi tufayli.

Hozirda SQL Server tugunlarining aksariyati o'chirildi; yangi mahsulotlar faqat C*One yordamida ishlab chiqilmoqda. Biz C*One-ni bulutda ishlashga moslashtirdik bir bulutli, bu yangi klasterlarni joylashtirishni tezlashtirish, konfiguratsiyani soddalashtirish va ishlashni avtomatlashtirish imkonini berdi. Manba kodi bo'lmasa, buni qilish ancha qiyin va mashaqqatli bo'lar edi.

Endi biz boshqa saqlash ob'ektlarimizni bulutga o'tkazish ustida ishlamoqdamiz - ammo bu butunlay boshqacha hikoya.

Manba: www.habr.com

a Izoh qo'shish