Perché potrebbe essere necessaria la replica parziale?

Ciao a tutti. Sono Vladislav Rodin. Attualmente insegno sul portale OTUS corsi dedicati all'architettura del software e all'architettura del software soggetta a carichi elevati. In vista dell'inizio di un nuovo ciclo di corsi «Architetto dei sistemi ad alta disponibilità» ho deciso di scrivere un breve materiale originale che desidero condividere con voi.

Perché potrebbe essere necessaria la replica parziale?

Introduzione

Poiché su un HDD possono essere eseguite solo circa 400-700 operazioni al secondo (cosa impensabile rispetto ai tipici rps delle sistemi ad alto carico), un database tradizionale diventa un collo di bottiglia nell'architettura. Pertanto, è necessario prestare particolare attenzione ai pattern di scalabilità di questo tipo di archiviazione.

Attualmente ci sono 2 pattern di scalabilità del database: replicazione e sharding. Lo sharding consente di scalare l'operazione di scrittura e, di conseguenza, ridurre gli rps di scrittura su un singolo server del proprio cluster. La replicazione consente la stessa cosa, ma con le operazioni di lettura. È proprio a questo pattern che è dedicato questo articolo.

Replica

Se si guarda alla replicazione da un punto di vista molto generico, è una cosa semplice: avevi un server, su di esso c'erano i dati, e poi quel server ha smesso di gestire il carico di lettura di quei dati. Aggiungi un paio di server, sincronizzi i dati su tutti i server e l'utente può leggere da qualsiasi server del tuo cluster.

Nonostante la sua apparente semplicità, ci sono diversi modi per classificare le varie implementazioni di questo schema:

  • Per ruoli nel cluster (master-master o master-slave)
  • Per oggetti inviati (row-based, statement-based o mixed)
  • Per meccanismo di sincronizzazione dei nodi

Oggi ci concentreremo proprio sul terzo punto.

Come avviene il commit delle transazioni

Questo argomento non è direttamente correlato alla replicazione e potrebbe complessivamente richiedere un articolo separato, ma poiché senza comprendere il meccanismo di commit delle transazioni la lettura successiva risulterebbe inutile, mi permetto di ricordare le cose più fondamentali. Il commit delle transazioni avviene in 3 fasi:

  1. Registrazione della transazione nel registro del database.
  2. Applicazione della transazione nel motore del database.
  3. Restituzione della conferma al cliente sull'applicazione riuscita della transazione.

Nelle diverse basi in questo algoritmo possono sorgere delle sfumature: ad esempio, nel motore InnoDB del database MySQL ci sono 2 registri: uno per la replicazione (binary log) e l'altro per mantenere l'ACID (undo/red log), mentre in PostgreSQL c'è un solo registro che svolge entrambe le funzioni (write ahead log = WAL). Tuttavia, quanto sopra rappresenta propriamente il concetto generale, che consente di non considerare tali sfumature.

Replicazione sincrona (sync)

Aggiungiamo all'algoritmo di commit della transazione la logica per replicare le modifiche ricevute:

  1. Registrazione della transazione nel registro del database.
  2. Applicazione della transazione nel motore del database.
  3. Invio dei dati a tutte le repliche.
  4. Ricezione della conferma da tutte le repliche riguardo l'esecuzione della transazione.
  5. Restituzione della conferma al cliente sull'applicazione riuscita della transazione.

Con questo approccio otteniamo una serie di svantaggi:

  • il cliente attende l'applicazione delle modifiche su tutte le repliche.
  • con l'aumento del numero di nodi nel cluster diminuiamo la probabilità che l'operazione di scrittura vada a buon fine.

Se per il primo punto è tutto più o meno chiaro, le ragioni del secondo punto meritano una spiegazione. Se nella replicazione sincrona non riceviamo risposta da almeno un nodo, annulliamo la transazione. Così, aumentando il numero di nodi nel cluster, aumentate la probabilità che l'operazione di scrittura fallisca.

Possiamo attendere conferma da solo una certa percentuale di nodi, ad esempio, dal 51% (quorum)? Sì, possiamo, tuttavia nella versione classica è richiesta la conferma da tutti i nodi, poiché è così che possiamo garantire la piena consistenza dei dati nel cluster, che è un indubbio vantaggio di questo tipo di replicazione.

Replicazione asincrona (async)

Modifichiamo l'algoritmo precedente. I dati alle repliche verranno inviati "prima o poi", e "prima o poi" le modifiche saranno applicate sulle repliche:

  1. Registrazione della transazione nel registro del database.
  2. Applicazione della transazione nel motore del database.
  3. Restituzione della conferma al cliente sull'applicazione riuscita della transazione.
  4. Invio dei dati alle repliche e applicazione delle modifiche da parte loro.

Questo approccio porta a un cluster che funziona rapidamente, poiché non teniamo il cliente in attesa finché i dati arrivano alle repliche e devono anche essere confermati.

Ma la condizione di invio dei dati alle repliche "prima o poi" può portare alla perdita di una transazione, e in particolare alla perdita di una transazione confermata all'utente, poiché se i dati non sono stati replicati in tempo, la conferma al cliente sull'esito positivo dell'operazione è stata inviata, mentre nel nodo che ha ricevuto le modifiche, l'HDD è andato in crash, perdiamo la transazione, il che può portare a conseguenze molto spiacevoli.

Replicazione semisincrona (semisync)

Finalmente siamo arrivati alla replica semisincrona. Questo tipo di replica non è molto conosciuto e non è molto diffuso, ma presenta un notevole interesse, poiché può combinare i vantaggi sia della replica sincronizzata che di quella asincrona.

Proviamo a unire i 2 approcci precedenti. Non terremo a lungo il cliente, ma richiederemo che i dati vengano replicati:

  1. Registrazione della transazione nel registro del database.
  2. Applicazione della transazione nel motore del database.
  3. Invio dei dati alle repliche.
  4. Ricezione della conferma dalla replica sulla ricezione delle modifiche (esse saranno applicate "quando sarà possibile").
  5. Restituzione della conferma al cliente sull'applicazione riuscita della transazione.

Si noti che con questo algoritmo la perdita di transazione si verifica solo in caso di arresto sia del nodo che riceve le modifiche sia del nodo-replica. La probabilità di un guasto di questo tipo è considerata bassa, e questi rischi sono accettati.

Ma con questo approccio è possibile il rischio di letture fantasma. Immaginiamo il seguente scenario: al passo 4 non abbiamo ricevuto conferma da nessuna replica. Dobbiamo annullare questa transazione e non restituire alcuna conferma al cliente. Poiché i dati sono stati applicati al passo 2, tra la fine del passo 2 e l'annullamento della transazione si crea un intervallo di tempo in cui transazioni parallele possono vedere quelle modifiche che non dovrebbero esserci nel database.

Replica semisincera senza perdita

Se ci pensiamo un attimo, basta solo scambiare i passi dell'algoritmo per risolvere il problema delle letture fantasma in questo scenario:

  1. Registrazione della transazione nel registro del database.
  2. Invio dei dati della replica.
  3. Ricezione della conferma dalla replica sulla ricezione delle modifiche (esse saranno applicate "quando sarà possibile").
  4. Applicazione della transazione nel motore del database.
  5. Restituzione della conferma al cliente sull'applicazione riuscita della transazione.

Ora confermiamo le modifiche solo se sono state replicate.

Conclusione

Come sempre, non esistono soluzioni ideali, ma piuttosto un insieme di soluzioni, ognuna delle quali ha i propri vantaggi e svantaggi e si adatta a diverse classi di problemi. Questo è altrettanto vero per la scelta del meccanismo di sincronizzazione dei dati in un database replicato. L'insieme dei vantaggi che offre la replica semisincrona è abbastanza solido e interessante da essere considerato degno di attenzione, nonostante la sua scarsa diffusione.

Questo è tutto. Ci vediamo a corso!

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster