Săriți la conținut

Blog ·

Reținerea devine amplasarea

Mutarea unei mașini între două rackuri are o clipă periculoasă: momentul în care destinația nu este nici rezervată, nici ocupată. Iată cum am eliminat-o.

De Provibr

Mutarea unui server de la o unitate de rack la alta înseamnă, fizic, o treabă scurtă cu o șurubelniță și încă o pereche de mâini. Evidența din jurul ei este locul unde trăiește eșecul interesant, iar el trăiește într-o singură clipă: momentul în care destinația nu mai este rezervată și încă nu este ocupată.

Dacă scrierea altcuiva nimerește în acea clipă, două mașini sunt înregistrate în același slot. Într-o bază de date asta se citește drept o încălcare de restricție despre care se poate discuta. Pe teren se citește drept un inginer care stă în fața unui rack cu o mașină în brațe și fără niciun loc în care să o pună.

Fereastra și cum să nu o aveți deloc

Succesiunea evidentă are trei pași. Se eliberează vechea revendicare, se eliberează reținerea pentru mutare de pe destinație, se scrie noua amplasare. În interiorul unei singure tranzacții, acea fereastră este invizibilă pentru celelalte sesiuni, exact motivul pentru care este ușor să o lăsați acolo: va trece orice test scrieți. Rămâne totuși o fereastră, pentru că instrucțiunea de după ea lucrează pe un slot pe care instrucțiunea precedentă tocmai l-a eliberat, iar o singură ordonare greșită într-o refactorizare ulterioară este de ajuns.

Noi facem ceva mai simplu. Reținerea pentru mutare este promovată, nu înlocuită. Rândurile care consemnează ce unități sunt ocupate rămân exact unde sunt; numai antetul își schimbă felul, dintr-o reținere pentru mutare într-o amplasare, iar expirarea lui este pusă pe null în aceeași actualizare. Vechea amplasare se închide în aceeași tranzacție. Nu există niciun moment în care destinația să fie liberă, așa că nu există o a doua ocazie de coliziune, iar totul este o singură actualizare și nu o inserare care trebuie să reușească.

Identificatorul revendicării rămâne neschimbat de-a lungul promovării, ceea ce este modul de a verifica faptul că asta s-a întâmplat cu adevărat și nu ceva care doar seamănă cu asta văzut din afară.

Punerea expirării pe null nu este chestiune de ordine. O verificare din baza de date refuză o amplasare care poartă una, pentru că o amplasare care încetează în tăcere să conteze într-o marți, în timp ce mașina este încă înșurubată acolo, este 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.

Arbitrul rămâne un singur index

Nimic din cele de mai sus nu este lucrul care previne o dublă rezervare. Acela rămâne un index unic parțial peste rack, față și slot, restrâns la rândurile care nu au fost eliberate, iar o reținere pentru mutare stă sub el exact la fel ca o amplasare.

Doi ingineri care aleg aceeași unitate în aceeași secundă o văd amândoi liberă în funcția de planificare ce rulează înainte de scriere, iar exact unul dintre ei trece de baza de date. Scrierea celuilalt eșuează pe index, iar singura cale care scrie ocuparea prinde acea încălcare și o transformă într-un refuz lizibil, care numește unitățile aflate în conflict. Care anume propoziție iese se decide după numele restricției care s-a declanșat, pentru că „unitatea aceasta este ocupată” și „mașina aceasta stă deja în altă parte” trimit un om la două rackuri diferite. O inserare directă, care sare peste acea cale, primește în schimb încălcarea brută. Măsurat în ambele feluri, pentru că a raționa despre nivelurile de izolare nu este o dovadă.

Funcția de planificare este un mesaj, nu o apărare. Indexul este apărarea. Ținerea acestor două roluri separate este ceea ce îi permite mesajului să fie de ajutor fără ca cineva să fie ispitit să se bazeze pe el.

Nouă stări și două ieșiri care încetează să existe

O mutare are nouă stări: ciornă, planificată, aprobată, în desfășurare, în așteptarea verificării, necesită reconciliere, încheiată, anulată și eșuată. Ce tranziții sunt permise este o structură cu câte o intrare pentru fiecare dintre cele nouă și nu o instrucțiune switch. Un switch cu o ramură implicită lasă o stare nou adăugată să cadă în permis, iar direcția periculoasă aici este exact aceea: o stare pe care cineva o adaugă pentru că se întâmplă ceva neobișnuit ar fi prima stare căreia i s-ar permite orice.

Rândul interesant este cel care pleacă din in_progress, pentru că din el lipsesc două ieșiri pe care le are orice stare anterioară: nu există drum înapoi către aprobat și niciun drum către anulat. În acel punct cineva ține mașina în mâini, iar singurele ieșiri sincere sunt „raportat ca încheiat”, „nu știm” și „a eșuat”. Anularea este o decizie luată dinainte; după ce s-a raportat munca fizică, o revenire în baza de date este o afirmație despre lumea fizică pe care nu a verificat-o nimeni.

Cele trei stări finale, încheiată, anulată și eșuată, poartă liste goale și nu absența oricărei intrări. Aceasta este diferența dintre „de aici nu mai continuă nimic” și „nu s-a gândit nimeni la asta”, iar numai prima este o decizie.

Un al doilea tabel spune, pentru fiecare stare, dacă destinația trebuie ținută. Intrarea care merită apărată este needs_reconcile, care o păstrează. În acel punct nimeni nu știe unde se află mașina, așa că eliberarea destinației ar putea pune o a doua mașină pe o unitate care s-ar putea să fie deja ocupată.

Mutarea nu înseamnă tranzitul

Echipamentele poartă o stare de proces, iar această lucrare a adăugat moving lângă in_transit, care exista deja. Sună a sinonime și nu sunt. moving înseamnă că mașina este relocată în interiorul acestui centru de date și că spațiul ei de destinație este rezervat. in_transit înseamnă că este pe drum între două amplasamente și, prin urmare, nu se află nicăieri. Amândouă blochează livrarea către un client, dar răspund la întrebări diferite atunci când cineva întreabă unde se află o mașină, iar contopirea lor ar face greșit răspunsul la a doua întrebare. Separarea este impusă și nu doar descrisă: o verificare din baza de date cere ca amplasamentul de origine al unei mutări și cel de destinație să fie unul și același, așa că o mutare este prin construcție ceva ce se petrece în interiorul unei singure clădiri, iar drumul dintre două amplasamente este un alt proces, cu alt cuvânt pentru el.

Starea pe care o avea mașina înainte de mutare este stocată în verificarea prealabilă înghețată, nu presupusă. Hardware-ul abia sosit stă în staging, iar readucerea tuturor la normal după aceea ar scoate în tăcere din recepție fiecare mașină relocată.

Două ieșiri din necunoaștere și niciuna nu este o revenire

Când rezultatul fizic este incert, mutarea trece în needs_reconcile și cineva trebuie să meargă să se uite. Există două răspunsuri, iar amândouă sunt consemnate ca observații.

ObservațieCe se întâmplă cu mutareaCe se întâmplă cu spațiul
Văzută la destinațieÎncheiatăReținerea devine amplasarea, ca mai sus
Văzută la origineEșuată, cu un motiv care spune că nu a fost niciodată executatăReținerea este eliberată; amplasarea inițială rămâne neatinsă

A doua este în mod deliberat eșuată și nu anulată. Cineva a făcut muncă fizică, iar mașina nu s-a mutat; acesta este un rezultat, nu o alegere. Și nu este o revenire: baza de date nu este readusă la o stare care pretinde că nu s-a întâmplat nimic. Istoricul de amplasare este numai prin adăugare, corecțiile sunt înregistrări compensatoare noi, iar diferența iese la iveală o lună mai târziu, când cineva întreabă de ce o mașină a stat pe loc o zi. O revenire nu lasă nimic în urmă. O înregistrare compensatoare arată că a existat o incertitudine și cum a fost lămurită.

Acele rânduri de istoric poartă identificatori de amplasament și de rack fără chei străine, în mod intenționat. Un rack scos din uz la anul nu schimbă ce a stat în el în martie trecut.

Două decizii mici care vor conta mai târziu

Mutarea arată către operațiunea ei de fundal printr-o referință care este pusă pe SET NULL atunci când operațiunea este ștearsă, în loc de CASCADE. Operațiunile sunt curățate după nouăzeci de zile. Evidența hardware nu este, iar o cascadă ar însemna că politica de retenție a barelor de progres șterge în tăcere consemnarea locului în care a ajuns o mașină.

Iar un index unic parțial permite o singură mutare deschisă pentru fiecare echipament. Fără el, doi oameni pot planifica două destinații diferite pentru aceeași mașină, iar amândouă arată corect pe propriul ecran.

Ce am nota

  1. Promovați, nu recreați. Dacă o rezervare și o alocare au aceeași formă, schimbați felul în loc să eliberați și să scrieți, și verificați că identificatorul a supraviețuit.
  2. Țineți arbitrul în baza de date și explicația în cod. Indexul decide cine câștigă; funcția de planificare spune care unități intră în conflict.
  3. Scrieți tabelul de tranziții peste fiecare stare. O ramură implicită transformă o stare nouă într-una permisă.
  4. După o muncă fizică raportată, nu reveniți niciodată. Adăugați o stare care înseamnă „necunoscut” și dați-i două ieșiri documentate, amândouă observații.
  5. Faceți istoricul numai prin adăugare și lăsați corecțiile să fie rânduri noi, pentru că faptul că ceva a fost cândva incert este el însuși o informație.
  6. Verificați de ce anume este legată politica dumneavoastră de retenție. O cascadă dintr-un tabel cu viață scurtă într-unul cu viață lungă este un defect de pierdere de date cu orar.

Pentru claritate în privința a ceea ce este asta: lucrul la logistica centrului de date stă în spatele unui indicator de lansare care este oprit implicit, cu o setare pentru fiecare organizație deasupra lui, așa că nimic din el nu se poate cumpăra astăzi. Patru lucruri sunt nedovedite. Evenimentul de progres în direct pentru o mutare a fost exersat fără magistrala lui de mesaje. Anularea unei mutări din ecranul de operațiuni nu a fost condusă într-un browser. O reținere care să fi expirat cu adevărat nu a fost niciodată observată, iar în mod deliberat nu există nicio măturare care să șteargă una, pentru că o reținere care își face singură ordine în timp ce cineva stă la rack este exact contradicția pe care indexul există ca să o prevină. Iar aceeași verificare de amplasament descrisă mai sus nu s-a declanșat niciodată cu adevărat, pentru că nu a fost semănat un al doilea amplasament cu care să se declanșeze.

Din lucrul la centrul de date de la Provibr. De ce un index unic parțial este singura limită reală a ocupării se află în singura limită reală a ocupării unui rack, iar de ce cele cinci întrebări de capacitate de deasupra unui rack nu se pot aduna se află în spațiul din rack nu înseamnă capacitate.

Începeți cu o gazdă și un agent

Creați un cont, instalați agentul cu o singură comandă și conectați primul dumneavoastră host Proxmox. Perioada de probă durează 14 zile și nu cere date de plată.