1.1 Sharding nima?
Google'da izlab ko'rsangiz, partitioning va sharding o'rtasidagi chegara biroz noaniq ekanini bilib olasiz. Har kim hamma narsani o'zi istagancha nomlaydi. Ba'zi odamlar gorizontal partitioning va shardingni ajratadilar. Boshqalar esa shardingni gorizontal partitioningning bir turi deb aytishadi.
Men ota-bobolar tomonidan ma'qullangan va ISO tomonidan sertifikatlangan yagona terminologik standart topmadim. Shaxsiy ichki ishonchim shunday: Partitioning — bu odatda "bazani bo'laklarga bo'lamiz" degan ma'noni anglatadi.
- Vertical partitioning — ustunlar bo'yicha. Masalan, 60 ta ustunli va ikki milliard yozuvli gigant jadval bor. Bitta shunday gigant jadvalni ushlab turish o'rniga, biz 60 ta shunday katta jadvalni 2 milliard yozuv bilan ushlab turamiz - bu ustunlar bo'yicha emas, balki vertikal partitioning hisoblanadi (terminologiyaning bir misoli sifatida).
- Horizontal partitioning — qatorlarni bo'lamiz, ehtimol server ichida.
Bu yerda noqulay moment shundaki, bu gorizontal partitioning va sharding o'rtasidagi nozik farqdir. Meni bo'laklarga bo'lsangiz ham, lekin men sizga aniq ayta olmayman, uning farqi nimada. Sharding va gorizontal partitioning deyarli bir xil narsa degan his bor.
Sharding — umuman olganda, agar sizda bazalar emas, balki document store bo'lsa, katta jadval bazalar yoki dokumentlar, ob'ektlar to'plamida bo'lib chiqilayotgani. Ya'ni, 2 milliard ob'ektdan bo'laklar olinadi, o'lchami muhim emas. Ob'ektlarni ichida bo'laklarga bo'lib tashlamaymiz, alohida ustunlarga ajratmaymiz, faqat to'plamlarga ajratib, turli joylarga joylashtiramiz.
Shundan so'ng nozik terminologik farqlar kelib chiqadi. Masalan, shartli ravishda, postgres'da ishlab chiquvchilar aytishi mumkin, gorizontal partitioning — bu asosiy jadvalni ajratgan barcha jadvallar bitta sxemada joylashganida, va turli mashinalarda joylashganda — bu sharding.
Umuman olganda, ma'lumotlar bazasi va konkret ma'lumotlar boshqarish tizimiga bog'lanmagan holda, shunday his qilyapman, sharding — bu oddiygina jadvallarni bo'laklarga/dokumentlarga bo'lib qo'yish va hokazo — va hammasi shu.
Ta'kidlab aytaman, odatda. Shunda biz bularni shunchaki, 2 milliard dokumentlarni 20 jadvalga bo'lib, har biri boshqarish mumkin bo'lgan bo'lgan emas, balki bu ko'p yadrolarga, ko'p diskka yoki ko'p turli fizkival yoki virtual serverlarga tarqatish uchun qilamiz.
1.2 Bo'linmaydigan narsani bo'lamiz
Xulosa qilib aytganda, har bir shard — har bir ma'lumot bo'lagini ko'p marta nusxalash uchun qilamiz. Lekin aslida yo'q.
INSERT INTO docs00
SELECT * FROM documents WHERE (id%16)=0
...
INSERT INTO docs15
SELECT * FROM documents WHERE (id%16)=15
Aslida, agar siz ma'lumotlarni shunday bo'lsangiz, va MySQL'dagi bitta gigant SQL jadvalidan o'z kompyuteringizda 16 ta kichik jadvallar hosil qilsangiz, bironta laptop, bironta sxemadan chiqmaydigan, bironta ma'lumotlar bazasidan chiqmaydigan va hokazo — sizda allaqachon sharding bor.
Bu quyidagiga olib keladi:
- Bandwidth oshadi — o'tkazish qobiliyati.
- Latency o'zgarmaydi, ya'ni har bir ishchi yoki consumer bu holatda, o'zini oladi. Barcha so'rovlar taxminan bir vaqtda bajariladi.
- Yoki ikkalasi, va yana high availability (nusxalash).
Nega bandwidth kerak? Ba'zida bizda shunday katta ma'lumotlar miqdori bo'lishi mumkinki, ular joylashmayapti — qayerga joylashmayapti, lekin joylashmayapti — 1 {yadro | disk | server | ...}. Resurs yetishmayapti va shunga. Bu katta dataset bilan ishlash uchun, uni bo'laklarga bo'lish kerak.
Nega latency kerak? Bitta yadroda 2 milliard satrdan iborat jadvalni 20 marta sekinroq skanerlash, 20 jadvalni 20 yadrolarda parallel ravishda skanerlashdan sekinroq. Ma'lumotlar bitta resursda juda sekin ishlanadi.
Nega high availability kerak? Yoki ma'lumotlarni bo'lamiz, shunda ikkalasini ham bir vaqtda bajarish uchun, va shunga bir nechta nusxa har bir sharddan — nusxalash yuqori mavjudlikni ta'minlaydi.
1.3 Oddiy misol "qo'lda qanday qilish"
Shartli shardingni test.documents jadvali orqali 32 dokumentda namuna qilib, va bu jadvaldan 16 test jadallarni taxminan 2 ta hujjat test.docs00, 01, 02, ..., 15 dan hosil qilish orqali amalga oshirish mumkin.
INSERT INTO docs00
SELECT * FROM documents WHERE (id%16)=0
...
INSERT INTO docs15
SELECT * FROM documents WHERE (id%16)=15
Nega taxminan? Chunki apreori, idlar qanday tarqalganligini bilmaymiz, agar 1 dan 32 gacha bo'lsa, har biriga aniq 2 ta hujjat bo'ladi, aks holda — yo'q.
Buning sababini qilamiz. 16 ta jadvalni yaratganimizdan so'ng, biz kerak bo'lgan narsaning 16 tasini "xazm qila olamiz". Nima bo'lishidan qat'i nazar, bu resurslarga parallel bo'lishimiz mumkin. Masalan, disko joy yetishmasa, bu jadvalni alohida disklar bo'ylab tarqatish ma'noga ega bo'ladi.
Bu hammasi, afsuski, bepul emas. Kanonik SQL-standartida (ko'pdan beri SQL-standartni o'qimaganman, ehtimol u ko'pdan beri yangilanmagan) aniq SQL-serverga: "Qadrli SQL-server, menga 32 ta shard yarat va ularni 4 ta diskka joylashtir" deyish uchun standartlashgan sintaksis yo'q deb o'ylayman. Ammo ayrim amalga oshirishlarda, asosiy maqsadni amalga oshirish uchun aniq sintaksis mavjud bo'lib turadi. PostgreSQL'da partitioning uchun mexanizmlar mavjud, MySQL MariaDB bor, Oracle esa ehtimol buni allaqachon bajargan.
Ammo, agar biz bularni qo'lda, ma'lumotlar bazasi qo'llab-quvvatlagan holda va standart doirasida qilsak, ma'lumotlarga kirishning murakkabligi uchun tizim sifati sifatida to'lov qilishingiz mumkin. U erda, SELECT * FROM documents WHERE id=123 oddiy bo'lganda, endi 16 x SELECT * FROM docsXX. Va yaxshi, agar biz yozuvni kalit bo'yicha olishga harakat qilsak. Agar biz oldingi yozuvlar diapazonini olishga harakat qilsak, qiziqroq. Endi (agar biz, ta'kidlayman, go'yo ahmoqona harakatlar qilsak, va biz standart doiralarida qolamiz) bu 16 ta SELECT * FROM natijalarini dasturda birlashtirish kerak bo'ladi.
Qanday o'zgarish kutish kerak?
- Intuitiv — chiziqli.
- Teorik — subchiziqli, chunki Amdahl qonuni.
- Amaliy — deyarli chiziqli yoki yo'q bo'lishi mumkin.
Aslida, to'g'ri javob — noma'lum. Sharding texnikasini chaqqonlik bilan qo'llash orqali dasturingizning ishlashini sezilarli ravishda yomonlashishiga olib kelishingiz mumkin, yana DBA qizigan qo'ygich bilan keladi.
Buni qanday amalga oshirish mumkinligini ko'ramiz. Postgresda shards=16 sozlamasini o'rnatish va keyin u o'zi uchib ketdi — bu qiziq emas. Keling, shunday bir misolni o'ylaylikki, 16 marta shardingdan, 32 ga sekinlashamiz — bu qiziq, bunday qilmaslikka qaraymiz.
Bizning sinovlarimiz har doim klassikaga boradi — qadimgi yaxshi Amdahl qonuniga (Amdahl law), u har doim aytadi, har qanday so'rovning ideal parallelizatsiyasi bo'lmaydi, har doim bir qator ketma-ket qismi mavjud.
1.4 Amdahl law
Har doim serialized qism mavjud.
Har doim so'rovni bajarishning bir qismi parallelizatsiyalanadi va har doim bir qismi parallelizatsiyalanmaydi. Garchi sizga to'liq parallelizatsiyalanadigan so'rovdek tuyulsa ham, natijaviy satroqni yig'ishda, har bir sharddan olingan satrlar, har doim mavjud bo'ladi va u har doim ketma-ket keladi.
Har doim biror ketma-ket qism bor. U juda kichik, umuman e'tiborga olinmaydigan bo'lishi mumkin, u juda katta bo'lishi mumkin va, shunga mos ravishda, parallelizatsiyaga kuchli ta'sir ko'rsatishi mumkin, ammo har doim bor.
Bundan tashqari, uning ta'siri o'zgarishi mumkin va sezilarli darajada oshishi mumkin, masalan, agar biz jadvalni bo'lsek — keling, stavkalarni oshiramiz — 64 yozuvdan 16 jadvalga bo'lsak, ushbu qism o'zgaradi. Albatta, shunday gigant ma'lumotlar hajmlarini biz mobil telefonda va 86 protsessorda 2 MGz ishlamoqdamiz, bizda va fayllar yetmayapti, bir vaqtning o'zida ochiq tutish mumkin bo'lgan. Ehtimol, bunday ma'lumotlar bilan biz bir vaqtning o'zida bir fayl ochamiz.
- Bo'ldi Total = Serial + Parallel. Masalan, parallel — bu DB ichidagi barcha ish, serial — natijani klientga yuborish.
- Bo'ldi Total2 = Serial + Parallel/N + Xserial. Masalan, umumiy ORDER BY, Xserial>0.
Ushbu oddiy misol bilan ko'rsatishga harakat qilaman, Xserial paydo bo'ladi. Bundan tashqari, har doim serializatsiyalanadigan qism bor, va biz ma'lumotlar bilan parallel ravishda ishlashga harakat qilyapmiz, ma'lumotlarni bo'lish qo'shimcha qismi paydo bo'ladi. Qisqasi, bizga kerak bo'lishi mumkin:
- bu 16 ta jadvalni ma'lumotlar bazasi ichki lug'atida topish;
- fayllarni ochish;
- xotirani ajratish;
- xotirani ajratmaslik;
- natijalarni birlashtirish;
- yadrolar orasida sinxronizatsiya qilish.
Ba'zi bir sinxronizatsiya effektlari har doim paydo bo'ladi. Ular juda kichik bo'lishi va umumiy vaqtning bir milliarddan bir qismini egallashi mumkin, lekin har doim noldan katta va har doim mavjud. Ular yordamida biz shardingdan keyin ishlashni sezilarli darajada yo'qotishimiz mumkin.
Bu Amdahl qonuni haqida standart rasm. Bu erda muhim narsa shundaki, ideal holatda to'g'ri bo'lishi kerak bo'lgan chiziqlar lineer o'sib, asimptotaga to'qnashmoqda. Ammo internetdan olingan grafik o'qilmas, menimcha, ko'proq tushunarli raqamlar bilan jadvallar tayyorladim.
Faraz qilaylik, bizda so'rovni qayta ishlashning ba'zi bir serializatsiyalangan qismi bor, u faqat 5%ni tashkil qiladi: serial = 0.05 = 1 / 20.
Intuitiv tarzda, so'rovni qayta ishlashning 1/20 qismini tashkil etadigan serializatsiyalangan qismida, agar biz so'rovni 20 yadroda parallel ravishda bajarsak, u taxminan 20, eng yomoni holatda 18 marta tezroq bo'lar edi.
Aslida matematika — bu befarq narsa:
wall = 0.05 + 0.95/num_cores, speedup = 1 / (0.05 + 0.95/num_cores)
Ma'lum bo'ldiki, agar diqqat bilan hisoblab chiqilganida, 5% serializatsiyalangan qismida tezlashish 10 marta (10,3), bu 51% nazariy idealga nisbatan.
| 8 cores | = 5.9 | = 74% |
| 10 cores | = 6.9 | = 69% |
| 20 cores | = 10.3 | = 51% |
| 40 cores | = 13.6 | = 34% |
| 128 cores | = 17.4 | = 14% |
20 yadro (20 disk, agar xohlasangiz) bir vazifani bajarganida, u hech qachon 20 marta ko'proq tezlashishni nazariy jihatdan ololmaymiz, amalda esa buning natijasi ancha kamayadi. Va parallel sonining ko'payishi bilan, samaradorlik sezilarli darajada o'sib boradi.
Qachonki faqat 1% serializatsiyalangan ish qolganda, va 99 % parallel ishlanadi, tezlik qiymati biroz yaxshilanadi:
| 8 cores | = 7.5 | = 93% |
| 16 cores | = 13.9 | = 87% |
| 32 cores | = 24.4 | = 76% |
| 64 cores | = 39.3 | = 61% |
Tamoman yadroli so'rov uchun, u tabiatda soatlab bajarilayotgan va tayyorlash ishlari va natijani to'plash juda oz vaqt oladigan (serial = 0.001), biz allaqachon yaxshi samaradorlikni ko'ramiz:
| 8 cores | = 7.94 | = 99% |
| 16 cores | = 15.76 | = 99% |
| 32 cores | = 31.04 | = 97% |
| 64 cores | = 60.20 | = 94% |
Diqqat qiling, 100% hech qachon ko'rmaymiz. Maxsus yaxshi hollarda, masalan, 99,999% ko'rish mumkin, lekin aniq 100% emas.
GO TO FULL VERSION