Više programera bi trebalo da zna ovo o bazama podataka

Bilješka. transl.: Jaana Dogan je iskusan inženjer u Google-u koji trenutno radi na vidljivosti proizvodnih usluga kompanije napisane na Go-u. U ovom članku, koji je stekao veliku popularnost među publikom engleskog govornog područja, sakupila je u 17 tačaka važne tehničke detalje u vezi sa DBMS-ovima (i ponekad distribuiranim sistemima općenito) koje je korisno uzeti u obzir za programere velikih/zahtjevnih aplikacija.

Više programera bi trebalo da zna ovo o bazama podataka

Velika većina računarskih sistema prati svoje stanje i, shodno tome, zahtevaju neku vrstu sistema za skladištenje podataka. Akumulirao sam znanje o bazama podataka tokom dugog vremenskog perioda, usput praveći greške u dizajnu koje su dovele do gubitka podataka i prekida rada. U sistemima koji obrađuju velike količine informacija, baze podataka leže u srcu arhitekture sistema i djeluju kao ključni element u odabiru optimalnog rješenja. Unatoč činjenici da se velika pažnja posvećuje radu baze podataka, problemi koje programeri aplikacija pokušavaju predvidjeti često su samo vrh ledenog brega. U ovoj seriji članaka dijelim neke ideje koje će biti korisne programerima koji nisu specijalizirani za ovu oblast.

  1. Imate sreće ako 99,999% vremena mreža ne uzrokuje probleme.
  2. KISELINA znači mnogo različitih stvari.
  3. Svaka baza podataka ima svoje mehanizme za osiguranje konzistentnosti i izolacije.
  4. Optimistično blokiranje dolazi u pomoć kada je teško održati uobičajeno.
  5. Postoje i druge anomalije osim prljavog čitanja i gubitka podataka.
  6. Baza podataka i korisnik se ne slažu uvijek o toku akcije.
  7. Sharding na nivou aplikacije može se premjestiti izvan aplikacije.
  8. Autoinkrementiranje može biti opasno.
  9. Zastarjeli podaci mogu biti korisni i ne moraju biti zaključani.
  10. Distorzije su tipične za bilo koje vremenske izvore.
  11. Kašnjenje ima mnogo značenja.
  12. Zahtjeve učinka treba procijeniti za određenu transakciju.
  13. Ugniježđene transakcije mogu biti opasne.
  14. Transakcije ne bi trebale biti vezane za stanje aplikacije.
  15. Planeri upita mogu vam puno reći o bazama podataka.
  16. Online migracija je teška, ali moguća.
  17. Značajno povećanje baze podataka povlači povećanje nepredvidljivosti.

Želio bih zahvaliti Emmanuelu Odekeu, Reinu Henrichsu i drugima na povratnim informacijama o ranijoj verziji ovog članka.

Imate sreće ako 99,999% vremena mreža ne uzrokuje probleme.

Ostaje pitanje koliko su moderne mrežne tehnologije pouzdane i koliko često sistemi padaju u kvar zbog kvarova na mreži. Informacije o ovom pitanju su oskudne, a istraživanjem često dominiraju velike organizacije sa specijalizovanim mrežama, opremom i osobljem.

Sa stopom dostupnosti od 99,999% za Spanner (Googleova globalno distribuirana baza podataka), Google tvrdi da samo 7,6% problemi su povezani sa mrežom. Istovremeno, kompanija svoju specijalizovanu mrežu naziva „glavnim stubom“ visoke dostupnosti. Studija Bailis i Kingsbury, sproveden 2014. godine, dovodi u pitanje jednu od “zablude o distribuiranom računarstvu“, koji je Peter Deutsch formulisao 1994. godine. Je li mreža zaista pouzdana?

Sveobuhvatno istraživanje izvan gigantskih kompanija, sprovedeno za širi internet, jednostavno ne postoji. Također nema dovoljno podataka od glavnih igrača o tome koliki je postotak problema njihovih korisnika povezan s mrežom. Dobro smo svjesni prekida u mreži velikih provajdera oblaka koji mogu oboriti cijeli dio interneta na nekoliko sati samo zato što su to događaji visokog profila koji utiču na veliki broj ljudi i kompanija. Prekidi mreže mogu uzrokovati probleme u mnogo više slučajeva, čak i ako nisu svi ti slučajevi u centru pažnje. Klijenti cloud servisa također ne znaju ništa o uzrocima problema. Ako dođe do kvara, gotovo ga je nemoguće pripisati mrežnoj grešci na strani provajdera usluge. Za njih su usluge trećih strana crne kutije. Nemoguće je procijeniti uticaj ako niste veliki pružalac usluga.

S obzirom na ono što veliki igrači izvještavaju o svojim sistemima, sa sigurnošću se može reći da imate sreće ako mrežne poteškoće predstavljaju samo mali postotak potencijalnih problema s prekidima. Mrežne komunikacije i dalje pate od svakodnevnih stvari kao što su kvarovi na hardveru, promjene topologije, promjene administrativne konfiguracije i nestanci struje. Nedavno sam bio iznenađen kada sam saznao da je lista mogućih problema dodata ajkula ugriza (da, dobro ste čuli).

ACID znači mnogo različitih stvari

Akronim ACID je skraćenica za atomičnost, konzistentnost, izolaciju, pouzdanost. Ova svojstva transakcija imaju za cilj da osiguraju njihovu valjanost u slučaju kvarova, grešaka, kvarova hardvera itd. Bez ACID-a ili sličnih šema, programerima aplikacija bilo bi teško da razlikuju za šta su oni odgovorni i za šta je odgovorna baza podataka. Većina relacionih transakcijskih baza podataka pokušava da bude kompatibilna sa ACID, ali novi pristupi kao što je NoSQL doveli su do mnogih baza podataka bez ACID transakcija jer su skupe za implementaciju.

Kada sam prvi put ušao u industriju, naš tehnički voditelj je govorio o tome koliko je koncept ACID relevantan. Da budemo pošteni, ACID se smatra grubim opisom, a ne strogim standardom implementacije. Danas ga smatram uglavnom korisnim jer pokreće specifičnu kategoriju pitanja (i predlaže niz mogućih rješenja).

Nije svaki DBMS kompatibilan sa ACID; Istovremeno, implementacije baze podataka koje podržavaju ACID različito razumiju skup zahtjeva. Jedan od razloga zašto su ACID implementacije neujednačene je zbog mnogih kompromisa koji se moraju napraviti da bi se implementirali ACID zahtjevi. Kreatori mogu predstaviti svoje baze podataka kao kompatibilne sa ACID-om, ali interpretacija rubnih slučajeva može dramatično varirati, kao i mehanizam za rukovanje "nevjerovatnim" događajima. U najmanju ruku, programeri mogu steći razumijevanje na visokom nivou zamršenosti osnovnih implementacija kako bi stekli pravilno razumijevanje njihovog posebnog ponašanja i kompromisa u dizajnu.

Debata o tome da li MongoDB ispunjava zahtjeve ACID nastavlja se čak i nakon izdavanja verzije 4. MongoDB već dugo nije podržan logging, iako su prema zadanim postavkama podaci predavani na disk ne više od jednom svakih 60 sekundi. Zamislite sljedeći scenario: aplikacija objavljuje dva upisivanja (w1 i w2). MongoDB uspješno pohranjuje w1, ali w2 je izgubljen zbog kvara na hardveru.

Više programera bi trebalo da zna ovo o bazama podataka
Dijagram koji ilustruje scenario. MongoDB se ruši prije nego što može zapisati podatke na disk

Urezivanje na disk je skup proces. Izbjegavajući česta urezivanja, programeri poboljšavaju performanse snimanja nauštrb pouzdanosti. MongoDB trenutno podržava evidentiranje, ali prljavi zapisi i dalje mogu utjecati na integritet podataka jer se logovi po defaultu snimaju svakih 100 ms. Odnosno, sličan scenarij je i dalje moguć za dnevnike i promjene prikazane u njima, iako je rizik mnogo manji.

Svaka baza podataka ima svoju konzistentnost i mehanizme izolacije

Od ACID zahtjeva, konzistentnost i izolacija imaju najveći broj različitih implementacija jer je raspon kompromisa širi. Mora se reći da su konzistentnost i izolacija prilično skupe funkcije. Oni zahtijevaju koordinaciju i povećavaju konkurenciju za konzistentnost podataka. Složenost problema se značajno povećava kada je potrebno horizontalno skalirati bazu podataka u više centara podataka (naročito ako se nalaze u različitim geografskim regijama). Postizanje visokog nivoa konzistentnosti je veoma teško jer takođe smanjuje dostupnost i povećava segmentaciju mreže. Za općenitije objašnjenje ovog fenomena, savjetujem vam da pogledate CAP teorema. Također je vrijedno napomenuti da se aplikacije mogu nositi s malim količinama nedosljednosti, a programeri mogu razumjeti nijanse problema dovoljno dobro da implementiraju dodatnu logiku u aplikaciji za rješavanje nedosljednosti, a da se u velikoj mjeri ne oslanjaju na bazu podataka da bi to riješili.

DBMS-ovi često pružaju različite nivoe izolacije. Programeri aplikacija mogu izabrati najefikasniji na osnovu svojih preferencija. Niska izolacija omogućava povećanu brzinu, ali i povećava rizik od trke podataka. Visoka izolacija smanjuje ovu vjerovatnoću, ali usporava rad i može dovesti do konkurencije, što će dovesti do takvih kočnica u bazi da počnu kvarovi.

Više programera bi trebalo da zna ovo o bazama podataka
Pregled postojećih modela konkurentnosti i odnosa između njih

SQL standard definira samo četiri nivoa izolacije, iako ih u teoriji i praksi ima mnogo više. Jepson.io nudi odličan pregled postojećih modela konkurentnosti. Na primjer, Google Spanner garantuje eksternu serijalizaciju sa sinhronizacijom sata, i iako je ovo stroži izolacijski sloj, nije definiran u standardnim izolacijskim slojevima.

SQL standard spominje sljedeće razine izolacije:

  • Serializable (najstroži i najskuplji): Izvršenje koje se može serijalizirati ima isti učinak kao neko sekvencijalno izvršenje transakcije. Sekvencijalno izvršenje znači da svaka sljedeća transakcija počinje tek nakon što je prethodna završena. Treba napomenuti da je nivo Serializable često implementirana kao takozvana izolacija snimaka (na primjer, u Oracleu) zbog razlika u interpretaciji, iako sama izolacija snimaka nije predstavljena u SQL standardu.
  • Ponovljiva čitanja: Nepovezani zapisi u trenutnoj transakciji dostupni su trenutnoj transakciji, ali promjene napravljene od strane drugih transakcija (kao što su novi redovi) nije vidljivo.
  • Čitanje posvećeno: Nepovezani podaci nisu dostupni za transakcije. U ovom slučaju, transakcije mogu vidjeti samo predane podatke i može doći do fantomskog čitanja. Ako transakcija ubaci i urezuje nove redove, trenutna transakcija će ih moći vidjeti kada se postavi upit.
  • Read uncommitted (najmanje strogi i skupi nivo): prljavo čitanje je dozvoljeno, transakcije mogu vidjeti neobjavljene promjene napravljene drugim transakcijama. U praksi, ovaj nivo može biti koristan za grube procjene, kao što su upiti COUNT(*) na stolu.

nivo Serializable minimizira rizik od trka podataka, dok je najskuplji za implementaciju i rezultira najvećim konkurentskim opterećenjem na sistemu. Drugi nivoi izolacije su lakši za implementaciju, ali povećavaju vjerovatnoću trka podataka. Neki DBMS vam omogućavaju da postavite prilagođeni nivo izolacije, drugi imaju jake preferencije i nisu podržani svi nivoi.

Podrška za nivoe izolacije se često oglašava u datom DBMS-u, ali samo pažljivo proučavanje njegovog ponašanja može otkriti šta se zapravo dešava.

Više programera bi trebalo da zna ovo o bazama podataka
Pregled anomalija istovremenosti na različitim nivoima izolacije za različite DBMS-ove

Martin Kleppmann u svom projektu pustinjaka Upoređuje različite nivoe izolacije, govori o anomalijama konkurentnosti i da li je baza podataka u stanju da se pridržava određenog nivoa izolacije. Kleppmannovo istraživanje pokazuje koliko različito programeri baza podataka razmišljaju o nivoima izolacije.

Optimistično blokiranje dolazi u pomoć kada je teško održati uobičajeno.

Blokiranje može biti veoma skupo, ne samo zato što povećava konkurenciju u bazi podataka, već i zato što zahteva od servera aplikacija da se stalno povezuju sa bazom podataka. Segmentacija mreže može pogoršati situacije isključivanja zaključavanja i dovesti do zastoja koje je teško identificirati i riješiti. U slučajevima kada ekskluzivno zaključavanje nije prikladno, optimistično zaključavanje pomaže.

Optimistična brava je metoda u kojoj prilikom čitanja niza uzima u obzir njegovu verziju, kontrolni zbroj ili vrijeme posljednje izmjene. Ovo vam omogućava da osigurate da nema promjene atomske verzije prije promjene unosa:

UPDATE products
SET name = 'Telegraph receiver', version = 2
WHERE id = 1 AND version = 1

U ovom slučaju, ažuriranje tabele products neće se izvršiti ako je neka druga operacija prethodno izvršila promjene u ovom redu. Ako na ovom redu nisu izvršene druge operacije, doći će do promjene za jedan red i možemo reći da je ažuriranje bilo uspješno.

Postoje i druge anomalije osim prljavog čitanja i gubitka podataka

Kada je u pitanju konzistentnost podataka, fokus je na potencijalnim uslovima trke koji mogu dovesti do prljavog čitanja i gubitka podataka. Međutim, anomalije podataka tu ne prestaju.

Jedan primjer takvih anomalija je izobličenje snimanja (napiši iskrivljene). Distorzije je teško otkriti jer se obično ne traže aktivno. Oni nisu zbog prljavog čitanja ili gubitka podataka, već zbog kršenja logičkih ograničenja postavljenih na podatke.

Na primjer, uzmimo u obzir aplikaciju za praćenje koja zahtijeva da jedan operater uvijek bude dežuran:

BEGIN tx1;                      BEGIN tx2;
SELECT COUNT(*)
FROM operators
WHERE oncall = true;
0                               SELECT COUNT(*)
                                FROM operators
                                WHERE oncall = TRUE;
                                0
UPDATE operators                UPDATE operators
SET oncall = TRUE               SET oncall = TRUE
WHERE userId = 4;               WHERE userId = 2;
COMMIT tx1;                     COMMIT tx2;

U gornjoj situaciji, doći će do oštećenja zapisa ako su obje transakcije uspješno izvršene. Iako nije bilo prljavog čitanja ili gubitka podataka, integritet podataka je bio ugrožen: sada se dvije osobe smatraju dežurnima u isto vrijeme.

Izolacija koja se može serijalizirati, dizajn sheme ili ograničenja baze podataka mogu pomoći da se eliminira oštećenje pisanja. Programeri moraju biti u stanju da identifikuju takve anomalije tokom razvoja kako bi ih izbjegli u proizvodnji. U isto vrijeme, izobličenja snimanja je izuzetno teško tražiti u bazi koda. Posebno u velikim sistemima, kada su različiti razvojni timovi odgovorni za implementaciju funkcija zasnovanih na istim tabelama i ne slažu se oko specifičnosti pristupa podacima.

Baza podataka i korisnik se ne slažu uvijek oko toga šta da rade

Jedna od ključnih karakteristika baza podataka je garancija naloga za izvršenje, ali sam ovaj nalog možda neće biti transparentan za programera softvera. Baze podataka izvršavaju transakcije onim redosledom kojim su primljene, a ne redosledom koji programeri nameravaju. Redoslijed transakcija je teško predvidjeti, posebno u visoko opterećenim paralelnim sistemima.

Tokom razvoja, posebno kada se radi sa bibliotekama koje ne blokiraju, loš stil i slaba čitljivost mogu dovesti do toga da korisnici poveruju da se transakcije izvršavaju sekvencijalno, dok u stvari mogu stići u bazu podataka bilo kojim redosledom.

Na prvi pogled, u programu ispod, T1 i T2 se pozivaju sekvencijalno, ali ako su ove funkcije neblokirajuće i odmah vraćaju rezultat u obliku obećanje, tada će redoslijed poziva biti određen prema momentima kada su ušli u bazu podataka:

result1 = T1() // pravi rezultati su obećanja
rezultat2 = T2()

Ako je potrebna atomičnost (to jest, sve operacije moraju biti dovršene ili prekinute) i redoslijed je važan, tada se operacije T1 i T2 moraju izvesti unutar jedne transakcije.

Sharding na nivou aplikacije može se premjestiti izvan aplikacije

Sharding je metoda horizontalnog particioniranja baze podataka. Neke baze podataka mogu automatski podijeliti podatke horizontalno, dok druge ne mogu, ili nisu baš dobre u tome. Kada arhitekti/programeri podataka budu u stanju da predvide kako će se tačno pristupiti podacima, oni mogu kreirati horizontalne particije u korisničkom prostoru umesto da delegiraju ovaj posao bazi podataka. Ovaj proces se zove "dijeljenje na nivou aplikacije" (sharing na nivou aplikacije).

Nažalost, ovo ime često stvara zabludu da dijeljenje živi u aplikacijskim servisima. Zapravo, može se implementirati kao poseban sloj ispred baze podataka. Ovisno o rastu podataka i iteracijama sheme, zahtjevi za dijeljenjem mogu postati prilično složeni. Neke strategije mogu imati koristi od mogućnosti ponavljanja bez ponovnog postavljanja poslužitelja aplikacija.

Više programera bi trebalo da zna ovo o bazama podataka
Primjer arhitekture u kojoj su aplikacijski poslužitelji odvojeni od servisa dijeljenja

Premještanje dijeljenja u zasebnu uslugu proširuje mogućnost korištenja različitih strategija dijeljenja bez potrebe za ponovnim postavljanjem aplikacija. Vitess je primjer takvog sistema dijeljenja na nivou aplikacije. Vitess pruža horizontalno dijeljenje za MySQL i omogućava klijentima da se povežu na njega putem MySQL protokola. Sistem segmentira podatke u različite MySQL čvorove koji ne znaju ništa jedan o drugom.

Autoinkrementiranje može biti opasno

AUTOINCREMENT je uobičajen način generiranja primarnih ključeva. Često postoje slučajevi kada se baze podataka koriste kao ID generatori, a baza podataka sadrži tabele dizajnirane za generisanje identifikatora. Postoji nekoliko razloga zašto je generiranje primarnih ključeva pomoću automatskog inkrementiranja daleko od idealnog:

  • U distribuiranoj bazi podataka, automatsko povećanje je ozbiljan problem. Za generiranje ID-a potrebno je globalno zaključavanje. Umjesto toga, možete generirati UUID: ovo ne zahtijeva interakciju između različitih čvorova baze podataka. Automatsko povećanje pomoću zaključavanja može dovesti do svađe i značajno smanjiti performanse na umetcima u distribuiranim situacijama. Neki DBMS-ovi (na primjer, MySQL) mogu zahtijevati posebnu konfiguraciju i pažljiviju pažnju kako bi se pravilno organizirala master-master replikacija. I lako je pogriješiti prilikom konfiguriranja, što će dovesti do neuspjeha snimanja.
  • Neke baze podataka imaju algoritme za particioniranje zasnovane na primarnim ključevima. Uzastopni ID-ovi mogu dovesti do nepredvidivih vrućih tačaka i povećanog opterećenja na nekim particijama dok druge ostaju neaktivne.
  • Primarni ključ je najbrži način za pristup redu u bazi podataka. Uz bolje načine za identifikaciju zapisa, sekvencijalni ID-ovi mogu pretvoriti najvažniju kolonu u tabelama u beskorisnu kolonu ispunjenu besmislenim vrijednostima. Stoga, kad god je to moguće, odaberite globalno jedinstveni i prirodni primarni ključ (npr. korisničko ime).

Prije nego što odlučite o pristupu, razmotrite utjecaj ID-ova koji se automatski povećavaju i UUID-a na indeksiranje, particioniranje i dijeljenje.

Zastarjeli podaci mogu biti korisni i ne zahtijevaju zaključavanje

Multiverzijska kontrola konkurentnosti (MVCC) implementira mnoge zahtjeve konzistentnosti o kojima smo ukratko raspravljali gore. Neke baze podataka (na primjer, Postgres, Spanner) koriste MVCC za “hranjivanje” transakcija snimcima – starijim verzijama baze podataka. Transakcije snimka se također mogu serijalizirati kako bi se osigurala konzistentnost. Prilikom čitanja sa starog snimka, čitaju se zastarjeli podaci.

Čitanje malo zastarjelih podataka može biti korisno, na primjer, kada se generiraju analitika iz podataka ili izračunavaju približne agregatne vrijednosti.

Prva prednost rada sa naslijeđenim podacima je nisko kašnjenje (posebno ako je baza podataka raspoređena u različitim geografskim područjima). Drugi je da su transakcije samo za čitanje bez zaključavanja. Ovo je značajna prednost za aplikacije koje puno čitaju, sve dok mogu rukovati zastarjelim podacima.

Više programera bi trebalo da zna ovo o bazama podataka
Aplikacijski poslužitelj čita podatke s lokalne replike koja je 5 sekundi zastarjela, čak i ako je najnovija verzija dostupna na drugoj strani Tihog oceana

DBMS-ovi automatski čiste starije verzije i, u nekim slučajevima, dozvoljavaju vam da to učinite na zahtjev. Na primjer, Postgres omogućava korisnicima da rade VACUUM na zahtjev, a također periodično obavlja ovu operaciju automatski. Spanner pokreće sakupljač smeća kako bi se riješio snimaka starijih od jednog sata.

U svakom trenutku izvori su podložni distorziji

Najbolje čuvana tajna u informatici je da svi API-ji za mjerenje vremena lažu. U stvari, naše mašine ne znaju tačno trenutno vreme. Kompjuteri sadrže kristale kvarca koji stvaraju vibracije koje se koriste za održavanje vremena. Međutim, oni nisu dovoljno precizni i mogu biti ispred/zaostajati za tačnim vremenom. Smjena može doseći 20 sekundi dnevno. Stoga vrijeme na našim računarima mora biti periodično sinhronizovano sa mrežnim.

NTP serveri se koriste za sinhronizaciju, ali sam proces sinhronizacije je podložan mrežnim kašnjenjima. Čak i sinhronizacija sa NTP serverom u istom data centru traje neko vreme. Jasno je da rad sa javnim NTP serverom može dovesti do još većeg izobličenja.

Atomski satovi i njihove GPS kolege su bolji za određivanje trenutnog vremena, ali su skupi i zahtijevaju složeno podešavanje, tako da se ne mogu instalirati na svaki automobil. Zbog toga, podatkovni centri koriste višeslojni pristup. Atomski i/ili GPS satovi pokazuju tačno vreme, nakon čega se emituje na druge mašine preko sekundarnih servera. To znači da će svaka mašina doživjeti određeni pomak od tačnog vremena.

Situaciju pogoršava činjenica da se aplikacije i baze podataka često nalaze na različitim mašinama (ako ne u različitim centrima podataka). Dakle, vrijeme će se razlikovati ne samo na DB čvorovima raspoređenim na različitim mašinama. Također će biti drugačije na poslužitelju aplikacija.

Google TrueTime ima potpuno drugačiji pristup. Većina ljudi vjeruje da se Googleov napredak u ovom pravcu objašnjava banalnim prelaskom na atomske i GPS satove, ali to je samo dio velike slike. Evo kako TrueTime funkcionira:

  • TrueTime koristi dva različita izvora: GPS i atomski sat. Ovi satovi imaju nekorelirane načine kvara. [pogledajte stranicu 5 za detalje ovdje - cca. prevod), pa njihova zajednička upotreba povećava pouzdanost.
  • TrueTime ima neobičan API. Vraća vrijeme kao interval sa ugrađenom greškom mjerenja i nesigurnošću. Stvarni trenutak u vremenu je negdje između gornje i donje granice intervala. Spanner, Googleova distribuirana baza podataka, jednostavno čeka dok se sa sigurnošću može reći da je trenutno vrijeme izvan opsega. Ova metoda uvodi određeno kašnjenje u sistem, posebno ako je nesigurnost na masterima velika, ali osigurava ispravnost čak iu globalno distribuiranoj situaciji.

Više programera bi trebalo da zna ovo o bazama podataka
Spanner komponente koriste TrueTime, gdje TT.now() vraća interval, tako da Spanner jednostavno spava do tačke u kojoj može biti siguran da je trenutno vrijeme prošlo određenu tačku

Smanjena preciznost u određivanju trenutnog vremena znači povećanje trajanja Spanner operacija i smanjenje performansi. Zbog toga je važno održavati najveću moguću preciznost iako je nemoguće dobiti potpuno precizan sat.

Kašnjenje ima mnogo značenja

Ako pitate desetak stručnjaka o tome šta je kašnjenje, vjerovatno ćete dobiti različite odgovore. U DBMS-u se kašnjenje često naziva "kašnjenjem baze podataka" i razlikuje se od onoga što percipira klijent. Činjenica je da klijent posmatra zbir kašnjenja mreže i kašnjenja baze podataka. Sposobnost izolacije tipa kašnjenja je kritična kada se otklanjaju rastući problemi. Kada prikupljate i prikazujete metriku, uvijek pokušajte paziti na obje vrste.

Zahtjeve učinka treba procijeniti za određenu transakciju

Ponekad se karakteristike performansi DBMS-a i njegova ograničenja specificiraju u smislu protoka pisanja/čitanja i kašnjenja. Ovo daje opšti pregled ključnih sistemskih parametara, ali kada se ocenjuje performanse novog DBMS-a, mnogo sveobuhvatniji pristup je da se posebno procene kritične operacije (za svaki upit i/ili transakciju). primjeri:

  • Propusnost pisanja i kašnjenje prilikom umetanja novog reda u tabelu X (sa 50 miliona redova) sa specificiranim ograničenjima i dopunama reda u srodnim tabelama.
  • Kašnjenje u prikazivanju prijatelja prijatelja određenog korisnika kada je prosječan broj prijatelja 500.
  • Latencija u preuzimanju prvih 100 unosa iz istorije korisnika kada korisnik prati 500 drugih korisnika sa X unosa po satu.

Procjena i eksperimentiranje mogu uključivati ​​takve kritične slučajeve sve dok ne budete sigurni da baza podataka ispunjava zahtjeve performansi. Slično pravilo također uzima u obzir ovu raščlambu pri prikupljanju metrike kašnjenja i određivanju SLO-ova.

Budite svjesni visoke kardinalnosti prilikom prikupljanja metrike za svaku operaciju. Koristite evidencije, kolekciju događaja ili distribuirano praćenje da biste dobili podatke za otklanjanje grešaka velike snage. U članku "Želite li otkloniti greške?» možete se upoznati sa metodologijama otklanjanja grešaka odgode.

Ugniježđene transakcije mogu biti opasne

Ne podržava svaki DBMS ugniježđene transakcije, ali kada to rade, takve transakcije mogu rezultirati neočekivanim greškama koje nije uvijek lako otkriti (odnosno, trebalo bi biti očito da postoji neka vrsta anomalije).

Možete izbjeći korištenje ugniježđenih transakcija koristeći klijentske biblioteke koje ih mogu otkriti i zaobići. Ako se ugniježđene transakcije ne mogu napustiti, obratite posebnu pažnju na njihovu implementaciju kako biste izbjegli neočekivane situacije u kojima se završene transakcije slučajno prekinu zbog ugniježđenih.

Enkapsuliranje transakcija u različitim slojevima može dovesti do neočekivanih ugniježđenih transakcija, a sa stanovišta čitljivosti koda, može otežati razumijevanje namjera autora. Pogledajte sljedeći program:

with newTransaction():
   Accounts.create("609-543-222")
   with newTransaction():
       Accounts.create("775-988-322")
       throw Rollback();

Šta će biti rezultat gornjeg koda? Hoće li poništiti obje transakcije ili samo onu unutrašnju? Šta se dešava ako se oslonimo na više slojeva biblioteka koje za nas obuhvataju kreiranje transakcija? Hoćemo li moći identificirati i poboljšati takve slučajeve?

Zamislite sloj podataka sa više operacija (npr. newAccount) je već implementiran u vlastitim transakcijama. Šta se događa ako ih pokrenete kao dio poslovne logike višeg nivoa koja se pokreće unutar svoje transakcije? Koja bi bila izolacija i dosljednost u ovom slučaju?

function newAccount(id string) {
  with newTransaction():
      Accounts.create(id)
}

Umjesto traženja odgovora na takva beskrajna pitanja, bolje je izbjegavati ugniježđene transakcije. Na kraju krajeva, vaš sloj podataka može lako izvoditi operacije visokog nivoa bez kreiranja vlastitih transakcija. Osim toga, sama poslovna logika je sposobna da pokrene transakciju, izvrši operacije na njoj, izvrši ili prekine transakciju.

function newAccount(id string) {
   Accounts.create(id)
}
// In main application:
with newTransaction():
   // Read some data from database for configuration.
   // Generate an ID from the ID service.
   Accounts.create(id)
   Uploads.create(id) // create upload queue for the user.

Transakcije ne bi trebale biti vezane za stanje aplikacije

Ponekad je primamljivo koristiti stanje aplikacije u transakcijama za promjenu određenih vrijednosti ili podešavanje parametara upita. Kritična nijansa koju treba uzeti u obzir je ispravan opseg primjene. Klijenti često ponovo pokreću transakcije kada postoje problemi sa mrežom. Ako transakcija tada zavisi od stanja koje se menja nekim drugim procesom, može izabrati pogrešnu vrednost u zavisnosti od mogućnosti trke podataka. Transakcije moraju uzeti u obzir rizik od uslova trke podataka u aplikaciji.

var seq int64
with newTransaction():
    newSeq := atomic.Increment(&seq)
    Entries.query(newSeq)
    // Other operations...

Gornja transakcija će povećati broj sekvence svaki put kada se izvrši, bez obzira na konačni rezultat. Ako urezivanje ne uspije zbog problema s mrežom, zahtjev će biti izvršen s drugim rednim brojem kada pokušate ponovo.

Planeri upita mogu vam puno reći o bazi podataka

Planeri upita određuju kako će se upit izvršiti u bazi podataka. Također analiziraju zahtjeve i optimiziraju ih prije slanja. Planeri mogu dati samo neke moguće procjene na osnovu signala kojima raspolažu. Na primjer, koja je najbolja metoda pretraživanja za sljedeći upit?

SELECT * FROM articles where author = "rakyll" order by title;

Rezultati se mogu dobiti na dva načina:

  • Kompletno skeniranje tabele: Možete pogledati svaki unos u tabeli i vratiti članke sa odgovarajućim imenom autora, a zatim ih naručiti.
  • Indeksno skeniranje: Možete koristiti indeks da pronađete podudarne ID-ove, dobijete te redove, a zatim ih naručite.

Posao planera upita je da odredi koja je strategija najbolja. Vrijedi uzeti u obzir da planeri upita imaju samo ograničene mogućnosti predviđanja. To može dovesti do loših odluka. DBA-ovi ili programeri mogu ih koristiti za dijagnosticiranje i fino podešavanje upita s lošim učinkom. Nove verzije DBMS-a mogu konfigurirati planere upita, a samodijagnostika može pomoći pri ažuriranju baze podataka ako nova verzija dovede do problema s performansama. Spori zapisnici upita, izvještaji o problemima kašnjenja ili statistika vremena izvršenja mogu pomoći da se identificiraju upiti kojima je potrebna optimizacija.

Neke metrike predstavljene od strane planera upita mogu biti podložne buci (naročito kada se procjenjuje kašnjenje ili CPU vrijeme). Dobar dodatak planerima su alati za praćenje i praćenje putanje izvršenja. Oni vam omogućavaju da dijagnostikujete takve probleme (nažalost, ne pružaju svi DBMS-ovi takve alate).

Online migracija je teška, ali moguća

Online migracija, migracija uživo ili migracija u realnom vremenu znači prelazak s jedne baze podataka na drugu bez zastoja ili oštećenja podataka. Živu migraciju je lakše izvesti ako se tranzicija dogodi unutar istog DBMS/motora. Situacija postaje složenija kada je potrebno prijeći na novi DBMS s drugačijim zahtjevima performansi i sheme.

Postoje različiti modeli online migracije. Evo jednog od njih:

  • Omogućite dvostruki unos u obje baze podataka. Nova baza podataka u ovoj fazi nema sve podatke, već prihvata samo najnovije podatke. Kada ste sigurni u ovo, možete prijeći na sljedeći korak.
  • Omogućite čitanje iz obje baze podataka.
  • Konfigurirajte sistem tako da se čitanje i pisanje obavlja prvenstveno na novoj bazi podataka.
  • Prestanite pisati u staru bazu podataka dok nastavljate čitati podatke iz nje. U ovoj fazi nova baza podataka je još uvijek lišena nekih podataka. Treba ih kopirati iz stare baze podataka.
  • Stara baza podataka je samo za čitanje. Kopirajte podatke koji nedostaju iz stare baze podataka u novu. Nakon što se migracija završi, prebacite staze na novu bazu podataka, zaustavite staru i izbrišite je iz sistema.

Za dodatne informacije preporučujem da se obratite članak, koji detaljno opisuje Stripeovu strategiju migracije zasnovanu na ovom modelu.

Značajno povećanje baze podataka povlači povećanje nepredvidljivosti

Rast baze podataka dovodi do nepredvidivih problema povezanih s njenom razmjerom. Što više znamo o internoj strukturi baze podataka, to bolje možemo predvidjeti kako će se ona skalirati. Međutim, neke trenutke je još uvijek nemoguće predvidjeti.
Kako baza raste, prethodne pretpostavke i očekivanja u vezi sa zahtjevima za volumenom podataka i propusnim opsegom mreže mogu postati zastarjeli. Tada se postavlja pitanje velikih remonta dizajna, velikih operativnih poboljšanja, ponovnog razmišljanja o implementaciji ili migracije na druge DBMS-ove kako bi se izbjegli potencijalni problemi.

Ali nemojte misliti da je odlično poznavanje interne strukture postojeće baze podataka jedino što je potrebno. Nove vage će sa sobom donijeti nove nepoznanice. Nepredvidive bolne tačke, neravnomjerna distribucija podataka, neočekivani problemi sa propusnošću i hardverom, sve veći promet i novi segmenti mreže natjerat će vas da ponovo razmislite o pristupu bazi podataka, modelu podataka, modelu implementacije i veličini baze podataka.

...

U trenutku kada sam počeo razmišljati o objavljivanju ovog članka, na mojoj originalnoj listi je već bilo još pet stavki. Onda je došao ogroman broj nove ideje o tome šta se još može pokriti. Stoga se članak dotiče najmanje očiglednih problema koji zahtijevaju maksimalnu pažnju. Međutim, to ne znači da je tema iscrpljena i da joj se više neću vraćati u svojim budućim materijalima i neću mijenjati sadašnju.

PS

Pročitajte i na našem blogu:

izvor: www.habr.com

Dodajte komentar