1.1 Vad Àr skÀrning?
Om man ihÀrdigt googlar visar det sig att det Àr en ganska suddig grÀns mellan den sÄ kallade partitioneringen och den sÄ kallade shardingen. Alla ringer vad de vill, vad de vill. Vissa mÀnniskor skiljer mellan horisontell partitionering och skÀrning. Andra sÀger att skÀrning Àr en viss typ av horisontell uppdelning.
Jag hittade inte en enda terminologisk standard som skulle godkÀnnas av grundarna och certifieras av ISO. Personlig inre övertygelse Àr ungefÀr sÄ hÀr: Att partitionera i genomsnitt Àr att "klippa basen i bitar" pÄ ett godtyckligt sÀtt.
- Vertikal partitionering - efter kolumn. Det finns till exempel ett gigantiskt bord med ett par miljarder poster i 60 kolumner. IstÀllet för att behÄlla en sÄdan gigantisk tabell, behÄller vi minst 60 gigantiska tabeller med 2 miljarder poster vardera - och detta Àr inte en kolumnbas, utan vertikal partitionering (som ett exempel pÄ terminologi).
- Horisontell partitionering - vi skÀr rad för rad, kanske inne i servern.
Det besvÀrliga ögonblicket hÀr Àr den subtila skillnaden mellan horisontell uppdelning och skÀrning. Jag kan skÀras i bitar, men jag kan inte sÀga dig sÀkert vad det Àr. Det finns en kÀnsla av att skÀrning och horisontell uppdelning Àr ungefÀr samma sak.
Sharding Àr i allmÀnhet nÀr en stor tabell i termer av databaser eller en pro-samling av dokument, objekt, om du inte har en databas, utan ett dokumentlager, skÀrs exakt av objekt. Det vill sÀga frÄn 2 miljarder objekt vÀljs bitar ut oavsett storlek. SjÀlva föremÄlen inuti varje föremÄl skÀrs inte i bitar, vi lÀgger inte ut dem i separata kolumner, nÀmligen vi lÀgger ut dem i omgÄngar pÄ olika stÀllen.
Det finns subtila terminologiska skillnader. Till exempel, relativt sett, kan Postgres-utvecklare sÀga att horisontell partitionering Àr nÀr alla tabeller som huvudtabellen Àr uppdelad i ligger i samma schema, och nÀr det Àr pÄ olika maskiner, sker detta redan.
I en allmÀn mening, utan att vara bunden till terminologin för en specifik databas och ett specifikt datahanteringssystem, finns det en kÀnsla av att skÀrning bara Àr att skÀra rad för rad / dokument för dokument, och sÄ vidare - det Àr allt.
Jag betonar typiska. I den meningen att vi gör allt detta inte bara för att skÀra 2 miljarder dokument i 20 tabeller, som var och en skulle vara mer hanterbar, utan för att distribuera den över mÄnga kÀrnor, mÄnga diskar eller mÄnga olika fysiska eller virtuella servrar.
1.2 Dela det odelbara
Det Àr underförstÄtt att vi gör detta sÄ att varje skÀrva - varje databit - replikeras mÄnga gÄnger. Men egentligen nej.
INSERT INTO docs00
SELECT * FROM documents WHERE (id%16)=0
...
INSERT INTO docs15
SELECT * FROM documents WHERE (id%16)=15
Faktum Àr att om du gör en sÄdan uppdelning av data, och frÄn en gigantisk SQL-tabell pÄ MySQL pÄ din tappra bÀrbara dator, kommer du att generera 16 smÄ tabeller, utan att gÄ lÀngre Àn en enda bÀrbar dator, inte ett enda schema, inte en enda databas, etc. . och sÄ vidare. - det Àr det, du har redan skÀrvning.
Detta resulterar i följande:
- Bandbredden ökar.
- Latensen förÀndras inte, det vill sÀga var och en, sÄ att sÀga, arbetare eller konsument i detta fall, fÄr sin egen. Olika förfrÄgningar betjÀnas ungefÀr samtidigt.
- Eller bÄda, och en annan, och Àven hög tillgÀnglighet (replikering).
Varför bandbredd? Vi kan ibland ha sÄdana datamÀngder som inte fÄr plats - det Àr inte klart var, men de passar inte - pÄ 1 {kÀrna | disk | server | ...}. Det finns helt enkelt inte tillrÀckligt med resurser, det Àr allt. För att kunna arbeta med denna stora datamÀngd mÄste du klippa den.
Varför latens? PÄ en kÀrna Àr det 20 gÄnger lÄngsammare att skanna en tabell med 2 miljarder rader Àn att skanna 20 tabeller pÄ 20 kÀrnor och göra det parallellt. Data bearbetas för lÄngsamt pÄ en enskild resurs.
Varför hög tillgÀnglighet? Eller sÄ klipper vi data för att göra bÄda samtidigt, och samtidigt flera kopior av varje skÀrva - replikering sÀkerstÀller hög tillgÀnglighet.
1.3 Ett enkelt exempel "hur man gör det för hand"
Villkorlig skÀrning kan skÀras ut med testtabellen test.documents för 32 dokument, och generera 16 testtabeller frÄn denna tabell, cirka 2 dokument vardera test.docs00, 01, 02, ..., 15.
INSERT INTO docs00
SELECT * FROM documents WHERE (id%16)=0
...
INSERT INTO docs15
SELECT * FROM documents WHERE (id%16)=15
Varför ungefÀr? Eftersom vi a priori inte vet hur id fördelas, om frÄn 1 till 32 kommer det att finnas exakt 2 dokument var, annars inte.
Vi gör det hÀr varför. Efter att vi har gjort 16 bord kan vi "ta" 16 av det vi behöver. Oavsett vad vi trÀffar kan vi parallellisera dessa resurser. Till exempel, om det inte finns tillrÀckligt med diskutrymme, skulle det vara vettigt att dekomponera dessa tabeller pÄ separata diskar.
Allt detta Àr tyvÀrr inte gratis. Jag misstÀnker att nÀr det gÀller den kanoniska SQL-standarden (jag har inte lÀst om SQL-standarden pÄ lÀnge, den kanske inte har uppdaterats pÄ lÀnge) sÄ finns det ingen officiell standardiserad syntax för att sÀga till nÄgon SQL-server : "KÀra SQL-server, gör mig 32 shards och dela upp dem i 4 diskar. Men i enskilda implementeringar finns det ofta en specifik syntax för att göra i princip samma sak. PostgreSQL har mekanismer för partitionering, MySQL har MariaDB, Oracle gjorde förmodligen allt detta för lÀnge sedan.
Men om vi gör det för hand, utan databasstöd och inom ramen för standarden, betalar vi villkorligt med dataÄtkomstens komplexitet . DÀr det fanns ett enkelt SELECT * FROM dokument WHERE id=123, nu 16 x SELECT * FROM docsXX. Och det Àr bra om vi försökte fÄ skivan med nyckel. Mycket mer intressant om vi försökte fÄ ett tidigt utbud av skivor. Nu (om vi, jag betonar, Àr, sÄ att sÀga, idioter och förblir inom ramen för standarden), kommer resultaten av dessa 16 SELECT * FROM att behöva kombineras i applikationen.
Vilken prestandaförÀndring kan du förvÀnta dig?
- Intuitivt - linjÀrt.
- Teoretiskt - sublinjÀr, eftersom Amdahl lag.
- Praktiskt taget, kanske nÀstan linjÀrt, kanske inte.
I sjÀlva verket Àr det rÀtta svaret okÀnt. Med en smart tillÀmpning av skÀrningstekniken kan du uppnÄ en betydande superlinjÀr försÀmring av din applikations prestanda, och till och med DBA kommer igÄng med en glödhet poker.
LÄt oss se hur detta kan uppnÄs. Det Àr klart att det inte Àr intressant att bara sÀtta instÀllningen till PostgreSQL shards=16, och sedan tar det fart av sig sjÀlv. LÄt oss fundera pÄ hur vi kan se till att vi saktar ner frÄn skÀrning med 16 gÄnger med 32 - det hÀr Àr intressant ur synvinkeln av hur man inte gör detta.
VÄra försök att snabba upp eller bromsa kommer alltid att stöta pÄ klassikerna - den gamla goda Amdahl-lagen, som sÀger att det inte finns nÄgon perfekt parallellisering av nÄgon begÀran, det finns alltid nÄgon konsekvent del.
1.4 Amdahls lag
Det finns alltid en serialiserad del.
Det finns alltid en del av frĂ„gekörningen som Ă€r parallelliserad, och det finns alltid en del som inte Ă€r parallelliserad. Ăven om det verkar för dig som en perfekt parallell frĂ„ga, finns Ă„tminstone insamlingen av resultatraden som du ska skicka till klienten frĂ„n raderna som tas emot frĂ„n varje skĂ€rva alltid dĂ€r, och den Ă€r alltid sekventiell.
Det finns alltid nÄgon konsekvent del. Den kan vara liten, helt osynlig mot den allmÀnna bakgrunden, den kan vara gigantisk och följaktligen starkt pÄverka parallelliseringen, men den finns alltid.
Dessutom förĂ€ndras dess inflytande och kan vĂ€xa avsevĂ€rt, om vi till exempel skĂ€r vĂ„rt bord â lĂ„t oss höja insatserna â frĂ„n 64 poster till 16 bord med 4 poster, kommer denna del att förĂ€ndras. Naturligtvis, att döma av sĂ„dana gigantiska mĂ€ngder data, arbetar vi pĂ„ en mobiltelefon och en 2 MHz 86-processor, och vi har inte tillrĂ€ckligt med filer som kan hĂ„llas öppna samtidigt. Tydligen öppnar vi med sĂ„dana ingĂ„ngar en fil i taget.
- Det var Totalt = Seriell + Parallell . DÀr till exempel parallell Àr allt arbete inuti DB, och seriell skickar resultatet till klienten.
- Blev Total2 = Seriell + Parallell/N + Xseriell . Till exempel nÀr den totala ORDER BY, Xserial>0.
Med detta enkla exempel försöker jag visa att nÄgot Xserial dyker upp. Förutom att det alltid finns en serialiserad del, och det faktum att vi försöker arbeta med data parallellt, finns det ytterligare en del för att tillhandahÄlla denna dataslicing. Grovt sett kan vi behöva:
- hitta dessa 16 tabeller i databasens interna ordbok;
- öppna filer;
- allokera minne;
- avallokera minne;
- slÄ samman resultat;
- synkronisera mellan kÀrnor.
Vissa effekter som inte Àr synkroniserade visas fortfarande. De kan vara obetydliga och uppta en miljarddel av den totala tiden, men de Àr alltid frÄn noll och alltid dÀr. Med deras hjÀlp kan vi dramatiskt förlora prestanda efter skÀrning.
Detta Àr en standardbild om Amdahls lag. Det viktiga hÀr Àr att linjerna, som helst ska vara raka och vÀxa linjÀrt, löper in i en asymptot. Men eftersom grafen frÄn Internet Àr olÀslig gjorde jag, enligt mig, mer visuella tabeller med siffror.
LÄt oss sÀga att vi har nÄgon serialiserad del av förfrÄgningsbehandlingen som bara tar 5 %: seriell = 0,05 = 1/20 .
Intuitivt verkar det som att med en serialiserad del som bara tar 1/20 av begÀrandebehandlingen, om vi parallelliserar begÀranbearbetningen för 20 kÀrnor, kommer den att bli cirka 20, i vÀrsta fall 18 gÄnger snabbare.
Faktum Àr att matematik Àr en hjÀrtlös sak :
vÀgg = 0,05 + 0,95/antal_kÀrnor, speedup = 1 / (0,05 + 0,95/antal_kÀrnor)
Det visar sig att om man noggrant rÀknar, med en serialiserad del pÄ 5 %, sÄ blir hastigheten 10 gÄnger (10,3), vilket Àr 51 % jÀmfört med det teoretiska idealet.
8 kÀrnor | = 5,9 | = 74 % |
10 kÀrnor | = 6,9 | = 69 % |
20 kÀrnor | = 10,3 | = 51 % |
40 kÀrnor | = 13,6 | = 34 % |
128 kÀrnor | = 17,4 | = 14 % |
Efter att ha anvÀnt 20 kÀrnor (20 diskar, om du vill) för uppgiften som man brukade arbeta med, kommer vi aldrig ens teoretiskt fÄ en acceleration pÄ mer Àn 20 gÄnger, men i praktiken - mycket mindre. Med ett ökat antal paralleller ökar dessutom ineffektiviteten kraftigt.
NÀr endast 1 % av det serialiserade arbetet ÄterstÄr, och 99 % Àr parallelliserat, förbÀttras hastighetshöjningsvÀrdena nÄgot:
8 kÀrnor | = 7,5 | = 93 % |
16 kÀrnor | = 13,9 | = 87 % |
32 kÀrnor | = 24,4 | = 76 % |
64 kÀrnor | = 39,3 | = 61 % |
För en perfekt termonukleÀr frÄga, som naturligtvis tar timmar att slutföra, och det förberedande arbetet och monteringen av resultatet tar vÀldigt lite tid (seriell = 0,001), kommer vi redan att se god effektivitet:
8 kÀrnor | = 7,94 | = 99 % |
16 kÀrnor | = 15,76 | = 99 % |
32 kÀrnor | = 31.04 | = 97 % |
64 kÀrnor | = 60,20 | = 94 % |
Observera att vi aldrig kommer att se 100 % . I sÀrskilt bra fall kan man se till exempel 99,999 %, men inte exakt 100 %.
GO TO FULL VERSION