banner

Notizia

Mar 07, 2023

Creazione e distribuzione di MySQL Raft su Meta

Noi di Meta gestiamo una delle più grandi implementazioni di MySQL al mondo. La distribuzione alimenta il grafico sociale insieme a molti altri servizi, come messaggistica, annunci e feed. Negli ultimi anni abbiamo implementato MySQL Raft, un motore di consenso Raft integrato con MySQL per creare una macchina a stati replicata. Abbiamo migrato gran parte della nostra distribuzione su MySQL Raft e prevediamo di sostituire completamente gli attuali database semisincroni MySQL con esso. Il progetto ha apportato vantaggi significativi all'implementazione MySQL presso Meta, tra cui maggiore affidabilità, sicurezza dimostrabile, miglioramenti significativi nei tempi di failover e semplicità operativa, il tutto con prestazioni di scrittura uguali o comparabili.

Per consentire elevata disponibilità, tolleranza agli errori e scalabilità delle letture, il datastore MySQL di Meta è un'implementazione con partizionamento massiccio e replica geografica con milioni di frammenti che contengono petabyte di dati. L'implementazione include migliaia di macchine in esecuzione in diverse regioni e data center in più continenti.

In precedenza, la nostra soluzione di replica utilizzava il protocollo di replica semisincrona (semisync) MySQL. Questo era un protocollo di solo percorso dati. Il primario MySQL utilizzerebbe la replica semisincrona su due repliche di solo log (logtailer) all'interno dell'area primaria ma all'esterno del dominio di errore del primario. Questi due logtailer agirebbero come ACKer semisincrono (un ACK è un riconoscimento al primario che la transazione è stata scritta localmente). Ciò consentirebbe al percorso dati di avere commit a latenza molto bassa (inferiore al millisecondo) e fornirebbe elevata disponibilità/durabilità per le scritture. Per una distribuzione più ampia in altre regioni è stata utilizzata la replica asincrona regolare da primario a replica di MySQL.

Le operazioni del piano di controllo (ad esempio, promozioni, failover e cambio di appartenenza) sarebbero responsabilità di un insieme di demoni Python (d'ora in poi chiamati automazione). L'automazione effettuerebbe l'orchestrazione necessaria per promuovere un nuovo server MySQL in una posizione di failover come primario. L'automazione indicherebbe inoltre la replica primaria precedente e le restanti repliche dalla nuova primaria. Le operazioni di modifica dell'appartenenza verrebbero orchestrate da un altro elemento di automazione chiamato MySQL pool scanner (MPS). Per aggiungere un nuovo membro, MPS indirizzerà la nuova replica al primario e la aggiungerà all'archivio di individuazione dei servizi. Un failover sarebbe un'operazione più complessa in cui i thread di coda dei logtailer (ACKer semisincroni) verrebbero chiusi per recintare il precedente primario morto.

In passato, per garantire la sicurezza ed evitare la perdita di dati durante le complesse operazioni di promozione e failover, diversi daemon e script di automazione utilizzavano blocchi, passaggi di orchestrazione, un meccanismo di fencing e SMC, un sistema di rilevamento dei servizi. Era una configurazione distribuita ed era difficile realizzarla in modo atomico. L'automazione è diventata più complessa e più difficile da mantenere nel tempo poiché è necessario riparare sempre più casi limite.

Abbiamo deciso di adottare un approccio completamente diverso. Abbiamo migliorato MySQL e lo abbiamo reso un vero sistema distribuito. Rendendoci conto che le operazioni del piano di controllo, come le promozioni e le modifiche all'appartenenza, erano la causa scatenante della maggior parte dei problemi, volevamo che le operazioni del piano di controllo e del piano dati facessero parte dello stesso registro replicato. Per questo abbiamo utilizzato il noto protocollo di consenso Raft. Ciò significava anche che la fonte della verità sull'appartenenza e sulla leadership si spostava all'interno del server (mysqld). Questo è stato il contributo più importante apportato dall'introduzione di Raft perché ha consentito la correttezza dimostrabile (proprietà di sicurezza) delle promozioni e dei cambiamenti di abbonamento nel server MySQL.

La nostra implementazione di Raft for MySQL è basata su Apache Kudu. Lo abbiamo migliorato in modo significativo per le esigenze di MySQL e della nostra implementazione. Abbiamo pubblicato questo fork come progetto open source, kuduraft.

Alcune delle funzionalità chiave che abbiamo aggiunto a kuduraft sono:

Abbiamo anche dovuto apportare modifiche relativamente importanti alla replica MySQL per interfacciarci con Raft. Per questo, abbiamo creato un nuovo plugin MySQL closed source chiamato MyRaft. MySQL si interfacciava con MyRaft tramite le API del plugin (API simili erano state utilizzate anche per la semisincronizzazione), mentre abbiamo creato un'API separata per MyRaft per interfacciarsi nuovamente con il server MySQL (callback).

CONDIVIDERE