Vairāk izstrādātājiem tas būtu jāzina par datu bāzēm

Piezīme. tulk.: Jaana Dogana ir pieredzējusi Google inženiere, kura pašlaik strādā pie uzņēmuma ražošanas pakalpojumu novērojamības, kas rakstīts Go. Šajā rakstā, kas ieguva lielu popularitāti angliski runājošās auditorijas vidū, viņa 17 punktos apkopoja svarīgas tehniskas detaļas par DBVS (un dažreiz arī izplatītajām sistēmām kopumā), kuras ir noderīgas lielu/prasīgu lietojumprogrammu izstrādātājiem.

Vairāk izstrādātājiem tas būtu jāzina par datu bāzēm

Lielākais vairums datorsistēmu seko līdzi savam stāvoklim un attiecīgi tām ir nepieciešama kāda veida datu uzglabāšanas sistēma. Es uzkrāju zināšanas par datu bāzēm ilgākā laika periodā, pa ceļam pieļaujot dizaina kļūdas, kas noveda pie datu zuduma un pārtraukumiem. Sistēmās, kas apstrādā lielu informācijas apjomu, datu bāzes ir sistēmas arhitektūras pamatā un darbojas kā galvenais elements optimālā risinājuma izvēlē. Neskatoties uz to, ka liela uzmanība tiek pievērsta datu bāzes darbam, problēmas, ko lietojumprogrammu izstrādātāji cenšas paredzēt, bieži vien ir tikai aisberga redzamā daļa. Šajā rakstu sērijā es dalos ar dažām idejām, kas noderēs izstrādātājiem, kuri nav specializējušies šajā jomā.

  1. Jums ir paveicies, ja 99,999% gadījumu tīkls nerada problēmas.
  2. SKĀBE nozīmē daudzas dažādas lietas.
  3. Katrai datubāzei ir savi mehānismi konsekvences un izolācijas nodrošināšanai.
  4. Optimistiskā bloķēšana nāk palīgā, kad ir grūti uzturēt ierasto.
  5. Bez netīrās lasīšanas un datu zuduma ir arī citas anomālijas.
  6. Datubāze un lietotājs ne vienmēr vienojas par darbības virzienu.
  7. Lietojumprogrammas līmeņa sadalīšanu var pārvietot ārpus lietojumprogrammas.
  8. Automātiska palielināšana var būt bīstama.
  9. Novecojuši dati var būt noderīgi, un tie nav jābloķē.
  10. Izkropļojumi ir raksturīgi jebkuriem laika avotiem.
  11. Kavēšanai ir daudz nozīmju.
  12. Veiktspējas prasības jāizvērtē konkrētam darījumam.
  13. Ligzdoti darījumi var būt bīstami.
  14. Darījumi nedrīkst būt saistīti ar lietojumprogrammas stāvokli.
  15. Vaicājumu plānotāji var daudz pastāstīt par datu bāzēm.
  16. Tiešsaistes migrācija ir sarežģīta, bet iespējama.
  17. Ievērojams datu bāzes pieaugums rada neparedzamības pieaugumu.

Es vēlētos pateikties Emmanuel Odeke, Rein Henrichs un citiem par viņu atsauksmēm par šī raksta iepriekšējo versiju.

Jums ir paveicies, ja 99,999% gadījumu tīkls nerada problēmas.

Paliek jautājums par to, cik uzticamas ir mūsdienu tīkla tehnoloģijas un cik bieži sistēmas nedarbojas tīkla kļūmju dēļ. Informācijas par šo jautājumu ir maz, un pētniecībā bieži dominē lielas organizācijas ar specializētiem tīkliem, aprīkojumu un personālu.

Tā kā Spanner (Google globāli izplatītā datubāze) pieejamības līmenis ir 99,999%, Google apgalvo, ka tikai 7,6% problēmas ir saistītas ar tīklu. Tajā pašā laikā uzņēmums savu specializēto tīklu sauc par augstas pieejamības “galveno pīlāru”. Pētījums Bailis un Kingsberija, kas veikta 2014. gadā, izaicina vienu no “maldīgi priekšstati par sadalīto skaitļošanu", ko Pīters Deičs formulēja 1994. gadā. Vai tīkls tiešām ir uzticams?

Visaptveroša izpēte ārpus milzu uzņēmumiem, kas veikta plašākam internetam, vienkārši nepastāv. Nav arī pietiekami daudz datu no lielākajiem spēlētājiem par to, cik procentu viņu klientu problēmas ir saistītas ar tīklu. Mēs labi zinām par pārtraukumiem lielu mākoņdatošanas pakalpojumu sniedzēju tīkla kaudzē, kas var nojaukt veselu interneta daļu uz vairākām stundām, jo ​​tie ir augsta līmeņa notikumi, kas ietekmē lielu skaitu cilvēku un uzņēmumu. Tīkla pārtraukumi var radīt problēmas daudzos gadījumos, pat ja ne visi šie gadījumi ir uzmanības centrā. Arī mākoņpakalpojumu klienti neko nezina par problēmu cēloņiem. Ja rodas kļūme, to ir gandrīz neiespējami saistīt ar tīkla kļūdu pakalpojumu sniedzēja pusē. Viņiem trešo pušu pakalpojumi ir melnās kastes. Nav iespējams novērtēt ietekmi, ja nav liels pakalpojumu sniedzējs.

Ņemot vērā to, ko lielie spēlētāji ziņo par savām sistēmām, var droši teikt, ka jums ir paveicies, ja tīkla grūtības veido tikai nelielu daļu no iespējamām dīkstāves problēmām. Tīkla sakari joprojām cieš no tādām ikdienišķām lietām kā aparatūras kļūmes, topoloģijas izmaiņas, administratīvās konfigurācijas izmaiņas un strāvas padeves pārtraukumi. Nesen es biju pārsteigts, uzzinot, ka iespējamo problēmu saraksts ir pievienots haizivju kodumi (jā, jūs dzirdējāt pareizi).

SKĀBE nozīmē daudz dažādu lietu

Akronīms ACID apzīmē atomitāti, konsistenci, izolāciju, uzticamību. Šīs transakciju īpašības ir paredzētas, lai nodrošinātu to derīgumu kļūmju, kļūdu, aparatūras kļūmju u.c. gadījumā. Bez ACID vai līdzīgām shēmām lietojumprogrammu izstrādātājiem būtu grūti atšķirt, par ko viņi ir atbildīgi, un par ko atbild datubāze. Lielākā daļa relāciju darījumu datu bāzu cenšas būt saderīgas ar ACID, taču jaunas pieejas, piemēram, NoSQL, ir radījušas daudzas datu bāzes bez ACID darījumiem, jo ​​to ieviešana ir dārga.

Kad es pirmo reizi ienācu šajā nozarē, mūsu tehniskais vadītājs runāja par ACID koncepcijas nozīmīgumu. Godīgi sakot, ACID tiek uzskatīts par aptuvenu aprakstu, nevis stingru ieviešanas standartu. Šodien es uzskatu, ka tas galvenokārt ir noderīgs, jo tas rada īpašu problēmu kategoriju (un ierosina dažādus iespējamos risinājumus).

Ne katra DBVS ir saderīga ar ACID; Tajā pašā laikā datu bāzes implementācijas, kas atbalsta ACID, prasību kopumu saprot atšķirīgi. Viens no iemesliem, kāpēc ACID ieviešana ir nevienmērīga, ir daudzo kompromisu dēļ, kas jāveic, lai ieviestu ACID prasības. Veidotāji var uzrādīt savas datubāzes kā saderīgas ar ACID, taču malu gadījumu interpretācija var krasi atšķirties, tāpat kā "maz ticamu" notikumu apstrādes mehānisms. Vismaz izstrādātāji var iegūt augsta līmeņa izpratni par bāzes ieviešanas sarežģītību, lai iegūtu pienācīgu izpratni par to īpašo uzvedību un dizaina kompromisiem.

Debates par to, vai MongoDB atbilst ACID prasībām, turpinās pat pēc 4. versijas izlaišanas. MongoDB ilgu laiku nav atbalstīts mežizstrāde, lai gan pēc noklusējuma dati diskā tika ievietoti ne biežāk kā reizi 60 sekundēs. Iedomājieties šādu scenāriju: lietojumprogramma ievieto divus ierakstus (w1 un w2). MongoDB veiksmīgi saglabā w1, bet w2 tiek zaudēts aparatūras kļūmes dēļ.

Vairāk izstrādātājiem tas būtu jāzina par datu bāzēm
Diagramma, kas ilustrē scenāriju. MongoDB avarē, pirms tas var ierakstīt datus diskā

Diska izmantošana ir dārgs process. Izvairoties no biežām saistībām, izstrādātāji uzlabo ierakstīšanas veiktspēju uz uzticamības rēķina. MongoDB pašlaik atbalsta reģistrēšanu, taču netīri ieraksti joprojām var ietekmēt datu integritāti, jo pēc noklusējuma žurnāli tiek tverti ik pēc 100 ms. Tas ir, līdzīgs scenārijs joprojām ir iespējams žurnāliem un tajos parādītajām izmaiņām, lai gan risks ir daudz mazāks.

Katrai datubāzei ir savi konsekvences un izolācijas mehānismi

No ACID prasībām konsekvence un izolācija var lepoties ar lielāko dažādu ieviešanu skaitu, jo kompromisu klāsts ir plašāks. Jāsaka, ka konsekvence un izolācija ir diezgan dārgas funkcijas. Tie prasa koordināciju un palielina konkurenci par datu konsekvenci. Problēmas sarežģītība ievērojami palielinās, ja ir nepieciešams horizontāli mērogot datubāzi vairākos datu centros (īpaši, ja tie atrodas dažādos ģeogrāfiskos reģionos). Panākt augstu konsekvences līmeni ir ļoti grūti, jo tas arī samazina pieejamību un palielina tīkla segmentāciju. Lai iegūtu vispārīgāku šīs parādības skaidrojumu, iesaku atsaukties uz CAP teorēma. Ir arī vērts atzīmēt, ka lietojumprogrammas var tikt galā ar nelielām neatbilstībām, un programmētāji var pietiekami labi izprast problēmas nianses, lai lietojumprogrammā ieviestu papildu loģiku, lai novērstu neatbilstības, nepaļaujoties uz datu bāzi, kas to apstrādā.

DBVS bieži nodrošina dažādus izolācijas līmeņus. Lietojumprogrammu izstrādātāji var izvēlēties visefektīvāko, pamatojoties uz savām vēlmēm. Zema izolācija ļauj palielināt ātrumu, bet arī palielina datu sacensību risku. Augsta izolācija samazina šo varbūtību, bet bremzē darbu un var izraisīt konkurenci, kas novedīs pie tādām bremzēm bāzē, ka sākas kļūmes.

Vairāk izstrādātājiem tas būtu jāzina par datu bāzēm
Esošo vienlaicības modeļu un to savstarpējo attiecību apskats

SQL standarts nosaka tikai četrus izolācijas līmeņus, lai gan teorētiski un praksē ir daudz vairāk. Jepson.io piedāvā lielisku pārskatu par esošajiem vienlaicības modeļiem. Piemēram, Google Spanner garantē ārēju serializējamību ar pulksteņa sinhronizāciju, un, lai gan šis ir stingrāks izolācijas slānis, tas nav definēts standarta izolācijas slāņos.

SQL standartā ir minēti šādi izolācijas līmeņi:

  • Serializējams (visstingrākā un dārgākā): Serializējamai izpildei ir tāds pats efekts kā dažu secīgu darījumu izpildei. Secīgā izpilde nozīmē, ka katrs nākamais darījums sākas tikai pēc tam, kad ir pabeigts iepriekšējais. Jāpiebilst, ka līmenis Serializējams interpretācijas atšķirību dēļ bieži tiek ieviesta kā tā sauktā momentuzņēmuma izolācija (piemēram, Oracle), lai gan pati momentuzņēmuma izolācija SQL standartā nav pārstāvēta.
  • Atkārtojami lasījumi: pašreizējā darījuma neiesaistītie ieraksti ir pieejami pašreizējam darījumam, bet citu darījumu veiktās izmaiņas (piemēram, jaunas rindas) nav redzams.
  • Lasīt apņēmies: transakcijām nav pieejami neapstiprinātie dati. Šādā gadījumā transakcijas var redzēt tikai piesaistītos datus, un var notikt fantoma nolasīšana. Ja darījums ievieto un veic jaunas rindas, pašreizējais darījums varēs tās redzēt pēc vaicājuma.
  • Lasīt bez saistībām (vismaz stingrs un dārgs līmenis): Ir atļauti netīri nolasījumi, transakcijās var redzēt citu darījumu veiktās izmaiņas. Praksē šis līmenis var būt noderīgs aptuvenām aplēsēm, piemēram, vaicājumiem COUNT(*) uz galda.

Līmenis Serializējams samazina datu sacīkšu risku, vienlaikus visdārgāk īstenojot un radot vislielāko sistēmas konkurences slodzi. Citus izolācijas līmeņus ir vieglāk ieviest, taču tie palielina datu sacensību iespējamību. Dažas DBVS ļauj iestatīt pielāgotu izolācijas līmeni, citām ir spēcīgas preferences, un ne visi līmeņi tiek atbalstīti.

Izolācijas līmeņu atbalsts bieži tiek reklamēts noteiktā DBVS, taču tikai rūpīga tās uzvedības izpēte var atklāt, kas patiesībā notiek.

Vairāk izstrādātājiem tas būtu jāzina par datu bāzēm
Vienlaicības anomāliju apskats dažādos izolācijas līmeņos dažādām DBVS

Martin Kleppmann savā projektā ermitāža Salīdzina dažādus izolācijas līmeņus, runā par vienlaicīguma anomālijām un to, vai datu bāze spēj ievērot noteiktu izolācijas līmeni. Kleppmann pētījums parāda, cik atšķirīgi datu bāzu izstrādātāji domā par izolācijas līmeņiem.

Optimistiskā bloķēšana nāk palīgā, kad ir grūti uzturēt ierasto.

Bloķēšana var būt ļoti dārga ne tikai tāpēc, ka tā palielina konkurenci datu bāzē, bet arī tāpēc, ka lietojumprogrammu serveriem ir pastāvīgi jāpievienojas datu bāzei. Tīkla segmentācija var saasināt ekskluzīvas bloķēšanas situācijas un izraisīt strupceļus, kurus ir grūti identificēt un atrisināt. Gadījumos, kad ekskluzīva bloķēšana nav piemērota, palīdz optimistiska bloķēšana.

Optimistiska slēdzene ir metode, kurā, lasot virkni, tā ņem vērā tās versiju, kontrolsummu vai pēdējās modifikācijas laiku. Tas ļauj nodrošināt, ka pirms ieraksta maiņas netiek mainīta atomu versija:

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

Šajā gadījumā tabulas atjaunināšana products netiks veikta, ja kāda cita darbība iepriekš veica izmaiņas šajā rindā. Ja šajā rindā netika veiktas nekādas citas darbības, vienas rindas izmaiņas notiks, un mēs varam teikt, ka atjaunināšana bija veiksmīga.

Bez netīrās lasīšanas un datu zuduma ir arī citas anomālijas

Runājot par datu konsekvenci, galvenā uzmanība tiek pievērsta iespējamajiem sacensību apstākļiem, kas var izraisīt netīrus nolasījumus un datu zudumu. Tomēr datu anomālijas ar to nebeidzas.

Viens no šādu anomāliju piemēriem ir ierakstīšanas kropļojumi (rakstīt šķībi). Izkropļojumus ir grūti noteikt, jo parasti tie netiek aktīvi meklēti. Tās nav saistītas ar netīriem nolasījumiem vai datu zudumu, bet gan datu loģisko ierobežojumu pārkāpumiem.

Piemēram, apsveriet pārraudzības lietojumprogrammu, kas prasa, lai viens operators vienmēr būtu dežūras:

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;

Iepriekš minētajā situācijā, ja abi darījumi tiks veiksmīgi izdarīti, notiks rekorda sabojāšana. Lai gan nebija netīras nolasīšanas vai datu zuduma, datu integritāte tika apdraudēta: tagad divi cilvēki tiek uzskatīti par dežūrām vienlaikus.

Serializējamā izolācija, shēmas dizains vai datu bāzes ierobežojumi var palīdzēt novērst rakstīšanas bojājumus. Izstrādātājiem ir jāspēj identificēt šādas anomālijas izstrādes laikā, lai izvairītos no tām ražošanā. Tajā pašā laikā koda bāzē ir ārkārtīgi grūti atrast ierakstīšanas traucējumus. Īpaši lielās sistēmās, kad dažādas izstrādes komandas ir atbildīgas par funkciju ieviešanu, pamatojoties uz vienādām tabulām un nav vienisprātis par datu piekļuves specifiku.

Datubāze un lietotājs ne vienmēr vienojas, kā rīkoties

Viena no galvenajām datu bāzu iezīmēm ir izpildes pasūtījuma garantija, taču pats pasūtījums programmatūras izstrādātājam var nebūt pārskatāms. Datu bāzes veic transakcijas to saņemšanas secībā, nevis programmētāju iecerētajā secībā. Darījumu secību ir grūti paredzēt, īpaši ļoti noslogotās paralēlās sistēmās.

Izstrādes laikā, īpaši strādājot ar nebloķējošām bibliotēkām, slikts stils un zema lasāmība var likt lietotājiem domāt, ka transakcijas tiek izpildītas secīgi, lai gan patiesībā tās varētu nonākt datu bāzē jebkurā secībā.

No pirmā acu uzmetiena zemāk esošajā programmā T1 un T2 tiek izsaukti secīgi, bet, ja šīs funkcijas nebloķē un nekavējoties atgriež rezultātu formā solījums, tad zvanu secību noteiks datubāzē ienākšanas brīži:

rezultāts1 = T1() // reālie rezultāti ir solījumi
rezultāts2 = T2()

Ja ir nepieciešama atomitāte (tas ir, visas darbības ir jāpabeidz vai jāpārtrauc) un secībai ir nozīme, operācijas T1 un T2 jāveic viena darījuma ietvaros.

Lietojumprogrammas līmeņa sadalīšanu var pārvietot ārpus lietojumprogrammas

Dalīšana ir datu bāzes horizontālās sadalīšanas metode. Dažas datu bāzes var automātiski sadalīt datus horizontāli, savukārt citas nevar vai nav pārāk labi tajā. Kad datu arhitekti/izstrādātāji spēj precīzi paredzēt, kā datiem tiks piekļūt, viņi var izveidot horizontālus nodalījumus lietotāja telpā, nevis deleģēt šo darbu datu bāzei. Šo procesu sauc par "lietojumprogrammas līmeņa sadalīšanu". (lietojumprogrammas līmeņa sadalīšana).

Diemžēl šis nosaukums bieži rada nepareizu priekšstatu, ka sharding dzīvo lietojumprogrammu pakalpojumos. Faktiski to var ieviest kā atsevišķu slāni datu bāzes priekšā. Atkarībā no datu pieauguma un shēmu iterācijām, sadalīšanas prasības var kļūt diezgan sarežģītas. Dažām stratēģijām var būt noderīga iespēja veikt atkārtojumus bez nepieciešamības atkārtoti izvietot lietojumprogrammu serverus.

Vairāk izstrādātājiem tas būtu jāzina par datu bāzēm
Arhitektūras piemērs, kurā lietojumprogrammu serveri ir atdalīti no sadalīšanas pakalpojuma

Sadalīšanas pārvietošana uz atsevišķu pakalpojumu paplašina iespēju izmantot dažādas sadalīšanas stratēģijas bez nepieciešamības atkārtoti izvietot lietojumprogrammas. Vitess ir šādas sadalīšanas sistēmas piemērs lietojumprogrammu līmenī. Vitess nodrošina MySQL horizontālo sadalīšanu un ļauj klientiem izveidot savienojumu ar to, izmantojot MySQL protokolu. Sistēma segmentē datus dažādos MySQL mezglos, kas neko nezina viens par otru.

Automātiska palielināšana var būt bīstama

AUTOMĀTISKĀ INCREMENT ir izplatīts veids, kā ģenerēt primārās atslēgas. Bieži ir gadījumi, kad datu bāzes tiek izmantotas kā ID ģeneratori, un datu bāzē ir tabulas, kas paredzētas identifikatoru ģenerēšanai. Ir vairāki iemesli, kāpēc primāro atslēgu ģenerēšana, izmantojot automātisko palielināšanu, nebūt nav ideāla:

  • Izplatītā datu bāzē automātiskā palielināšana ir nopietna problēma. Lai ģenerētu ID, ir nepieciešama globāla bloķēšana. Tā vietā varat ģenerēt UUID: tam nav nepieciešama mijiedarbība starp dažādiem datu bāzes mezgliem. Automātiska palielināšana ar slēdzenēm var izraisīt strīdus un ievērojami samazināt ieliktņu veiktspēju sadalītās situācijās. Dažām DBVS (piemēram, MySQL) var būt nepieciešama īpaša konfigurācija un rūpīgāka uzmanība, lai pareizi organizētu galveno un galveno replikāciju. Un konfigurēšanas laikā ir viegli pieļaut kļūdas, kas novedīs pie ierakstīšanas kļūmēm.
  • Dažām datu bāzēm ir sadalīšanas algoritmi, kuru pamatā ir primārās atslēgas. Secīgi ID var izraisīt neprognozējamus karstos punktus un palielināt dažu nodalījumu slodzi, kamēr citi paliek dīkstāvē.
  • Primārā atslēga ir ātrākais veids, kā piekļūt rindai datubāzē. Izmantojot labākus ierakstu identificēšanas veidus, secīgi ID var pārvērst svarīgāko tabulu kolonnu par bezjēdzīgu kolonnu, kas piepildīta ar bezjēdzīgām vērtībām. Tāpēc, kad vien iespējams, izvēlieties globāli unikālu un dabisku primāro atslēgu (piemēram, lietotājvārdu).

Pirms izlemjat par pieeju, apsveriet automātiskās ID un UUID palielināšanas ietekmi uz indeksēšanu, sadalīšanu un sadalīšanu.

Novecojuši dati var būt noderīgi, un tiem nav nepieciešama bloķēšana

Vairāku versiju vienlaicīguma kontrole (MVCC) īsteno daudzas konsekvences prasības, kas tika īsi apspriestas iepriekš. Dažas datu bāzes (piemēram, Postgres, Spanner) izmanto MVCC, lai “pabarotu” transakcijas ar momentuzņēmumiem — datu bāzes vecākām versijām. Lai nodrošinātu konsekvenci, momentuzņēmuma darījumus var arī serializēt. Lasot no veca momentuzņēmuma, tiek nolasīti novecojuši dati.

Nedaudz novecojušu datu lasīšana var būt noderīga, piemēram, ģenerējot analīzi no datiem vai aprēķinot aptuvenas apkopotās vērtības.

Pirmā priekšrocība, strādājot ar mantotajiem datiem, ir zems latentums (īpaši, ja datubāze ir sadalīta dažādās ģeogrāfiskās vietās). Otrais ir tas, ka tikai lasāmie darījumi ir bez bloķēšanas. Tā ir būtiska priekšrocība lietojumprogrammām, kuras lasa daudz, ja vien tās var apstrādāt novecojušus datus.

Vairāk izstrādātājiem tas būtu jāzina par datu bāzēm
Lietojumprogrammas serveris nolasa datus no vietējās kopijas, kas ir 5 sekundes novecojušas, pat ja jaunākā versija ir pieejama otrpus Klusajam okeānam.

DBVS automātiski iztīra vecākas versijas un dažos gadījumos ļauj to izdarīt pēc pieprasījuma. Piemēram, Postgres ļauj lietotājiem to darīt VACUUM pēc pieprasījuma, kā arī periodiski veic šo darbību automātiski. Spanners vada atkritumu savācēju, lai atbrīvotos no momentuzņēmumiem, kas vecāki par vienu stundu.

Jebkuri laika avoti ir pakļauti izkropļojumiem

Vislabāk glabātais datorzinātņu noslēpums ir tas, ka visas laika noteikšanas API melo. Patiesībā mūsu mašīnas nezina precīzu pašreizējo laiku. Datori satur kvarca kristālus, kas rada vibrācijas, kas tiek izmantotas laika noturēšanai. Tomēr tie nav pietiekami precīzi un var būt priekšā/atpalikt no precīzā laika. Maiņa var sasniegt 20 sekundes dienā. Tāpēc laiks mūsu datoros ir periodiski jāsinhronizē ar tīkla laiku.

Sinhronizācijai tiek izmantoti NTP serveri, bet pats sinhronizācijas process ir pakļauts tīkla aizkavei. Pat sinhronizācija ar NTP serveri tajā pašā datu centrā aizņem kādu laiku. Ir skaidrs, ka darbs ar publisko NTP serveri var radīt vēl lielākus traucējumus.

Atompulksteņi un to GPS analogi ir labāki pašreizējā laika noteikšanai, taču tie ir dārgi un prasa sarežģītu iestatīšanu, tāpēc tos nevar uzstādīt katrā automašīnā. Šī iemesla dēļ datu centri izmanto daudzpakāpju pieeju. Atomu un/vai GPS pulksteņi parāda precīzu laiku, pēc kura tas tiek pārraidīts uz citām mašīnām caur sekundārajiem serveriem. Tas nozīmē, ka katra iekārta piedzīvos noteiktu nobīdi no precīzā laika.

Situāciju pasliktina tas, ka lietojumprogrammas un datu bāzes bieži atrodas dažādās iekārtās (ja ne dažādos datu centros). Tādējādi laiks atšķirsies ne tikai DB mezglos, kas sadalīti dažādās iekārtās. Tas būs atšķirīgs arī lietojumprogrammu serverī.

Google TrueTime izmanto pavisam citu pieeju. Lielākā daļa cilvēku uzskata, ka Google progress šajā virzienā ir izskaidrojams ar banālo pāreju uz atomu un GPS pulksteņiem, taču tā ir tikai daļa no kopējā attēla. TrueTime darbojas šādi:

  • TrueTime izmanto divus dažādus avotus: GPS un atompulksteņus. Šiem pulksteņiem ir nekorelēti atteices režīmi. [Sīkāku informāciju skatiet 5. lpp šeit — apm. tulk.), tāpēc to kopīga lietošana palielina uzticamību.
  • TrueTime ir neparasta API. Tas atgriež laiku kā intervālu, kurā ir iebūvēta mērījumu kļūda un nenoteiktība. Faktiskais laika moments atrodas kaut kur starp intervāla augšējo un apakšējo robežu. Spanner, Google izplatītā datu bāze, vienkārši gaida, līdz var droši teikt, ka pašreizējais laiks ir ārpus diapazona. Šī metode sistēmā ievieš zināmu latentumu, it īpaši, ja maģistrāļu nenoteiktība ir liela, bet nodrošina pareizību pat globāli izkliedētā situācijā.

Vairāk izstrādātājiem tas būtu jāzina par datu bāzēm
Atslēgas atslēgas komponenti izmanto TrueTime, kur TT.now() atgriež intervālu, tāpēc uzgriežņu atslēga vienkārši guļ līdz brīdim, kad var būt pārliecināts, ka pašreizējais laiks ir pagājis noteiktu punktu.

Samazināta precizitāte pašreizējā laika noteikšanā nozīmē uzgriežņu darbības ilguma palielināšanos un veiktspējas samazināšanos. Tāpēc ir svarīgi saglabāt augstāko iespējamo precizitāti, pat ja nav iespējams iegūt pilnīgi precīzu pulksteni.

Kavēšanai ir daudz nozīmju

Ja pajautāsiet desmitiem ekspertu par to, kas ir kavēšanās, iespējams, saņemsiet dažādas atbildes. DBVS latentumu bieži sauc par "datu bāzes latentumu", un tas atšķiras no klienta uztvertā. Fakts ir tāds, ka klients ievēro tīkla aizkaves un datu bāzes aizkaves summu. Spēja izolēt latentuma veidu ir ļoti svarīga, atkļūdojot pieaugošās problēmas. Apkopojot un parādot metriku, vienmēr mēģiniet sekot līdzi abiem veidiem.

Veiktspējas prasības jāizvērtē konkrētam darījumam

Dažreiz DBVS veiktspējas raksturlielumi un tās ierobežojumi ir norādīti rakstīšanas/lasīšanas caurlaidības un latentuma izteiksmē. Tas sniedz vispārīgu pārskatu par galvenajiem sistēmas parametriem, taču, novērtējot jaunas DBVS veiktspēju, daudz visaptverošāka pieeja ir kritisko operāciju atsevišķa novērtēšana (katram vaicājumam un/vai transakcijai). Piemēri:

  • Ierakstiet caurlaidspēju un latentumu, ievietojot jaunu rindu tabulā X (ar 50 miljoniem rindu) ar noteiktiem ierobežojumiem un rindu pildījumu saistītajās tabulās.
  • Aizkave noteikta lietotāja draugu draugu parādīšanai, ja vidējais draugu skaits ir 500.
  • Latentums 100 populārāko ierakstu izgūšanai no lietotāja vēstures, kad lietotājs seko 500 citiem lietotājiem ar X ierakstiem stundā.

Novērtēšana un eksperimentēšana var ietvert šādus kritiskus gadījumus, līdz esat pārliecināts, ka datubāze atbilst veiktspējas prasībām. Līdzīgs īkšķis noteikums arī ņem vērā šo sadalījumu, apkopojot latentuma metriku un nosakot SLO.

Vācot metriku katrai darbībai, ievērojiet augstu kardinalitāti. Izmantojiet žurnālus, notikumu apkopošanu vai izkliedētu izsekošanu, lai iegūtu jaudīgus atkļūdošanas datus. Rakstā "Vai vēlaties atkļūdot latentumu?» varat iepazīties ar aizkaves atkļūdošanas metodoloģijām.

Ligzdoti darījumi var būt bīstami

Ne katra DBVS atbalsta ligzdotas transakcijas, taču, ja tās atbalsta, šādas transakcijas var izraisīt neparedzētas kļūdas, kuras ne vienmēr ir viegli atklāt (tas ir, ir jābūt acīmredzamam, ka pastāv kāda veida anomālija).

Jūs varat izvairīties no ligzdotu darījumu izmantošanas, izmantojot klientu bibliotēkas, kas var tās noteikt un apiet. Ja ligzdotās transakcijas nevar atteikties, ievērojiet īpašu piesardzību to ieviešanā, lai izvairītos no neparedzētām situācijām, kad pabeigtās transakcijas tiek nejauši pārtrauktas ligzdoto darījumu dēļ.

Transakciju iekapsulēšana dažādos slāņos var izraisīt negaidītas ligzdotas transakcijas, un no koda lasāmības viedokļa tas var apgrūtināt autora nodomu izpratni. Apskatiet šādu programmu:

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

Kāda būs iepriekš minētā koda izvade? Vai tas atcels abus darījumus vai tikai iekšējo? Kas notiek, ja mēs paļaujamies uz vairākiem bibliotēku slāņiem, kas ietver transakciju izveidi mūsu vietā? Vai mēs spēsim identificēt un uzlabot šādus gadījumus?

Iedomājieties datu slāni ar vairākām darbībām (piem. newAccount) jau ir ieviests savos darījumos. Kas notiek, ja jūs tos palaižat kā daļu no augstāka līmeņa biznesa loģikas, kas darbojas savā darījumā? Kāda būtu izolācija un konsekvence šajā gadījumā?

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

Tā vietā, lai meklētu atbildes uz šādiem bezgalīgiem jautājumiem, labāk izvairīties no ligzdotiem darījumiem. Galu galā jūsu datu slānis var viegli veikt augsta līmeņa darbības, neveidojot savus darījumus. Turklāt pati biznesa loģika spēj uzsākt darījumu, veikt ar to darbības, veikt vai pārtraukt darījumu.

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.

Darījumi nedrīkst būt saistīti ar lietojumprogrammas stāvokli

Dažreiz ir vilinoši izmantot lietojumprogrammas stāvokli darījumos, lai mainītu noteiktas vērtības vai pielāgotu vaicājuma parametrus. Būtiskākā nianse, kas jāņem vērā, ir pareiza piemērošanas joma. Klienti bieži atsāk darījumus, ja rodas tīkla problēmas. Ja darījums pēc tam ir atkarīgs no stāvokļa, ko maina kāds cits process, tas var izvēlēties nepareizu vērtību atkarībā no datu sacīkstes iespējas. Darījumos ir jāņem vērā datu sacensību nosacījumu risks pieteikumā.

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

Iepriekš minētā darījuma kārtas numurs palielinās katru reizi, kad tas tiks izpildīts, neatkarīgi no gala rezultāta. Ja apstiprināšana neizdodas tīkla problēmu dēļ, pieprasījums tiks izpildīts ar citu kārtas numuru, kad mēģināsit vēlreiz.

Vaicājumu plānotāji var daudz pastāstīt par datu bāzi

Vaicājumu plānotāji nosaka, kā vaicājums tiks izpildīts datu bāzē. Viņi arī analizē pieprasījumus un optimizē tos pirms to nosūtīšanas. Plānotāji var sniegt tikai dažus iespējamos aprēķinus, pamatojoties uz viņu rīcībā esošajiem signāliem. Piemēram, kāda ir labākā meklēšanas metode šādam vaicājumam?

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

Rezultātus var iegūt divos veidos:

  • Pilna tabulas skenēšana: varat apskatīt katru tabulas ierakstu un atgriezt rakstus ar atbilstošu autora vārdu un pēc tam tos pasūtīt.
  • Indeksa skenēšana: varat izmantot indeksu, lai atrastu atbilstošus ID, iegūtu šīs rindas un pēc tam tās sakārtotu.

Vaicājumu plānotāja uzdevums ir noteikt, kura stratēģija ir vislabākā. Ir vērts ņemt vērā, ka vaicājumu plānotājiem ir tikai ierobežotas prognozēšanas iespējas. Tas var novest pie sliktiem lēmumiem. DBA vai izstrādātāji var tos izmantot, lai diagnosticētu un precizētu neefektīvus vaicājumus. Jaunās DBVS versijas var konfigurēt vaicājumu plānotājus, un pašdiagnostika var palīdzēt datu bāzes atjaunināšanas laikā, ja jaunā versija rada veiktspējas problēmas. Lēni vaicājumu žurnāli, latentuma problēmu pārskati vai izpildes laika statistika var palīdzēt noteikt vaicājumus, kuriem nepieciešama optimizācija.

Dažas vaicājumu plānotāja parādītās metrikas var būt pakļautas trokšņiem (īpaši, novērtējot latentumu vai CPU laiku). Labs plānotāju papildinājums ir rīki izpildes ceļa izsekošanai un izsekošanai. Tie ļauj diagnosticēt šādas problēmas (diemžēl ne visas DBVS nodrošina šādus rīkus).

Tiešsaistes migrācija ir sarežģīta, bet iespējama

Tiešsaistes migrācija, reāllaika migrācija vai reāllaika migrācija nozīmē pāreju no vienas datu bāzes uz citu bez dīkstāves vai datu sabojāšanas. Tiešo migrāciju ir vieglāk veikt, ja pāreja notiek tajā pašā DBVS/dzinējā. Situācija kļūst sarežģītāka, ja nepieciešams pāriet uz jaunu DBVS ar atšķirīgām veiktspējas un shēmas prasībām.

Ir dažādi tiešsaistes migrācijas modeļi. Šeit ir viens no tiem:

  • Iespējot dubulto ierakstu abās datubāzēs. Jaunajā datu bāzē šajā posmā nav visu datu, bet tā pieņem tikai jaunākos datus. Kad esat par to pārliecināts, varat pāriet uz nākamo soli.
  • Iespējot lasīšanu no abām datu bāzēm.
  • Konfigurējiet sistēmu tā, lai lasīšana un rakstīšana galvenokārt tiktu veikta jaunajā datu bāzē.
  • Pārtrauciet rakstīšanu vecajā datu bāzē, turpinot lasīt datus no tās. Šajā posmā jaunajā datu bāzē joprojām trūkst dažu datu. Tie ir jākopē no vecās datu bāzes.
  • Vecā datu bāze ir tikai lasāma. Kopējiet trūkstošos datus no vecās datu bāzes uz jauno. Kad migrācija ir pabeigta, pārslēdziet ceļus uz jauno datu bāzi, apturiet veco un izdzēsiet to no sistēmas.

Papildus informācijai iesaku sazināties raksts, kurā detalizēti aprakstīta Stripe migrācijas stratēģija, kuras pamatā ir šis modelis.

Ievērojams datu bāzes pieaugums rada neparedzamības pieaugumu

Datu bāzes izaugsme rada neparedzamas problēmas, kas saistītas ar tās mērogu. Jo vairāk mēs zinām par datu bāzes iekšējo struktūru, jo labāk varam paredzēt, kā tā tiks mērogota. Tomēr dažus brīžus joprojām nav iespējams paredzēt.
Bāzei pieaugot, iepriekšējie pieņēmumi un cerības attiecībā uz datu apjomu un tīkla joslas platuma prasībām var kļūt novecojuši. Šajā gadījumā rodas jautājums par nozīmīgiem dizaina remontiem, liela mēroga darbības uzlabojumiem, izvietošanas pārdomāšanu vai migrāciju uz citām DBVS, lai izvairītos no iespējamām problēmām.

Bet nedomājiet, ka vienīgās nepieciešamās ir izcilas zināšanas par esošās datu bāzes iekšējo struktūru. Jauni svari nesīs sev līdzi jaunus nezināmos. Neparedzami sāpju punkti, nevienmērīgs datu sadalījums, negaidītas joslas platuma un aparatūras problēmas, arvien pieaugošā trafika un jauni tīkla segmenti liks jums pārdomāt datu bāzes pieeju, datu modeli, izvietošanas modeli un datu bāzes lielumu.

...

Laikā, kad sāku domāt par šī raksta publicēšanu, manā sākotnējā sarakstā jau bija vēl pieci vienumi. Tad nāca milzīgs skaits jaunas idejas par to, ko vēl var segt. Tāpēc raksts skar vismazāk acīmredzamās problēmas, kurām jāpievērš maksimāla uzmanība. Taču tas nenozīmē, ka tēma ir izsmelta un turpmāk savos materiālos pie tās vairs neatgriezīšos un izmaiņas esošajā netaisīšu.

PS

Lasi arī mūsu emuārā:

Avots: www.habr.com

Pievieno komentāru