Blog ·
Singura limită reală a ocupării unui rack
Doi ingineri aleg în același timp aceeași unitate de rack. Formularul le spune ambilor că este liberă. Decide un index unic parțial și nimic altceva nu poate.
De Provibr
Doi ingineri amplasează mașini în același rack. Amândoi deschid formularul, amândoi se uită la U nouă, amândoi văd un slot liber, amândoi apasă salvare. Orice ar face codul aplicației dumneavoastră între acele două cereri, există o fereastră în care amândoi citesc același răspuns, și nicio verificare dinaintea scrierii nu o închide.
Aceasta este cea mai veche cursă din carte și are un singur răspuns corect: decide baza de date. Tot ce se află deasupra ei este acolo ca să producă un refuz lizibil, nu ca să prevină o coliziune. Inversarea acestei ordini este exact felul în care ajungeți cu o regulă de unicitate care se scurge într-o zi aglomerată, iar într-un centru de date o scurgere înseamnă cineva cu un cărucior stând în fața unui rack care este deja plin.
Granița este un singur index
Ocuparea este stocată de două ori, în mod intenționat. O revendicare are un rând de antet, care este lucrul făcut de cineva: această față, de la această unitate până la aceea, iar pentru o amplasare, mașina care stă în ea. Și are câte un rând pentru fiecare slot ocupat: acest rack, această față, acest singur U.
Tabelul de sloturi există exact dintr-un singur motiv. El poartă un index unic parțial pe rack, pe față și pe numărul de slot, restrâns la rândurile care nu au fost eliberate. Indexul acela este singura limită reală a ocupării din tot sistemul. Nimic altceva nu poate fi, pentru că un index unic nu poate face join: el vede doar coloanele rândului pe care stă, așa că rackul și fața trebuie denormalizate pe rândul de slot pentru ca restricția să existe în general.
Prețul este că eliberarea unei revendicări înseamnă două actualizări într-o singură tranzacție, de vreme ce marcajul de timp al eliberării trăiește și pe antet, și pe sloturi. Câștigul este că invariantul este impus de baza de date, nu de grija celui care scrie următoarea funcționalitate.
Am măsurat asta în loc să raționăm despre ea. Două conexiuni Postgres reale, o barieră reciprocă astfel încât amândouă să fie în tranzacția lor înainte ca vreuna să facă commit, amândouă revendicând U nouă în față. Rezultatul: exact o revendicare scrisă, o eroare 23505 care numește acel index și niciun antet orfan lăsat în urmă de anulare. Aceasta este propoziția pe care vreți să o puteți scrie despre o garanție de concurență, iar din citirea codului nu o puteți scrie.
La ce servește de fapt verificarea dinaintea scrierii
Există o funcție pură care planifică o revendicare și care refuză în trei feluri, în această ordine.
Fața nu există. Un cadru deschis fără spate nu este un rack în spatele căruia atârnați ceva, motiv pentru care faptul că un rack are o față și un spate este o proprietate a rackului, nu o presupunere.
În afara limitelor. Întregul interval trebuie să încapă între unitatea de start a rackului și capătul lui, inclusiv. Nu toate rackurile încep de la unu și nu toate numerotează în sus, așa că aceasta este aritmetică față de geometria acelui rack anume și nu față de numărul patruzeci și doi.
Ocupat, iar acest refuz poartă lista sloturilor care intră în conflict. Un mesaj care spune „plin” trimite pe cineva înapoi la formular fără nicio idee unde să se uite. Un mesaj care spune că U nouă și U zece din față sunt luate îl trimite la răspuns.
Niciunul dintre acestea nu este granița. Amândoi inginerii din primul paragraf trec de toate trei. Funcția există pentru ca situația obișnuită, adică o singură persoană pe rând care greșește, să producă o propoziție în loc de un cod de eroare de bază de date.
Adâncimea necunoscută se comportă ca cea plină
Fiecare echipament are o clasă de adâncime: plină, pe jumătate sau necunoscută. Un element cu jumătate de adâncime revendică doar fața de care atârnă. Un element cu adâncime plină revendică fața și spatele.
Necunoscutul revendică și el fața și spatele, iar alegerea aceasta merită apărată, pentru că implicitul intuitiv este opusul. Necunoscutul pare o dată lipsă pe care o veți completa mai târziu, iar cât timp așteptați pare inofensiv să lăsați cealaltă parte liberă.
Nu este inofensiv. O mașină a cărei adâncime se dovedește a fi plină nu poate fi instalată dacă între timp cineva a umplut spatele, iar corectarea se întâmplă cu mașina deja pe teren. Blocarea spatelui vă costă un slot pe care poate l-ați fi avut. Neblocarea lui vă costă o livrare. Necunoscutul nu este absența unei restricții, este o restricție pe care încă nu o puteți numi, iar partea sigură a ei este cea conservatoare.
Același principiu străbate restul modelului de capacitate: o greutate necunoscută, un consum necunoscut de putere sau o stare de revendicare învechită se citesc drept necunoscut sau blocat, și niciodată drept capacitate liberă.
O amplasare nu expiră niciodată
Revendicările vin în patru feluri. O amplasare este o mașină care se află fizic acolo. Un blocaj este spațiu scos din serviciu pentru cablare. O reținere pentru mutare și o rezervare sunt cele două care păstrează spațiu pentru ceva aflat în mișcare sau pe comandă. Numai primul are astăzi un ecran; celelalte trei există ca date, pentru ca primitiva să fie un singur lucru, nu patru lucruri asemănătoare.
O verificare din baza de date impune ca o amplasare să nu aibă expirare. Sună a regulă măruntă. Ce previne este un rând care încetează în tăcere să conteze într-o marți, în timp ce mașina este încă înșurubată acolo, adică un rack despre care software-ul crede că are un slot liber. O rezervare care expiră este o funcționalitate; o amplasare care expiră este o minciună cu ceas.
O a doua verificare cere ca o amplasare să aibă un echipament, de vreme ce celelalte trei feluri, în mod legitim, nu au niciunul, iar un index unic parțial permite cel mult o amplasare activă pentru fiecare echipament. Fără indexul acela, aceeași mașină poate fi înregistrată în două rackuri deodată. Nu este o problemă de calitate a datelor pe care o observați într-un raport; este o problemă pe care o observați când cineva stă în fața rackului greșit.
Merită știut despre indecșii de forma aceasta: ei sunt globali, nu delimitați pentru fiecare organizație. O mașină care poartă deja un rând activ intră în coliziune cu restricția de unicitate, nu cu o verificare de proprietate, chiar și atunci când a doua încercare vine de la o altă organizație. Aceasta este partea sigură și înseamnă totodată că un test cu două organizații are nevoie de un al treilea echipament, pentru că restricția se declanșează înainte ca logica de proprietate să apuce să ruleze.
Aceeași formă cu un nivel mai sus
Predarea unei mașini către un client are structura identică și are nevoie de doi indecși, nu de unul, pentru că sunt doi invarianți pe care oamenii îi enunță de obicei într-o singură propoziție.
Un serviciu stă pe cel mult o mașină. Fără asta, un serviciu poate indica două echipamente, iar fișa lui de locație indică în două direcții.
O mașină este emisă către cel mult un serviciu. Fără asta, aceeași mașină este vândută de două ori, și aflați când sună doi clienți.
Amândoi sunt indecși unici parțiali pe rânduri a căror dată de sfârșit este încă goală, ceea ce este aceeași construcție ca indexul de sloturi și din același motiv: verificarea din aplicație produce refuzul lizibil, indexul decide cine câștigă.
O regulă nu a putut intra în baza de date. O legătură trebuie să indice un serviciu dedicat, iar o restricție de tip CHECK nu poate citi alt tabel. Aceea trăiește în funcția care scrie legătura, și merită să fiți expliciți despre care dintre regulile dumneavoastră sunt impuse de schemă și care sunt impuse de un traseu de cod, pentru că al doilea fel este bun doar pe măsura numărului de trasee de scriere pe care vă amintiți să le direcționați prin el.
Legăturile sunt istorice, nu curente. Data de sfârșit este ce face rândul inactiv, iar fiecare citire a unei locații fizice filtrează după ea și după organizația atât a legăturii, cât și a echipamentului. Scoateți filtrele acelea și un fost client citește rackul și unitatea clientului care a venit după el. Asta a fost dovedit roșu înainte să fie reparat, singurul mod în care puteți ști că un filtru chiar lucrează.
Ce am nota
- Puneți unicitatea acolo unde este rândul. Dacă restricția are nevoie de un join, denormalizați coloanele de care are nevoie; un index nu poate face join, iar un trigger nu este o restricție.
- Materializați unitatea de dispută. Câte un rând pentru fiecare slot ocupat, nu un interval pe un antet, pentru că un interval nu poate fi unic față de alt interval.
- Dovediți cursa cu două conexiuni și o barieră. Raționamentul despre nivelurile de izolare nu este o dovadă.
- Lăsați preverificarea să fie un mesaj, nu o apărare, și faceți-o să numească sloturile exacte care intră în conflict.
- Faceți necunoscutul să se comporte ca varianta scumpă, astfel încât o măsurătoare lipsă să nu se prezinte niciodată drept spațiu liber.
Pentru claritate despre unde stă asta: munca de logistică pentru centrul de date se află în spatele unui indicator de lansare oprit implicit, cu o setare pentru fiecare organizație peste el, așa că nimic din cele de mai sus nu se poate cumpăra astăzi. Două lucruri sunt nedovedite: măsurătoarea de concurență a fost rulată pe revendicări de tip blocaj, într-un test direct pe baza de date, nu pe traseul de amplasare însuși, iar felurile reținere pentru mutare și rezervare nu au încă un scriitor. Obiceiul mai larg de a lăsa baza de date să fie arbitrul apare și în alte părți din acest produs, în cum sunt date adresele dintr-un pool și în cum un interval de VMID este de fapt o graniță de permisiuni.
Din munca la centrul de date de la Provibr. De ce cele cinci întrebări despre capacitatea de deasupra unui rack nu trebuie adunate se află în spațiul din rack nu înseamnă capacitate, iar ce se întâmplă când un sistem extern pretinde că știe unde stă o mașină se află în când NetBox este sursa de adevăr.