Alibabin intervjuer: Zašto raditi podelu baze i podelu tabela?
Predgovor
U sistemima sa visokom konkurentnošću, podela baze i podela tabela (sharding) jedna je od neophodnih tehničkih sredstava, a ujedno je i često ispitivano pitanje na intervjuima u velikim kompanijama poput BAT-a.
Znate li zašto radimo podelu baze i podelu tabela?
Ovo pitanje treba objasniti iz dva pravca: vertikalni pravac i horizontalni pravac.
1 Vertikalni pravac
Vertikalni pravac se uglavnom odnosi na biznis; u nastavku ćemo proći vezu između razvoja biznisa i podele baze i tabela.
1.1 Jedna baza (single database)
U početnoj fazi sistema, funkcije biznisa su relativno jednostavne, a sistemski moduli malobrojni.
Da bismo brzo zadovoljili potrebe iteracije i smanjili neke nepotrebne zavisnosti, a što je još važnije, da bismo smanjili složenost sistema i osigurali brzinu razvoja, obično koristimo jednu bazu za čuvanje podataka.
Arhitektura baze u početnoj fazi sistema je sledeća:

U ovom trenutku, rešenje baze podataka je: jedna baza sadrži više poslovnih tabela. Korisnički zahtevi za čitanje i pisanje podataka rade nad istom bazom.
1.2 Podela tabela
Nakon puštanja sistema u rad, sa razvojem biznisa, neprestano se dodaju nove funkcije. To dovodi do toga da jedna tabela ima sve više polja, pa počinje da bude pomalo teška za održavanje.
Jedna tabela korisnika sadrži i po desetine, čak i stotine polja, pa je upravljanje pomalo haotično.
Šta onda raditi?
Odgovor: podela tabela.
Tabela korisnika se podeli na: tabelu osnovnih informacija o korisniku i tabelu proširenih informacija o korisniku.

U tabeli osnovnih informacija o korisniku čuvaju se najvažnije informacije o korisniku, kao što su: korisničko ime, lozinka, nadimak, broj mobilnog, imejl, uzrast, pol i ostali ključni podaci.
Ove informacije su usko povezane sa korisnikom i vrlo se često pretražuju.
U tabeli proširenih informacija o korisniku čuvaju se proširene informacije o korisniku, kao što su: institucija kojoj pripada, mesto prijave prebivališta, grad u kom se nalazi itd. — neključni podaci.
Ove informacije se pretražuju samo u specifičnim poslovnim scenarijima, dok u većini scenarija nisu potrebne.
Zato se kroz podelu tabela ključni i neključni podaci razdvajaju, čime struktura tabele postaje jasnija, odgovornost jedinstvenija, a održavanje lakše.
Pored podele tabela prema stvarnom biznisu, još jedan uobičajeni princip podele tabela je: one sa visokom učestalošću poziva stavljaju se u jednu tabelu, a one sa niskom učestalošću poziva u drugu.
Jedan klasičan primer su: tabela narudžbina i tabela detalja narudžbine.
1.3 Podela baze
Ne primećujući, sistem je već online više od godinu dana. Prošao je kroz N iteracija razvoja zahteva, pa su funkcije veoma potpune.
Kada su funkcije sistema potpune, to znači da su različiti odnosi veza u sistemu zamršeni i složeni.
U ovom trenutku, ako se brzo ne razjasni poslovna logika, kasnije će se pojaviti mnogi skriveni problemi koji će nas ugroziti.
Ovo zahteva podelu na različite domene prema funkciji biznisa. Tabele istog domena stavljaju se u istu bazu, a tabela različitih domena u druge baze.
Konkretan proces cepanja je sledeći:

Tabele vezane za korisnike, proizvode, logistiku i narudžbine se iz prvobitne jedne baze cepaju u zasebnu bazu korisnika, bazu proizvoda, bazu logistike i bazu narudžbina — ukupno četiri baze.
Ovde sam, radi preglednosti, za svaku bazu nacrtao samo po jednu tabelu; u stvarnom scenariju može ih biti više.
Nakon ovakve podele po domenima, svaki domen mora da obraća pažnju samo na tabele koje ga se tiču, odgovornost je jedinstvenija, pa je odjednom postalo lakše za održavanje.
1.4 Podela baze i podela tabela
Ponekad, prema biznisu, samo deljenje baze ili samo deljenje tabela nije dovoljno. Na primer: neki finansijski sistemi moraju da sažmu sredstva svih korisnika po mesecima i godinama.
Zato je potrebno uraditi: podelu baze i podelu tabela.
Svaka godina ima zasebnu bazu, a u svakoj bazi postoji 12 tabela; svaka tabela čuva podatke o korisničkim sredstvima za jedan mesec.

Nakon ovakve podele baze i tabela, može se veoma efikasno pretražiti sredstva nekog korisnika po mesecima ili godinama.
Pored toga, postoje i neke specifičnije potrebe, kao što je podela baze prema regionu, na primer: Centralna Kina, Severna Kina, Južna Kina itd., pri čemu svaki region ima posebnu bazu.
Čak i neke platforme za igre vrše podelu baze i tabela prema priključenim proizvođačima igara.
2 Horizontalni pravac
Horizontalni pravac se uglavnom odnosi na podatke; u nastavku ćemo proći vezu između podataka i podele baze i tabela.
2.1 Jedna baza
U početnoj fazi sistema, pošto je korisnika veoma malo, konkurentnost sistema je mala. Takođe, količina podataka u tabelama je veoma mala.
Arhitektura baze u ovom trenutku je sledeća:

U ovom trenutku, rešenje baze podataka je isto: jedna master baza sadrži više poslovnih tabela.
Korisnički zahtevi za čitanje i pisanje podataka rade nad istom bazom; ovo rešenje je prilično pogodno za poslovne scenarije sa veoma niskom konkurentnošću.
2.2 Master-slave razdvajanje čitanja i pisanja
Nakon što je sistem određeno vreme online, broj korisnika je porastao.
Tada ćete otkriti da u korisničkim zahtevima zahtevi za čitanje podataka čine većinu, dok je stvarni udeo zahteva za pisanje podataka veoma mali.
Kao što je poznato, veze sa bazom podataka su konačne, to je veoma dragocen resurs. Svaki zahtev za čitanje ili pisanje u bazi zauzima najmanje jednu vezu sa bazom.
Ako veze sa bazom potrebne za zahteve za pisanje budu zauzete zahtevima za čitanje, zar nećemo moći da pišemo podatke?
Tada problem postaje ozbiljan.
Da bismo rešili ovaj problem, moramo da razdvojimo bazu za čitanje i bazu za pisanje.
Tako se pojavila arhitektura master-slave razdvajanja čitanja i pisanja:

S obzirom na to da u početku broj korisnika još nije toliko veliki, bira se jedan master, jedan slave arhitektura, odnosno ono što se često zove jedan master i jedan slave.
Svi zahtevi za pisanje podataka idu na master bazu. Čim master baza upiše podatke, odmah ih asinhrono sinhronizuje na slave bazu. Tako svi zahtevi za čitanje podataka mogu blagovremeno da dobiju podatke iz slave baze (osim ako postoji mrežno kašnjenje).
Rešenje razdvajanja čitanja i pisanja može rešiti gore pomenuti problem jedne tačke; u poređenju sa rešenjem jedne baze, može bolje da osigura stabilnost sistema.
Jer ako master baza padne, slave baza se može unaprediti u master, pa se svi zahtevi za čitanje i pisanje usmere na novu master bazu i sistem ponovo radi normalno.
Rešenje razdvajanja čitanja i pisanja zapravo je vrsta podele baze; ono relativno govoreći pravi rezervnu kopiju podataka i postalo je prvo rešenje u početnoj fazi sistema.
Ali ovde postoji problem: ako je broj korisnika zaista pomelo veliki, a master padne, slave se unapredi u master i svi zahtevi za čitanje i pisanje usmere na novi master.
Ali šta ako tada taj novi master uopšte ne može da izdrži sve zahteve za čitanje i pisanje?
Zato je potrebna arhitektura jedan master, više slave-ova:

Na gornjoj slici prikazano je jedan master, dva slave-a; ako master padne, može se izabrati jedan od slavova 1 ili 2 i unaprediti ga u novi master. Ako ovde slave 1 unapredimo u novi master, onda prvobitni slave 2 postaje slave novog master-a.
Arhitektonski dijagram nakon prilagođavanja je sledeći:

Ovim se rešava gore navedeni problem.
Pored toga, ako se količina zahteva za pretraživanje dodatno poveća, arhitekturu možemo nadgraditi u jedan master tri slava, jedan master četiri slava ... jedan master N slavova itd.
2.3 Podela baze
Gore navedeno rešenje razdvajanja čitanja i pisanja zaista može rešiti problem da master čvor ne izdrži kada su zahtevi za čitanje brojniji od zahteva za pisanje. Ali ako u nekom domenu, na primer bazi korisnika, količina zahteva za registraciju korisnika bude veoma velika, odnosno sam obim zahteva za pisanje bude veliki, jedna master baza ne može da podnese toliki pritisak.
Šta onda raditi?
Odgovor: napraviti više baza korisnika.
Proces cepanja baze korisnika je sledeći:

Ovde sam bazu korisnika podelio u tri baze (u stvarnom scenariju ne mora biti tako); struktura tabela svake baze je potpuno ista, samo su pohranjeni podaci različiti.
2.4 Podela tabela
Kada količina korisničkih zahteva poraste, neminovno raste i količina podataka. Čak i uz podelu baze, može se desiti da jedna baza, na primer baza korisnika, dostigne 50 miliona podataka.
Prema iskustvenoj vrednosti, količina podataka u jednoj tabeli treba da se drži ispod 10 miliona radi najboljih performansi. Ako postoji količina podataka od desetine miliona, čuvanje u jednoj tabeli će dovesti do vrlo loših performansi.
Ako je količina podataka prevelika, indeks koji treba izgraditi biće takođe veliki; pretraživanje podataka je veoma vremenski zahtevno i jako troši CPU resurse.
Šta onda raditi?
Odgovor: podela tabela, čime se kontroliše količina podataka i veličina indeksa svake tabele.
Proces cepanja tabele je sledeći:

Ovde sam tabelu korisnika u bazi korisnika podelio u četiri tabele (u stvarnom scenariju ne mora biti tako); struktura svake tabele je potpuno ista, samo su pohranjeni podaci različiti.
Ako broj korisničkih podataka kasnije postane sve veći, dovoljno je dodati još nekoliko korisničkih tabela.
2.5 Podela baze i podela tabela
Kada sistem razvije do određene faze, korisnička konkurentnost je velika, a i količina podataka koje treba čuvati je veliki. Šta onda raditi?
Odgovor: potrebno je uraditi podelu baze i podelu tabela.
Kao što je prikazano na slici:

Na slici je baza korisnika podeljena u tri baze, a svaka baza sadrži četiri korisničke tabele.
Kada stigne korisnički zahtev, najpre se na osnovu korisničkog id-a rutira do jedne od baza korisnika, a zatim pozicionira do neke tabele.
Algoritama rutiranja ima prilično:
Moduo prema id-u, na primer: id=7, postoje 4 tabele, pa je 7%4=3, moduo je 3, rutira do tabele korisnika 3.Zadavanje intervala za id, na primer: vrednost id-a je 0-100000, pa se podaci čuvaju u tabeli korisnika 0; vrednost id-a je 100000-200000, pa se podaci čuvaju u tabeli korisnika 1.Algoritam konzistentnog heširanja
Ovaj članak neće previše ulaziti u detalje; kasnije će postojati članak koji posebno predstavlja ove algoritme rutiranja.
3 Stvarni slučajevi
Dalje, bez mnogo priče, podeliću s vama tri iskustva sa projektima podele baze i tabela u kojima sam učestvovao, kao referencu prijateljima kojima je potrebno.
3.1 Podela baze
Ranije sam radio u jednoj kompaniji; naš tim se bavio operacijama igara. Naša kompanija pruža platformu, proizvođači igara se priključuju na našu platformu i promovišu svoje igre.
Igrači se prijavljuju preko naše platforme, a nakon uspeha se preusmeravaju na specificiranu stranicu igre proizvođača, pa taj igrač može normalno da igra igru i takođe može da dopuni igračije novčiće.
Zato je potrebno uspostaviti mapiranje između našeg sistema naloga i naloga proizvođača igara; igrači se prijavljuju na nalog igre na našoj platformi, a nakon uspeha se konvertuju u nalog na sopstvenoj platformi proizvođača igara.
Ovde postoje dva problema:
- Način priključenja svakog proizvođača igara može biti drugačiji, a i odnos mapiranja sistema naloga ima razlike.
- Korisnici se prijavljuju sa naše platforme, a nakon uspeha se preusmeravaju na stranicu igre proizvođača. Tada je bilo priključeno N proizvođača igara, broj aktivnih igrača je bio veliki, pa konkurentnost na interfejsu za prijavu nije bila zanemarljiva.
Da bismo rešili ova dva problema, tada smo usvojili rešenje: podela baze. Odnosno za svaku igru se posebno pravi jedna baza, a struktura tabela u bazi sme da se razlikuje.

Tada nismo išli dalje u podelu tabela, jer smo razmišljali o broju korisnika svake vrste igre, koji još nije bio apsurdno veliki. Za razliku od fenomenskih igara poput Honor of Kings, koje imaju stotine miliona igrača.
Jedno od ključnih mesta je: u interfejs za prijavu treba proslediti polje game id, preko kojeg sistem zna kojom bazom da radi, jer ime baze već sadrži informaciju o game id-u.
3.2 Podela tabela
I u toj istoj kompaniji platforme za igre imali smo još jedan biznis: Gold Diamond članstvo.
Suštinski je u pitanju izgradnja sistema članstva vezanog za igre; da bi se održala aktivnost korisnika, otvaranje članstva nosi mnoge beneficije, kao što su: poklonski igrajići novčići, popusti na dopune, zamena poena, nagradne igre, namenska korisnička podrška itd.
U ovom sistemu članstva postoji jedna veoma važna funkcija: poeni.
Korisnici mogu da dobiju poene na mnogo načina, kao što su: prijava, dopuna, igranje igara, nagradne igre, promocija, učestvovanje u aktivnostima itd.
Koja je svrha poena?
- Zamena za fizičke poklone
- Zamena za igračije novčiće
- Nagradne igre
Rekavši sve ovo, zapravo želim da kažem da jedan korisnik tokom dana može više puta da dobija ili troši poene, pa jedan korisnik može proizvesti i po desetine zapisa u jednom danu.
Ako je korisnika mnogo, količina podataka vezanih za poene zapravo prilično iznenađujuća.
Tada smo razmišljali da bi količina podataka u horizontalnom pravcu mogla biti veoma velika, ali korisnička konkurentnost nije velika, za razliku od interfejsa za prijavu.
Zato je usvojeno rešenje: podela tabela.
Tada je bila dovoljna jedna baza poena, ali je podeljena na 128 tabela. Zatim se na osnovu korisničkog id-a vrši heš, deli sa 128 i uzima ostatak.

Posebno treba obratiti pažnju na to da je broj tabela najbolje da bude stepen dvojke, radi lakšeg proširenja kapaciteta kasnije.
3.3 Podela baze i podela tabela
Kasnije sam prešao u kompaniju koja se bavi razvojem softvera za restorane. Ova kompanija ima osobinu da u svakodnevnim vrhuncima ručka i večere korisnička konkurentnost bude veoma velika.
Pre jela, korisnik mora preko našeg sistema da naruči hranu, zatim da podnese narudžbinu, a onda i da plati. Tada su konkurentnost naručivanja i podnošenja narudžbine bile prilično velike.
U restoranu može biti mnogo ljudi, a svako može podneti više narudžbina. To dovodi do visoke korisničke konkurentnosti i velike količine podataka.
Zato, nakon sveobuhvatnog razmatranja, tada smo usvojili tehničko rešenje: podela baze i podela tabela.
Nakon istraživanja, odlučili smo se za JDBC zasnovan okvir middleware-a koji je Dangdang otvorio: sharding-jdbc.
Tada su podeljene 4 baze, a svaka baza je imala 32 tabele.

4 Rezime
Gore smo uglavnom iz dva pravca — vertikalnog i horizontalnog — predstavili zašto naš sistem radi podelu baze i podele tabela.
Iskreno, vertikalni pravac (odnosno poslovni pravac) je jednostavniji.
U horizontalnom pravcu (odnosno pravcu podataka), uloga podele baze i podele tabela se zapravo razlikuje i ne mogu se poistovetiti.
Podela baze: služi da reši problem nedostatka resursa veza sa bazom i problem uskih grla performansi diskovnog IO-a.Podela tabela: služi da reši problem previše velike količine podataka u jednoj tabeli, zbog koje SQL upit, čak i uz korišćenje indeksa, ostaje veoma vremenski zahtevan. Pored toga može rešiti i problem trošenja CPU resursa.Podela baze i podela tabela: može rešiti probleme kao što su nedostatak resursa veza sa bazom, uska grla performansi diskovnog IO-a, vremenska zahtevnost pretraživanja podataka i trošenje CPU resursa.
Ako u nekim poslovnim scenarijima korisnička konkurentnost bude velika, ali količina podataka koju treba sačuvati bude malena, tada se može samo podeliti baza, bez podele tabela.
Ako u nekim poslovnim scenarijima korisnička konkurentnost bude mala, ali količina podataka koju treba sačuvati bude velika, tada se može samo podeliti tabele, bez podele baze.
Ako u nekim poslovnim scenarijima korisnička konkurentnost bude velika i količina podataka koju treba sačuvati bude velika, može se raditi i podela baze i podela tabela.
Link za preuzimanje: https://mp.weixin.qq.com/s/klkD8xea0gQ96Mh1Q1MHLw, Izvor: macrozheng, Priredio: Chenmo Wang Er
