RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster

L'affidabilità e l'alta disponibilità sono temi vasti, quindi dedicheremo articoli separati a RabbitMQ e Kafka. Questo articolo è su RabbitMQ, mentre il prossimo sarà su Kafka, in confronto a RabbitMQ. L'articolo è lungo, quindi sistemati comodamente.

Esaminiamo le strategie di tolleranza ai guasti, coerenza e alta disponibilità (HA), oltre ai compromessi che si devono affrontare in ciascuna strategia. RabbitMQ può funzionare su un cluster di nodi, classificandosi quindi come sistema distribuito. Quando si parla di sistemi distribuiti, parliamo spesso di coerenza e disponibilità.

Questi concetti descrivono come il sistema si comporta in caso di guasto. Guasti nelle connessioni di rete, guasti del server, guasti del disco rigido, temporanea indisponibilità del server a causa di garbage collection, perdita di pacchetti o rallentamenti delle connessioni di rete. Tutto ciò può portare a perdita di dati o conflitti. Risulta praticamente impossibile avere un sistema che sia completamente coerente (senza perdita di dati, senza incongruenze nei dati) e disponibile (che accetta operazioni di lettura e scrittura) per tutte le possibili situazioni di guasto.

Vedremo che la coerenza e la disponibilità si trovano agli opposti estremi dello spettro, e dovrai scegliere verso quale ottimizzare. La buona notizia è che con RabbitMQ questa scelta è possibile. Hai dei veri e propri "pomelli da nerd" per spostare l'equilibrio verso una maggiore coerenza o una maggiore disponibilità.

Presteremo particolare attenzione a quali configurazioni possono portare alla perdita di dati a causa delle conferme di registrazione. Esiste una catena di responsabilità tra publisher, broker e consumatori. Dopo che un messaggio è stato inviato al broker, spetta a lui non perdere il messaggio. Quando il broker conferma al publisher di aver ricevuto il messaggio, ci aspettiamo che non venga perso. Ma vedremo che questo può effettivamente accadere a seconda della configurazione del tuo broker e dell'editore.

Primitivi di resilienza di un nodo

Code resilienti/routing

In RabbitMQ ci sono due tipi di code: durevoli (durable) e non durevoli (non-durable). Tutte le code vengono salvate nel database Mnesia. Le code durevoli vengono ripristinate all'avvio del nodo e, in questo modo, sopravvivono a riavvii, crash di sistema o guasti del server (fintanto che i dati vengono salvati). Questo significa che finché dichiari la routing (exchange) e la coda come durevoli, l'infrastruttura di code/routing tornerà operativa.

Le code non durevoli e la routing vengono eliminate al riavvio del nodo.

Messaggi durevoli

Il fatto che una coda sia durevole non implica che tutti i suoi messaggi sopravvivano al riavvio del nodo. Saranno ripristinati solo i messaggi impostati dal publisher come durevoli (persistent). I messaggi durevoli creano effettivamente un carico aggiuntivo sul broker, ma se la perdita di un messaggio è inaccettabile, non c'è altra scelta.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 1. Matrice di durevolezza

Clusterizzazione con mirroring della coda

Per sopravvivere alla perdita di un broker, abbiamo bisogno di ridondanza. Possiamo raggruppare più nodi RabbitMQ in un cluster e poi aggiungere ulteriore ridondanza replicando le code tra più nodi. In questo modo, se un nodo va giù, non perdiamo dati e rimaniamo accessibili.

Mirroring della coda:

  • una coda principale (master), che riceve tutti i comandi di scrittura e lettura
  • uno o più mirror, che ricevono tutti i messaggi e i metadati dalla coda principale. Questi mirror non esistono per scalabilità, ma esclusivamente per ridondanza.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 2. Mirroring della coda

Il mirroring viene impostato con la politica corrispondente. Qui puoi scegliere il fattore di replicazione e persino i nodi su cui deve essere collocata la coda. Esempi:

  • ha-mode: all
  • ha-mode: exactly, ha-params: 2 (un master e un mirror)
  • ha-mode: nodes, ha-params: rabbit@node1, rabbit@node2

Conferma al publisher

Per ottenere una registrazione coerente sono necessarie conferme al publisher (Publisher Confirms). Senza di esse, si corre il rischio di perdere messaggi. La conferma viene inviata al publisher dopo che il messaggio è stato registrato su disco. RabbitMQ scrive i messaggi su disco non al momento della ricezione, ma con periodicità, nell'ordine di alcune centinaia di millisecondi. Quando la coda è speculata, la conferma viene inviata solo dopo che tutte le repliche hanno anche registrato la loro copia del messaggio su disco. Questo significa che l'uso delle conferme aggiunge un ritardo, ma se la sicurezza dei dati è importante, sono necessarie.

Coda resiliente

Quando il broker termina o si arresta, tutte le code maître su questo nodo si disconnettono insieme a lui. Il cluster poi seleziona la replica più vecchia di ciascun maître e la promuove a nuovo maître.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 3. Diverse code speculari e le loro politiche

Il broker 3 si arresta. Si noti che la replica della Coda C sul Broker 2 viene promossa a maître. Si noti anche che è stata creata una nuova replica per la Coda C sul Broker 1. RabbitMQ cerca sempre di mantenere il coefficiente di replica indicato nelle vostre politiche.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 4. Il broker 3 si disconnette, causando il guasto della coda C

Si arresta il successivo Broker 1! Ci rimane solo un broker. La replica della Coda B viene promossa a maître.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 5

Abbiamo ripristinato il Broker 1. Indipendentemente da quanto bene i dati abbiano sopportato la perdita e il ripristino del broker, tutti i messaggi speculati della coda vengono scartati al riavvio. È importante notare questo, poiché avrà delle conseguenze. Presto esamineremo queste conseguenze. Pertanto, il Broker 1 è di nuovo un membro del cluster, e il cluster cerca di rispettare le politiche e quindi crea repliche sul Broker 1.

In questo caso, la perdita del Broker 1 è stata totale, così come quella dei dati, quindi la Coda B non speculata è stata completamente persa.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 6. Il Broker 1 torna in funzione

Il broker 3 è tornato operativo, quindi le code A e B ricevono indietro gli specchi creati su di esso per soddisfare i loro politici HA. Ma ora tutte le code principali sono su un nodo! Non è ideale, è meglio una distribuzione uniforme tra i nodi. Sfortunatamente, qui non ci sono particolari opzioni per il riequilibrio dei master. Torneremo su questo problema più tardi, poiché per ora dobbiamo considerare la sincronizzazione della coda.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 7. Il broker 3 torna operativo. Tutte le code principali sono su un nodo!

Quindi, ora dovreste avere un'idea di come gli specchi forniscano ridondanza e tolleranza ai guasti. Questo garantisce accessibilità in caso di fallimento di un nodo e protegge dalla perdita di dati. Ma non abbiamo ancora finito, perché in realtà è molto più complicato.

Sincronizzazione

Quando si crea un nuovo specchio, tutti i nuovi messaggi verranno sempre replicati su questo specchio e su qualsiasi altro. Per quanto riguarda i dati esistenti nella coda principale, possiamo replicarli nel nuovo specchio, che diventa una copia completa del master. Possiamo anche decidere di non replicare i messaggi esistenti e permettere alla coda principale e al nuovo specchio di allinearsi nel tempo, con i nuovi messaggi che arrivano alla coda e i messaggi esistenti che vengono rimossi dalla testa della coda principale.

Tale sincronizzazione avviene automaticamente o manualmente e viene gestita tramite la politica delle code. Consideriamo un esempio.

Abbiamo due code mirror. La coda A è sincronizzata automaticamente, mentre la coda B è sincronizzata manualmente. Entrambe le code contengono dieci messaggi.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 8. Due code con diversi modi di sincronizzazione

Ora stiamo perdendo il Broker 3.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 9. Il Broker 3 è caduto

Il broker 3 torna operativo. Il cluster crea uno specchio per ogni coda su un nuovo nodo e sincronizza automaticamente la nuova Coda A con il master. Tuttavia, lo specchio della nuova Coda B rimane vuoto. Ciò significa che abbiamo una piena ridondanza della Coda A e solo uno specchio per i messaggi esistenti della Coda B.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 10. Il nuovo specchio della Coda A riceve tutti i messaggi esistenti, mentre il nuovo specchio della Coda B non riceve nulla.

In entrambe le code arrivano ancora dieci messaggi. Poi il Broker 2 va in crash e la Coda A torna allo specchio più vecchio, che si trova sul Broker 1. In caso di guasto non si verificano perdite di dati. Nella Coda B ci sono venti messaggi nel master e solo dieci nello specchio, poiché questa coda non ha mai replicato i primi dieci messaggi.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 11. La Coda A torna sul Broker 1 senza perdere messaggi

In entrambe le code arrivano ancora dieci messaggi. Ora si arresta il Broker 1. La Coda A si commuta senza problemi sullo specchio senza perdita di messaggi. Tuttavia, la Coda B presenta dei problemi. A questo punto possiamo ottimizzare o la disponibilità o la coerenza.

Se vogliamo ottimizzare la disponibilità, allora la politica ha-promote-on-failure dovrebbe essere impostata su always. Questo valore è predefinito, quindi si può semplicemente non specificare affatto la politica. In tal caso, di fatto, consentiamo guasti negli specchi non sincronizzati. Ciò porterà a perdite di messaggi, ma la coda rimane disponibile per la lettura e la scrittura.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 12. La Coda A torna sul Broker 3 senza perdita di messaggi. La Coda B torna sul Broker 3 con la perdita di dieci messaggi

Possiamo anche impostare ha-promote-on-failure a valore when-synced. In questo caso, invece di tornare allo specchio, la coda aspetterà finché il Broker 1 con i suoi dati non torni operativo. Dopo il suo ritorno, la coda principale si trova di nuovo sul Broker 1 senza perdita di dati. La disponibilità viene sacrificata a favore della sicurezza dei dati. Ma questo è un modo rischioso, che potrebbe portare anche a una perdita totale di dati, cosa che discuteremo a breve.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 13. La Coda B rimane non disponibile dopo la perdita del Broker 1

Puoi chiederti: "Forse è meglio non usare mai la sincronizzazione automatica?". La risposta è che la sincronizzazione è un'operazione bloccante. Durante la sincronizzazione, la coda principale non può eseguire alcuna operazione di lettura o scrittura!

Facciamo un esempio. Ora abbiamo code molto grandi. Come possono crescere a tale dimensione? Per varie ragioni:

  • Le code non vengono utilizzate attivamente
  • Queste sono code ad alta velocità, e proprio ora i consumatori stanno lavorando lentamente
  • Queste sono code ad alta velocità, si è verificato un guasto e i consumatori stanno recuperando

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 14. Due grandi code con diversi regimi di sincronizzazione

Ora il Broker 3 cade.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 15. Il Broker 3 cade, lasciando un master e uno specchio in ciascuna coda

Il Broker 3 ritorna in funzione e vengono creati nuovi specchi. La Coda Principale A inizia a replicare i messaggi esistenti su un nuovo specchio e durante questo tempo la Coda non è disponibile. La replicazione dei dati richiede due ore, il che porta a due ore di inattività per questa Coda!

Tuttavia, la Coda B rimane disponibile per tutto il periodo. Ha sacrificato un po' di ridondanza per garantire la disponibilità.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 16. La coda rimane non disponibile durante la sincronizzazione

Dopo due ore, anche la Coda A diventa disponibile e può ricominciare a ricevere operazioni di lettura e scrittura.

Aggiornamenti

Questo comportamento bloccante durante la sincronizzazione rende difficile l'aggiornamento dei cluster con code molto grandi. Ad un certo punto, il nodo con il master deve essere riavviato, il che significa passare a uno specchio o disabilitare la coda durante l'aggiornamento del server. Se scegliamo di passare, perderemo i messaggi se gli specchi non sono sincronizzati. Di default, durante la disattivazione del broker, non si passa a uno specchio non sincronizzato. Questo significa che non appena il broker ritorna, non perdiamo messaggi, l'unico danno è stato l'inattività della coda. Le regole di comportamento per la disattivazione del broker sono definite dalla politica ha-promote-on-shutdown. Puoi impostare uno dei due valori:

  • always= attivare il passaggio a specchi non sincronizzati
  • when-synced= passaggio solo a specchi sincronizzati, altrimenti la coda diventa non disponibile per lettura e scrittura. La coda ritorna in funzione non appena il broker ritorna

In ogni caso, con grandi code bisogna scegliere tra perdita di dati e non disponibilità.

Quando la disponibilità aumenta la sicurezza dei dati

Prima di prendere una decisione, è necessario considerare un'altra complicazione. Anche se la sincronizzazione automatica è migliore per la ridondanza, come influisce sulla sicurezza dei dati? Certo, grazie a una migliore ridondanza RabbitMQ ha una minore probabilità di perdere messaggi esistenti, ma che dire dei nuovi messaggi dai publisher?

Qui bisogna considerare quanto segue:

  • Il publisher può semplicemente restituire un errore e il servizio superiore o l'utente possono riprovare in seguito?
  • Il publisher può salvare il messaggio localmente o nel database per riprovare più tardi?

Se il publisher può solo scartare il messaggio, in realtà, il miglioramento della disponibilità aumenta anche la sicurezza dei dati.

Di conseguenza, è necessario trovare un equilibrio e la soluzione dipende dalla situazione specifica.

Problemi con ha-promote-on-failure=when-synced

Idea ha-promote-on-failure= when-synced consiste nell'impedire il passaggio a uno specchio non sincronizzato, evitando così la perdita di dati. La coda rimane non accessibile per la lettura o la scrittura. Invece, cerchiamo di recuperare il broker guasto con dati intatti affinché possa riprendere a funzionare come master senza perdita di dati.

Ma (ed è un grande ma) se il broker ha perso i suoi dati, abbiamo un grosso problema: la coda è persa! Tutti i dati sono svaniti! Anche se hai specchi che sostanzialmente stanno raggiungendo la coda principale, questi specchi vengono anch'essi scartati.

Per riaggiungere un nodo con lo stesso nome, diciamo al cluster di dimenticare il nodo perduto (comando rabbitmqctl forget_cluster_node) e avviare un nuovo broker con lo stesso nome host. Finché il cluster ricorda il nodo perduto, ricorda la vecchia coda e gli specchi non sincronizzati. Quando si dice al cluster di dimenticare il nodo perduto, anche questa coda viene dimenticata. Ora deve essere nuovamente dichiarata. Abbiamo perso tutti i dati, anche se avevamo specchi con un insieme parziale di dati. Sarebbe stato meglio passare a uno specchio non sincronizzato!

Pertanto, la sincronizzazione manuale (e la mancata esecuzione della sincronizzazione) insieme a ha-promote-on-failure=when-synced, a mio parere, è piuttosto rischiosa. I documenti affermano che tale opzione esiste per la sicurezza dei dati, ma si tratta di una lama a doppio taglio.

Ribilanciamento dei master

Come promesso, torniamo al problema della concentrazione di tutti i master su uno o più nodi. Questo può accadere anche a causa di un aggiornamento "rolling" del cluster. In un cluster con tre nodi, tutte le code principali si concentreranno su uno o due nodi.

Il ribilanciamento dei master può rivelarsi problematico per due motivi:

  • Non ci sono buoni strumenti per eseguire il ribilanciamento
  • Sincronizzazione delle code

Per la riconfigurazione c'è un terzo plugin, che non è ufficialmente supportato. Riguardo ai plugin di terzi nel manuale di RabbitMQ si dice: «Il plugin fornisce alcuni strumenti aggiuntivi per la configurazione e il reporting, ma non è supportato e non è stato verificato dal team di RabbitMQ. Utilizzalo a tuo rischio e pericolo».

C'è un altro trucco per spostare la coda principale tramite politiche HA. Nel manuale si menziona script per questo. Funziona come segue:

  • Rimuove tutti i mirror utilizzando una politica temporanea con priorità superiore rispetto alla politica HA esistente.
  • Modifica la politica HA temporanea per utilizzare la modalità «nodi» specificando il nodo su cui si desidera spostare la coda principale.
  • Sincronizza la coda per forzare la migrazione.
  • Dopo aver completato la migrazione, rimuove la politica temporanea. L'originale politica HA entra in vigore e viene creato il numero necessario di mirror.

Lo svantaggio è che questo approccio potrebbe non funzionare se hai code di grandi dimensioni o requisiti rigorosi di ridondanza.

Ora vediamo come i cluster RabbitMQ gestiscono le partizioni di rete.

Violazione della coerenza

I nodi di un sistema distribuito sono collegati da legami di rete, e i legami di rete possono e saranno disconnessi. La frequenza delle disconnessioni dipende dall'infrastruttura locale o dall'affidabilità del cloud scelto. In ogni caso, i sistemi distribuiti devono essere in grado di affrontarle. Una volta di più, ci troviamo di fronte a una scelta tra disponibilità e coerenza, e di nuovo la buona notizia è che RabbitMQ offre entrambe le opzioni (ovviamente non simultaneamente).

Con RabbitMQ abbiamo due opzioni principali:

  • Consentire la divisione logica (split-brain). Questo garantisce la disponibilità, ma può provocare perdita di dati.
  • Vietare la divisione logica. Questo potrebbe portare a una perdita di disponibilità a breve termine a seconda di come i client si connettono al cluster. Potrebbe anche portare a un'impossibilità totale nel cluster di due nodi.

Ma cos'è la divisione logica? È quando un cluster si divide in due a causa della perdita di legami di rete. Su ciascun lato, i mirror vengono elevati a master, quindi alla fine ogni coda ha più master.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 17. La coda principale e due specchi, ciascuno su un nodo separato. Poi si verifica un guasto di rete e uno specchio si distacca. Il nodo separato vede che gli altri due si sono disconnessi e promuove i propri specchi a master. Ora abbiamo due code principali, entrambe consentono scrittura e lettura.

Se i publisher inviano dati ad entrambi i master, avremo due copie divergenti della coda.

Diverse modalità di RabbitMQ garantiscono o disponibilità, o coerenza.

Modalità Ignore (predefinita)

Questa modalità garantisce disponibilità. Dopo la perdita di connettività si verifica una separazione logica. Dopo il ripristino della connettività, l'amministratore deve decidere quale sezione privilegiare. La parte perdente verrà riavviata e tutti i dati accumulati su quel lato andranno persi.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 18. Tre publisher sono collegati a tre broker. Internamente, il cluster dirige tutte le richieste alla coda principale sul Broker 2.

Ora perdiamo il Broker 3. Vede che gli altri broker si sono disconnessi e promuove il suo specchio a master. Si verifica quindi una separazione logica.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 19. Separazione logica (split-brain). Le scritture vanno in due code principali, e due copie divergono.

La connettività viene ripristinata, ma la separazione logica rimane. L'amministratore deve scegliere manualmente la parte perdente. Nel caso seguente, l'amministratore riavvia il Broker 3. Vanno persi tutti i messaggi che non è riuscito a inviare.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 20. L'amministratore disabilita il Broker 3.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 21. L'amministratore avvia il Broker 3 e si unisce al cluster, perdendo tutti i messaggi che erano rimasti.

Durante la perdita di connettività e dopo il suo ripristino, il cluster e questa coda erano disponibili per lettura e scrittura.

Modalità Autoheal

Funziona in modo simile alla modalità Ignore, tranne per il fatto che il cluster stesso sceglie automaticamente la parte perdente dopo la separazione e il ripristino della connettività. La parte perdente torna al cluster vuota e la coda perde tutti i messaggi inviati solo a quella parte.

Modalità Pause Minority

Se non vogliamo consentire una divisione logica, l'unica opzione è rinunciare alla lettura e alla scrittura sul lato inferiore dopo la partizione del cluster. Quando il broker vede di trovarsi sul lato inferiore, sospende il funzionamento, chiudendo tutte le connessioni esistenti e rifiutando qualsiasi nuova. Una volta al secondo controlla il ripristino della connettività. Non appena la connettività è ripristinata, riprende il funzionamento e si riunisce al cluster.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 22. Tre publisherr sono collegati a tre broker. Internamente, il cluster dirige tutte le richieste alla coda principale sul Broker 2.

Poi i Broker 1 e 2 si separano dal Broker 3. Invece di elevare il suo mirror a master, il Broker 3 sospende il funzionamento e diventa non disponibile.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 23. Il Broker 3 sospende il funzionamento, disconnette tutti i clienti e rifiuta le richieste di connessione.

Non appena la connettività è ripristinata, torna al cluster.

Diamo un'occhiata a un altro esempio, dove la coda principale si trova sul Broker 3.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 24. La coda principale sul Broker 3.

Si verifica quindi la stessa perdita di connettività. Il Broker 3 va in pausa, poiché si trova sul lato inferiore. Dall'altra parte, i nodi vedono che il Broker 3 è andato offline, quindi il mirror più vecchio dai Broker 1 e 2 viene elevato a master.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 25. Transizione al Broker 2 in assenza del Broker 3.

Quando la connettività è ripristinata, il Broker 3 si unirà al cluster.

RabbitMQ contro Kafka: resilienza e alta disponibilità nei cluster
Fig. 26. Il cluster è tornato a operare normalmente.

È importante capire che otteniamo coerenza, ma possiamo anche ottenere disponibilità, se riusciamo a reindirizzare i clienti sulla parte più grande della partizione. Per la maggior parte delle situazioni, personalmente sceglierei la modalità Pause Minority, ma in realtà dipende dal caso specifico.

Per garantire la disponibilità è fondamentale assicurarsi che i clienti si connettano con successo al nodo. Consideriamo le nostre opzioni.

Garantire la connettività dei clienti

Abbiamo diverse opzioni su come reindirizzare i clienti alla parte principale del cluster o ai nodi operativi dopo la perdita di connettività (dopo il fallimento di un nodo). Iniziamo a ricordare che una specifica coda è collocata su un nodo particolare, ma il routing e le politiche vengono replicate su tutti i nodi. I clienti possono connettersi a qualsiasi nodo e il routing interno li guiderà dove necessario. Ma quando un nodo è sospeso, rifiuta le connessioni, quindi i clienti devono connettersi a un altro nodo. Se un nodo fallisce, ha veramente poche possibilità di intervenire.

Le nostre opzioni:

  • L'accesso al cluster avviene tramite un bilanciatore di carico che semplicemente itera ciclicamente sui nodi e i clienti effettuano tentativi di connessione fino al completamento con successo. Se un nodo non funziona o è sospeso, i tentativi di connessione a quel nodo falliranno, ma i successivi tentativi andranno verso altri server (in modalità ciclica). Questo è adatto per una perdita temporanea di connettività o per un server non funzionante che verrà rapidamente ripristinato.
  • Accesso al cluster tramite bilanciatore di carico e rimozione dei nodi sospesi/falliti dall'elenco non appena vengono rilevati. Se lo facciamo rapidamente e se i clienti sono in grado di ripetere i tentativi di connessione, otterremo una disponibilità continua.
  • Fornire a ogni cliente un elenco di tutti i nodi e il cliente, durante la connessione, sceglie casualmente uno di essi. Se durante il tentativo di connessione riceve un errore, passa al nodo successivo nell'elenco fino a connettersi.
  • Reindirizzare il traffico dal nodo non operativo/sospeso tramite DNS. Questo viene fatto utilizzando un basso TTL.

Conclusioni

La clusterizzazione di RabbitMQ ha i suoi vantaggi e svantaggi. Gli svantaggi più significativi sono:

  • quando ci si unisce al cluster, i nodi scartano i propri dati;
  • la sincronizzazione bloccante porta all'inaccessibilità della coda.

Tutte le decisioni difficili derivano da queste due caratteristiche dell'architettura. Se RabbitMQ potesse salvare i dati durante la riconnessione del cluster, la sincronizzazione sarebbe più veloce. Se fosse in grado di una sincronizzazione non bloccante, sarebbe migliore nel supportare grandi code. Risolvere questi due problemi migliorerebbe significativamente le caratteristiche di RabbitMQ come tecnologia di messaggistica resiliente e altamente disponibile. Non mi sentirei di raccomandare RabbitMQ con clustering nelle seguenti situazioni:

  • Rete inaffidabile.
  • Memoria inaffidabile.
  • Code molto grandi.

Per quanto riguarda le impostazioni per alta disponibilità, considera le seguenti:

  • ha-promote-on-failure=always
  • ha-sync-mode=manual
  • cluster_partition_handling=ignore (o autoheal)
  • messaggi resilienti
  • assicurati che i client si connettano a un nodo attivo quando un nodo fallisce

Per la coerenza (sicurezza dei dati), considera le seguenti impostazioni:

  • Publisher Confirms e Manual Acknowledgements dal lato del consumatore
  • ha-promote-on-failure=when-synced, se i publisher possono riprovare in seguito e se hai una memoria molto affidabile! Altrimenti imposta =always.
  • ha-sync-mode=automatic (ma per grandi code inattive potrebbe essere necessario il modo manuale; inoltre, considera se la mancanza di disponibilità porterà alla perdita di messaggi)
  • modalità Pause Minority
  • messaggi resilienti

Non abbiamo ancora considerato tutte le questioni di resilienza e alta disponibilità; ad esempio, come eseguire procedure amministrative in modo sicuro (come gli aggiornamenti graduali). È necessario parlare anche di federazione e del plugin Shovel.

Se ho trascurato qualcosa, ti prego di farmelo sapere.

Vedi anche il mio post, dove faccio un'analisi nel cluster RabbitMQ usando Docker e Blockade per testare alcuni scenari di perdita di messaggi descritti in questo articolo.

Articoli precedenti della serie:
№1 — habr.com/ru/company/itsumma/blog/416629
№2 — habr.com/ru/company/itsumma/blog/418389
№3 — habr.com/ru/company/itsumma/blog/437446

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