Salta al contenuto

Blog ·

Il fermo diventa la collocazione

Spostare una macchina fra due rack ha un istante pericoloso: quello in cui la destinazione non è né prenotata né occupata. Ecco come lo abbiamo tolto.

Di Provibr

Spostare un server da un’unità rack a un’altra è, fisicamente, un lavoro breve con un cacciavite e un secondo paio di mani. È l’amministrazione che ci sta intorno a ospitare il guasto interessante, e quel guasto vive in un solo istante: il momento in cui la destinazione non è più prenotata e non è ancora occupata.

Se la scrittura di qualcun altro cade in quell’istante, due macchine risultano registrate nello stesso slot. In un database questo si legge come una violazione di vincolo su cui si può discutere. Sul pavimento della sala si legge come un tecnico fermo davanti a un rack con una macchina in mano e nessun posto dove metterla.

La finestra, e come non averne una

La sequenza ovvia è fatta di tre passi. Rilasciare la vecchia assegnazione, rilasciare il fermo per spostamento sulla destinazione, scrivere la nuova collocazione. Dentro una sola transazione quella finestra è invisibile alle altre sessioni, ed è esattamente per questo che è facile lasciarla lì: supererà ogni test che si scriva. Resta comunque una finestra, perché l’istruzione successiva opera su uno slot che l’istruzione precedente ha liberato, e basta un ordinamento sbagliato durante un rifacimento futuro.

Noi facciamo qualcosa di più semplice. Il fermo per spostamento viene promosso anziché sostituito. Le righe che registrano quali unità sono occupate restano esattamente dove sono; cambia soltanto il tipo dell’intestazione, da fermo per spostamento a collocazione, e nello stesso aggiornamento la sua scadenza viene messa a null. La vecchia collocazione si chiude nella stessa transazione. Non esiste alcun momento in cui la destinazione sia libera, quindi non c’è una seconda occasione per collidere, e il tutto è un aggiornamento anziché un inserimento che deve riuscire.

L’identificatore dell’assegnazione resta invariato attraverso la promozione, ed è il modo per verificare che sia davvero successo questo e non qualcosa che da fuori gli somiglia soltanto.

Mettere la scadenza a null non è pulizia formale. Un vincolo di controllo del database rifiuta una collocazione che ne porti una, perché una collocazione che smette di contare in silenzio un martedì mentre la macchina è ancora avvitata dentro è un rack che il software crede abbia un’unità libera. Una prenotazione che scade è una funzionalità; una collocazione che scade è una bugia con un timer sopra.

L’arbitro resta un solo indice

Niente di quanto sopra è la cosa che impedisce una doppia assegnazione. Quella resta un indice univoco parziale su rack, lato e slot, limitato alle righe che non sono state rilasciate, e un fermo per spostamento ci sta sotto esattamente come una collocazione.

Due tecnici che scelgono la stessa unità nello stesso secondo la vedono entrambi libera nella funzione di pianificazione che gira prima della scrittura, e dal database ne passa esattamente uno. La scrittura dell’altro fallisce sull’indice, e l’unica via che scrive l’occupazione intercetta quella violazione e la trasforma in un rifiuto leggibile che nomina le unità in conflitto. Quale frase ne esca lo sceglie il nome del vincolo che è scattato, perché «questa unità è occupata» e «questa macchina sta già da un’altra parte» mandano una persona verso due rack diversi. Un inserimento diretto che salti quella via riceve invece la violazione grezza. Misurato in entrambi i modi, perché ragionare sui livelli di isolamento non è una prova.

La funzione di pianificazione è un messaggio, non una difesa. L’indice è la difesa. Tenere separati quei due ruoli è ciò che permette al messaggio di essere utile senza che nessuno sia tentato di fidarsene.

Nove stati, e due uscite che smettono di esistere

Uno spostamento ha nove stati: bozza, pianificato, approvato, in corso, in attesa di verifica, da riconciliare, completato, annullato e fallito. Quali transizioni siano lecite è un record su tutti e nove anziché un’istruzione switch. Uno switch con un ramo predefinito lascia che uno stato appena aggiunto ricada nel permesso, e la direzione pericolosa qui è esattamente quella: uno stato che qualcuno aggiunge perché sta succedendo qualcosa di insolito sarebbe il primo stato a cui è consentito qualunque cosa.

La riga interessante è quella che esce da in_progress, perché da lì mancano due uscite che ogni stato precedente ha: non c’è alcun percorso di ritorno ad approvato e nessun percorso verso annullato. A quel punto qualcuno ha la macchina in mano, e le uniche uscite oneste sono «riferito come fatto», «non lo sappiamo» e «è fallito». Annullare è una decisione che si prende prima; dopo che un lavoro fisico è stato riferito, un rollback nel database è un’affermazione sul mondo fisico che nessuno ha verificato.

I tre stati terminali, completato, annullato e fallito, portano elenchi vuoti anziché nessuna voce. È la differenza fra «da qui non si prosegue» e «nessuno ci ha pensato», e solo la prima è una decisione.

Una seconda tabella dice, per ogni stato, se la destinazione debba restare tenuta. La voce che vale la pena difendere è needs_reconcile, che la tiene. A quel punto nessuno sa dove sia la macchina, quindi rilasciare la destinazione potrebbe mettere una seconda macchina su un’unità forse già occupata.

In spostamento non vuol dire in transito

Le macchine portano uno stato di processo, e questo lavoro ha aggiunto moving accanto all’esistente in_transit. Sembrano sinonimi e non lo sono. moving significa che la macchina viene spostata dentro questo datacenter e che il suo spazio di destinazione è prenotato. in_transit significa che è su strada fra due siti e quindi non è da nessuna parte. Entrambi bloccano la consegna a un cliente, ma rispondono a domande diverse quando qualcuno chiede dove sia una macchina, e fonderli renderebbe sbagliata la risposta alla seconda. La separazione è imposta e non soltanto descritta: un vincolo di controllo del database pretende che il sito di origine e il sito di destinazione di uno spostamento siano lo stesso, quindi uno spostamento è per costruzione qualcosa che accade dentro un solo edificio, e la strada fra due siti è un processo diverso con una parola diversa.

Quale stato avesse la macchina prima dello spostamento è conservato nel controllo preliminare congelato, non dato per scontato. L’hardware appena arrivato sta in staging, e riportare tutto a normal alla fine farebbe uscire in silenzio dall’accettazione ogni macchina spostata.

Due uscite dal non sapere, e nessuna delle due è un rollback

Quando l’esito fisico è incerto, lo spostamento passa a needs_reconcile e qualcuno deve andare a guardare. Le risposte sono due, ed entrambe vengono registrate come osservazioni.

OsservazioneChe cosa succede allo spostamentoChe cosa succede allo spazio
Vista alla destinazioneCompletatoIl fermo diventa la collocazione, come sopra
Vista all’origineFallito, con una ragione che dice che non è mai stato eseguitoIl fermo viene rilasciato; la collocazione originale resta intatta

La seconda è deliberatamente fallita anziché annullata. Qualcuno ha fatto un lavoro fisico e la macchina non si è mossa; quello è un esito, non una scelta. E non è un rollback: il database non viene riportato a uno stato che finge che non sia successo nulla. La cronologia delle posizioni si scrive solo in aggiunta, le correzioni sono nuove voci di compensazione, e la differenza salta fuori un mese dopo, quando qualcuno chiede perché una macchina sia rimasta ferma per un giorno. Un rollback non lascia nulla dietro di sé. Una voce di compensazione mostra che c’è stata un’incertezza e come è stata risolta.

Quelle righe di cronologia portano identificatori di sito e di rack senza chiavi esterne, di proposito. Un rack dismesso l’anno prossimo non cambia che cosa ci stava dentro lo scorso marzo.

Due piccole decisioni che conteranno più avanti

Lo spostamento punta alla propria operazione in background con un riferimento impostato su SET NULL quando l’operazione viene eliminata, anziché su CASCADE. Le operazioni vengono potate dopo novanta giorni. L’amministrazione dell’hardware no, e una cascata significherebbe che la politica di conservazione delle barre di avanzamento cancella in silenzio il registro di dove è andata a finire una macchina.

E un indice univoco parziale ammette un solo spostamento aperto per macchina. Senza di esso, due persone possono pianificare due destinazioni diverse per la stessa macchina ed entrambe sembrano corrette sul proprio schermo.

Che cosa metteremmo per iscritto

  1. Promuovere, non ricreare. Se una prenotazione e un’assegnazione hanno la stessa forma, si cambi il tipo anziché rilasciare e scrivere, e si verifichi che l’identificatore sia sopravvissuto.
  2. Tenere l’arbitro nel database e la spiegazione nel codice. L’indice decide chi vince; la funzione di pianificazione dice quali unità sono in conflitto.
  3. Scrivere la tabella delle transizioni su ogni stato. Un ramo predefinito trasforma un nuovo stato in uno permesso.
  4. Dopo un lavoro fisico riferito, non tornare mai indietro. Si aggiunga uno stato che significhi «sconosciuto» e gli si diano due uscite documentate, entrambe osservazioni.
  5. Rendere la cronologia solo in aggiunta e lasciare che le correzioni siano righe nuove, perché il fatto che qualcosa sia stato incerto è a sua volta un’informazione.
  6. Controllare a che cosa è attaccata la propria politica di conservazione. Una cascata da una tabella di vita breve verso una di vita lunga è un difetto di perdita di dati con un calendario.

Per chiarezza su che cosa sia questo: il lavoro sulla logistica di datacenter sta dietro un flag di rollout disattivato per impostazione predefinita, con sopra un’impostazione per organizzazione, quindi niente di tutto questo è acquistabile oggi. Quattro cose non sono dimostrate. L’evento di avanzamento dal vivo di uno spostamento è stato esercitato senza il suo bus dei messaggi. L’annullamento di uno spostamento dalla schermata delle operazioni non è stato provato in un browser. Un fermo davvero scaduto non è mai stato osservato, e deliberatamente non esiste alcuna procedura periodica che ne liberi uno, perché un fermo che si mette in ordine da solo mentre qualcuno è in piedi davanti al rack è esattamente la contraddizione che l’indice esiste per impedire. E lo stesso controllo di sito descritto sopra non è mai scattato davvero, perché non è stato creato alcun secondo sito con cui farlo scattare.

Dal lavoro sul datacenter di Provibr. Perché un indice univoco parziale sia l’unico limite reale all’occupazione è in l’unico limite reale all’occupazione di un rack, e perché le cinque domande di capacità sopra un rack non si possano sommare è in lo spazio in rack non è capacità.

Inizi con un host e un agente

Crei un account, installi l’agente con un solo comando e colleghi il suo primo host Proxmox. Il periodo di prova dura 14 giorni e non chiede alcun dato di pagamento.