RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità

В ultimo articolo abbiamo esaminato il clustering RabbitMQ per la tolleranza agli errori e l'elevata disponibilità. Ora scaviamo in profondità in Apache Kafka.

Qui l'unità di replica è la partizione. Ogni argomento ha una o più sezioni. Ogni sezione ha un leader con o senza seguaci. Quando crei un argomento, specifichi il numero di partizioni e il coefficiente di replica. Il valore abituale è 3, che significa tre repliche: un leader e due seguaci.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 1. Quattro sezioni sono distribuite tra tre broker

Tutte le richieste di lettura e scrittura vanno al leader. I follower inviano periodicamente richieste al leader per ricevere gli ultimi messaggi. I consumatori non si rivolgono mai ai follower; questi ultimi esistono solo per ridondanza e tolleranza agli errori.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità

Errore della partizione

Quando un broker fallisce, spesso falliscono i leader di diverse sezioni. In ognuno di essi, un follower di un altro nodo diventa il leader. In realtà, non è sempre così, poiché influisce anche il fattore di sincronizzazione: se ci sono follower sincronizzati e, in caso contrario, se è consentito il passaggio a una replica non sincronizzata. Ma non complichiamo le cose per ora.

Il broker 3 lascia la rete e viene eletto un nuovo leader per la sezione 2 del broker 2.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 2. Il broker 3 muore e il suo seguace sul broker 2 viene eletto nuovo leader della partizione 2

Poi il broker 1 se ne va e anche la sezione 1 perde il suo leader, il cui ruolo passa al broker 2.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 3. È rimasto un broker. Tutti i leader lavorano su un broker con ridondanza zero

Quando il broker 1 torna online, aggiunge quattro follower, fornendo una certa ridondanza a ciascuna partizione. Ma tutti i leader sono rimasti comunque sul broker 2.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 4. I leader rimangono sul broker 2

Quando viene visualizzato il broker 3, torniamo a tre repliche per partizione. Ma tutti i leader sono ancora sul broker 2.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 5. Posizionamento sbilanciato dei leader dopo il ripristino dei broker 1 e 3

Kafka ha uno strumento per un migliore riequilibrio del leader rispetto a RabbitMQ. Lì dovevi utilizzare un plug-in o uno script di terze parti che modificava le policy per la migrazione del nodo master riducendo la ridondanza durante la migrazione. Inoltre, per code di grandi dimensioni dovevamo accettare l'indisponibilità durante la sincronizzazione.

Kafka ha il concetto di “repliche preferite” per il ruolo di leader. Quando vengono create le partizioni degli argomenti, Kafka tenta di distribuire i leader in modo uniforme tra i nodi e contrassegna i primi leader come preferiti. Nel corso del tempo, a causa di riavvii, guasti e interruzioni della connettività dei server, i leader potrebbero finire su altri nodi, come nel caso estremo descritto sopra.

Per risolvere questo problema, Kafka offre due opzioni:

  • Opzione auto.leader.rebalance.enable=true consente al nodo controller di riassegnare automaticamente i leader alle repliche preferite e quindi ripristinare una distribuzione uniforme.
  • L'amministratore può eseguire lo script kafka-preferred-replica-election.sh per la riassegnazione manuale.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 6. Repliche dopo il ribilanciamento

Questa era una versione semplificata del fallimento, ma la realtà è più complessa, anche se qui non c'è nulla di troppo complicato. Tutto si riduce alle repliche sincronizzate (Repliche In-Sync, ISR).

Repliche sincronizzate (ISR)

Un ISR è un insieme di repliche di una partizione considerata "sincronizzata" (in-sync). C'è un leader, ma potrebbero non esserci seguaci. Un follower è considerato sincronizzato se ha effettuato copie esatte di tutti i messaggi del leader prima della scadenza dell'intervallo replica.lag.time.max.ms.

Un follower viene rimosso dal set ISR se:

  • non ha effettuato una richiesta di selezione per l'intervallo replica.lag.time.max.ms (presunto morto)
  • non è riuscito ad aggiornare durante l'intervallo replica.lag.time.max.ms (considerato lento)

I follower effettuano richieste di campionamento nell'intervallo replica.fetch.wait.max.ms, che per impostazione predefinita è 500 ms.

Per spiegare chiaramente lo scopo dell’ISR, dobbiamo considerare le conferme del produttore e alcuni scenari di fallimento. I produttori possono scegliere quando il broker invia la conferma:

  • acks=0, la conferma non viene inviata
  • acks=1, la conferma viene inviata dopo che il leader ha scritto un messaggio sul suo log locale
  • acks=all, la conferma viene inviata dopo che tutte le repliche nell'ISR hanno scritto il messaggio nei log locali

Nella terminologia Kafka, se l'ISR ha salvato un messaggio, questo è “impegnato”. Acks=all è l'opzione più sicura, ma aggiunge anche ulteriore ritardo. Diamo un'occhiata a due esempi di fallimento e al modo in cui le diverse opzioni "acks" interagiscono con il concetto ISR.

Acks=1 e ISR

In questo esempio, vedremo che se il leader non attende che tutti i messaggi di tutti i follower vengano salvati, è possibile una perdita di dati se il leader fallisce. La navigazione verso un follower non sincronizzato può essere abilitata o disabilitata tramite l'impostazione leader.impuro.elezioni.abilita.

In questo esempio il produttore ha il valore acks=1. La sezione è distribuita su tutti e tre i broker. Il Broker 3 è indietro, si è sincronizzato con il leader otto secondi fa e ora è indietro di 7456 messaggi. Il broker 1 era solo un secondo indietro. Il nostro produttore invia un messaggio e riceve rapidamente una risposta, senza il sovraccarico di follower lenti o morti che il leader non sta aspettando.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 7. PVR con tre repliche

Il broker 2 fallisce e il produttore riceve un errore di connessione. Dopo che la leadership passa al broker 1, perdiamo 123 messaggi. Il follower del broker 1 faceva parte dell'ISR, ma non era completamente sincronizzato con il leader quando è caduto.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 8. I messaggi vengono persi in caso di arresto anomalo

In configurazione bootstrap.server Il produttore ha diversi broker elencati e può chiedere a un altro broker di diventare il nuovo leader della sezione. Quindi stabilisce una connessione al broker 1 e continua a inviare messaggi.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 9. L'invio dei messaggi riprende dopo una breve pausa

Broker 3 è ancora più indietro. Effettua richieste di recupero ma non può sincronizzarsi. Ciò potrebbe essere dovuto alla connessione di rete lenta tra i broker, a problemi di archiviazione, ecc. Viene rimosso dall'ISR. Ora l'ISR è costituito da una replica: il leader! Il produttore continua a inviare messaggi e ricevere conferme.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 10. Il follower sul broker 3 viene rimosso dall'ISR

Il broker 1 crolla e il ruolo di leadership passa al broker 3 con la perdita di 15286 messaggi! Il produttore riceve un messaggio di errore di connessione. Il passaggio a un leader al di fuori dell'ISR è stato possibile solo a causa dell'impostazione unclean.leader.election.enable=true. Se è installato in falso, la transizione non avverrebbe e tutte le richieste di lettura e scrittura verrebbero rifiutate. In questo caso aspettiamo che il broker 1 ritorni con i suoi dati intatti nella replica, che assumerà nuovamente la leadership.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 11. Il broker 1 cade. Quando si verifica un errore, un gran numero di messaggi viene perso

Il produttore stabilisce una connessione con l'ultimo broker e vede che ora è il leader della sezione. Inizia a inviare messaggi al broker 3.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 12. Dopo una breve pausa, i messaggi vengono nuovamente inviati alla sezione 0

Abbiamo visto che, a parte brevi interruzioni per stabilire nuove connessioni e cercare un nuovo leader, il produttore inviava costantemente messaggi. Questa configurazione garantisce la disponibilità a scapito della coerenza (sicurezza dei dati). Kafka perse migliaia di messaggi ma continuò ad accettare nuove scritture.

Acks=all e ISR

Ripetiamo ancora questo scenario, ma con acks=tutto. Broker 3 ha una latenza media di quattro secondi. Il produttore invia un messaggio con acks=tutto, e ora non riceve una risposta rapida. Il leader attende che il messaggio venga salvato da tutte le repliche nell'ISR.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 13. PVR con tre repliche. Uno è lento, con conseguenti ritardi nella registrazione

Dopo altri quattro secondi di ritardo, il broker 2 invia un messaggio di conferma. Tutte le repliche sono ora completamente aggiornate.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 14. Tutte le repliche salvano i messaggi e inviano un riconoscimento

Il broker 3 resta ora ancora più indietro e viene escluso dall'ISR. La latenza è notevolmente ridotta perché non sono rimaste repliche lente nell'ISR. Il broker 2 ora attende solo il broker 1 e ha un ritardo medio di 500 ms.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 15. La replica sul broker 3 viene rimossa dall'ISR

Quindi il broker 2 cade e la leadership passa al broker 1 senza perdita di messaggi.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 16. Il broker 2 cade

Il produttore trova un nuovo leader e inizia a inviargli messaggi. La latenza è ulteriormente ridotta poiché l'ISR ora è costituito da una replica! Quindi l'opzione acks=tutto non aggiunge ridondanza.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 17. La replica sul broker 1 prende il comando senza perdere messaggi

Quindi il broker 1 va in crash e il vantaggio va al broker 3 con una perdita di 14238 messaggi!

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 18. Il broker 1 muore e la transizione della leadership con un'impostazione non pulita provoca una vasta perdita di dati

Non è stato possibile installare l'opzione leader.impuro.elezioni.abilita nel significato vero. Per impostazione predefinita è uguale falso. Impostazioni acks=tutto с unclean.leader.election.enable=true fornisce l'accessibilità con una certa sicurezza aggiuntiva dei dati. Ma come puoi vedere, possiamo ancora perdere messaggi.

Ma cosa succede se vogliamo aumentare la sicurezza dei dati? Puoi mettere impuro.leader.election.enable = falso, ma questo non ci proteggerà necessariamente dalla perdita di dati. Se il leader si è comportato male e ha portato con sé i dati, i messaggi andranno comunque persi e la disponibilità verrà persa finché l'amministratore non ripristina la situazione.

È meglio assicurarsi che tutti i messaggi siano ridondanti e altrimenti eliminare la registrazione. Quindi, almeno dal punto di vista del broker, la perdita di dati è possibile solo in caso di due o più guasti simultanei.

Acks=all, min.insync.replicas e ISR

Con configurazione dell'argomento repliche.min.insinc Stiamo aumentando il livello di sicurezza dei dati. Esaminiamo nuovamente l'ultima parte dello scenario precedente, ma questa volta con min.insync.replicas=2.

Quindi il broker 2 ha un leader di replica e il follower sul broker 3 viene rimosso dall'ISR.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 19. ISR da due repliche

Il broker 2 cade e la leadership passa al broker 1 senza perdita di messaggi. Ma ora l'ISR è costituito da una sola replica. Questo non soddisfa il numero minimo per ricevere record e pertanto il broker risponde al tentativo di scrittura con un errore Non abbastanza repliche.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 20. Il numero di ISR ​​è inferiore di uno rispetto a quanto specificato in min.insync.replicas

Questa configurazione sacrifica la disponibilità a favore della coerenza. Prima di riconoscere un messaggio, ci assicuriamo che sia scritto su almeno due repliche. Ciò dà al produttore molta più fiducia. In questo caso, la perdita del messaggio è possibile solo se due repliche falliscono simultaneamente in un breve intervallo finché il messaggio non viene replicato su un ulteriore follower, il che è improbabile. Ma se sei super paranoico, puoi impostare il fattore di replica su 5 e repliche.min.insinc di 3. Qui tre broker devono cadere contemporaneamente per perdere il record! Naturalmente questa affidabilità si paga con una latenza aggiuntiva.

Quando l'accessibilità è necessaria per la sicurezza dei dati

Come in caso con RabbitMQ, a volte l'accessibilità è necessaria per la sicurezza dei dati. Ecco a cosa devi pensare:

  • L'editore può semplicemente restituire un errore e chiedere al servizio upstream o all'utente di riprovare più tardi?
  • L'editore può salvare il messaggio localmente o in un database per riprovare più tardi?

Se la risposta è no, l’ottimizzazione della disponibilità migliora la sicurezza dei dati. Perderai meno dati se scegli la disponibilità invece di non registrare. Tutto si riduce quindi alla ricerca di un equilibrio e la decisione dipende dalla situazione specifica.

Il significato di ISR

La suite ISR ti consente di scegliere l'equilibrio ottimale tra sicurezza dei dati e latenza. Ad esempio, garantire la disponibilità in caso di guasto della maggior parte delle repliche, riducendo al minimo l'impatto di repliche morte o lente in termini di latenza.

Scegliamo noi stessi il significato replica.lag.time.max.ms in base alle tue esigenze. In sostanza, questo parametro indica quanto ritardo siamo disposti ad accettare e quando acks=tutto. Il valore predefinito è dieci secondi. Se per te è troppo lungo, puoi ridurlo. Quindi la frequenza delle modifiche all'ISR aumenterà, poiché i follower verranno rimossi e aggiunti più spesso.

RabbitMQ è semplicemente un insieme di mirror che devono essere replicati. I mirror lenti introducono una latenza aggiuntiva e i mirror morti possono attendere finché i pacchetti che controllano la disponibilità di ciascun nodo (net tick) non rispondono. L'ISR è un modo interessante per evitare questi problemi di latenza. Ma rischiamo di perdere la ridondanza poiché l’ISR può solo ridursi al leader. Per evitare questo rischio, utilizzare l'impostazione repliche.min.insinc.

Garanzia di connessione del cliente

Nelle impostazioni bootstrap.server produttore e consumatore possono specificare più broker per connettere i clienti. L'idea è che quando un nodo non funziona, ne rimangono diversi di riserva con cui il client può aprire una connessione. Questi non sono necessariamente leader di sezione, ma semplicemente un trampolino di lancio per il caricamento iniziale. Il client può chiedere quale nodo ospita il leader della partizione di lettura/scrittura.

In RabbitMQ, i client possono connettersi a qualsiasi nodo e il routing interno invia la richiesta dove deve andare. Ciò significa che puoi installare un bilanciatore del carico davanti a RabbitMQ. Kafka richiede ai client di connettersi al nodo che ospita il leader della partizione corrispondente. In una situazione del genere, non è possibile installare un bilanciatore del carico. Elenco bootstrap.server È fondamentale che i client possano accedere e trovare i nodi corretti dopo un errore.

Architettura del consenso di Kafka

Finora non abbiamo considerato come il cluster viene a conoscenza della caduta del broker e come viene eletto un nuovo leader. Per capire come funziona Kafka con le partizioni di rete, è necessario prima comprendere l'architettura di consenso.

Ogni cluster Kafka viene distribuito insieme a un cluster Zookeeper, ovvero un servizio di consenso distribuito che consente al sistema di raggiungere il consenso su un determinato stato, dando priorità alla coerenza rispetto alla disponibilità. Per approvare le operazioni di lettura e scrittura è necessario il consenso della maggioranza dei nodi Zookeeper.

Zookeeper memorizza lo stato del cluster:

  • Elenco di argomenti, sezioni, configurazione, repliche leader attuali, repliche preferite.
  • Membri del cluster. Ogni broker esegue il ping del cluster Zookeeper. Se non riceve un ping entro un periodo di tempo specificato, Zookeeper registra il broker come non disponibile.
  • Selezione dei nodi principali e di riserva per il controller.

Il nodo controller è uno dei broker Kafka responsabile dell'elezione dei leader della replica. Zookeeper invia notifiche al controller sull'appartenenza al cluster e sulle modifiche agli argomenti e il controller deve agire in base a tali modifiche.

Ad esempio, prendiamo un nuovo argomento con dieci partizioni e un fattore di replica pari a 3. Il controllore deve eleggere un leader per ciascuna partizione, cercando di distribuire in modo ottimale i leader tra i broker.

Per ogni controller di sezione:

  • aggiorna le informazioni in Zookeeper su ISR e leader;
  • Invia un LeaderAndISRCommand a ciascun broker che ospita una replica di questa partizione, informando i broker sull'ISR e sul leader.

Quando un broker con un leader cade, Zookeeper invia una notifica al controllore ed elegge un nuovo leader. Anche in questo caso, il controller prima aggiorna Zookeeper e poi invia un comando a ciascun broker notificandolo del cambio di leadership.

Ogni leader è responsabile del reclutamento degli ISR. Impostazioni replica.lag.time.max.ms determina chi entrerà lì. Quando l'ISR cambia, il leader trasmette le nuove informazioni allo Zookeeper.

Zookeeper è sempre informato di eventuali cambiamenti in modo che, in caso di fallimento, la gestione passi senza problemi a un nuovo leader.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 21. Consenso di Kafka

Protocollo di replica

Comprendere i dettagli della replica aiuta a comprendere meglio i potenziali scenari di perdita di dati.

Query di campionamento, Log End Offset (LEO) e Highwater Mark (HW)

Abbiamo considerato che i follower inviano periodicamente richieste di recupero al leader. L'intervallo predefinito è 500 ms. Ciò differisce da RabbitMQ in quanto in RabbitMQ la replica non viene avviata dal mirror della coda ma dal master. Il master spinge le modifiche agli specchi.

Il leader e tutti i follower salvano l'etichetta Log End Offset (LEO) e Highwater (HW). Il contrassegno LEO memorizza l'offset dell'ultimo messaggio nella replica locale e l'HW conserva l'offset dell'ultimo commit. Ricorda che per lo stato di commit, il messaggio deve essere persistente su tutte le repliche ISR. Ciò significa che LEO è solitamente leggermente avanti rispetto a HW.

Quando il leader riceve un messaggio, lo archivia localmente. Il follower effettua una richiesta di recupero trasmettendo il suo LEO. Il leader quindi invia un batch di messaggi a partire da questo LEO e trasmette anche l'HW corrente. Quando il leader riceve l'informazione che tutte le repliche hanno memorizzato il messaggio all'offset specificato, sposta il contrassegno HW. Solo il leader può spostare l'HW, quindi tutti i follower conosceranno il valore corrente nelle risposte alla loro richiesta. Ciò significa che i follower potrebbero rimanere indietro rispetto al leader sia nel messaggio che nella conoscenza HW. I consumatori ricevono messaggi solo fino all'attuale HW.

Tieni presente che "persistente" significa scritto in memoria, non su disco. Per migliorare le prestazioni, Kafka si sincronizza sul disco a un intervallo specifico. Anche RabbitMQ ha un intervallo simile, ma invierà un riconoscimento all'editore solo dopo che il master e tutti i mirror avranno scritto il messaggio sul disco. Gli sviluppatori di Kafka, per motivi di prestazioni, hanno deciso di inviare un ack non appena il messaggio viene scritto in memoria. Kafka scommette che la ridondanza compensa il rischio di archiviare brevemente i messaggi riconosciuti solo in memoria.

Fallimento del leader

Quando un leader cade, Zookeeper avvisa il controllore e seleziona una nuova replica del leader. Il nuovo leader imposta un nuovo marchio HW in base al suo LEO. I follower ricevono quindi informazioni sul nuovo leader. A seconda della versione di Kafka, il follower sceglierà uno dei due scenari:

  1. Troncherà il log locale in un HW conosciuto e invierà una richiesta al nuovo leader per i messaggi dopo questo segno.
  2. Invierà una richiesta al leader per scoprire l'HW nel momento in cui è stato eletto leader, quindi troncherà il registro a questo offset. Inizierà quindi a effettuare richieste di recupero periodiche a partire da questo offset.

Un follower potrebbe dover troncare il registro per i seguenti motivi:

  • Quando un leader fallisce, il primo follower del set ISR registrato con Zookeeper vince le elezioni e diventa il leader. Tutti i follower su ISR, sebbene considerati “sincronizzati”, potrebbero non aver ricevuto copie di tutti i messaggi dall’ex leader. È del tutto possibile che il follower in primo piano non abbia la copia più aggiornata. Kafka assicura che non vi sia alcuna divergenza tra le repliche. Pertanto, per evitare discrepanze, ciascun follower deve troncare il proprio log al valore HW del nuovo leader al momento della sua elezione. Questo è un altro motivo per cui impostare acks=tutto così importante per la coerenza.
  • I messaggi vengono periodicamente scritti su disco. Se tutti i nodi del cluster falliscono contemporaneamente, sui dischi verranno archiviate repliche con offset diversi. È possibile che quando i broker torneranno online, il nuovo leader eletto sarà dietro ai suoi seguaci perché è stato salvato sul disco prima degli altri.

Riunione con il cluster

Quando si ricongiungono al cluster, le repliche fanno lo stesso di quando un leader fallisce: controllano la replica del leader e troncano il loro log al suo HW (al momento dell'elezione). In confronto, RabbitMQ tratta ugualmente i nodi riuniti come completamente nuovi. In entrambi i casi, il broker scarta qualsiasi stato esistente. Se viene utilizzata la sincronizzazione automatica, il master deve replicare assolutamente tutto il contenuto corrente sul nuovo mirror con il metodo "lascia che il mondo intero aspetti". Il master non accetta alcuna operazione di lettura o scrittura durante questa operazione. Questo approccio crea problemi in code di grandi dimensioni.

Kafka è un log distribuito e in generale memorizza più messaggi di una coda RabbitMQ, dove i dati vengono rimossi dalla coda dopo essere stati letti. Le code attive dovrebbero rimanere relativamente piccole. Ma Kafka è un registro con una propria politica di conservazione, che può impostare un periodo di giorni o settimane. L'approccio del blocco delle code e della sincronizzazione completa è assolutamente inaccettabile per un registro distribuito. Invece, i seguaci di Kafka troncano semplicemente il loro log all'HW del leader (al momento della sua elezione) se la loro copia è davanti al leader. Nel caso più probabile, quando il follower è indietro, inizia semplicemente a effettuare richieste di recupero a partire dal suo LEO attuale.

I follower nuovi o ricongiunti iniziano al di fuori dell'ISR e non partecipano ai commit. Lavorano semplicemente a fianco del gruppo, ricevendo messaggi il più velocemente possibile finché non raggiungono il leader ed entrano nell'ISR. Non c'è alcun vincolo e non c'è bisogno di buttare via tutti i tuoi dati.

Perdita di connettività

Kafka ha più componenti di RabbitMQ, quindi ha un insieme di comportamenti più complessi quando il cluster viene disconnesso. Ma Kafka è stato originariamente progettato per i cluster, quindi le soluzioni sono molto ben pensate.

Di seguito sono riportati diversi scenari di errore di connettività:

  • Scenario 1: Il seguace non vede il leader, ma vede comunque il Guardiano dello Zoo.
  • Scenario 2: Il leader non vede alcun seguito, ma vede comunque il Guardiano dello Zoo.
  • Scenario 3: Il seguace vede il leader, ma non vede il guardiano dello zoo.
  • Scenario 4: Il leader vede i seguaci, ma non vede il guardiano dello zoo.
  • Scenario 5: il follower è completamente separato sia dagli altri nodi Kafka che da Zookeeper.
  • Scenario 6: il leader è completamente separato sia dagli altri nodi Kafka che da Zookeeper.
  • Scenario 7: il nodo del controller Kafka non può vedere un altro nodo Kafka.
  • Scenario 8: il controller Kafka non vede Zookeeper.

Ogni scenario ha il proprio comportamento.

Scenario 1: il follower non vede il leader, ma vede comunque il guardiano dello zoo

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 22. Scenario 1: ISR di tre repliche

L'errore di connettività separa il broker 3 dai broker 1 e 2, ma non da Zookeeper. Broker 3 non può più inviare richieste di recupero. Dopo che il tempo è passato replica.lag.time.max.ms viene rimosso dall'ISR e non partecipa ai commit dei messaggi. Una volta ripristinata la connettività, riprenderà le richieste di recupero e si unirà all'ISR quando raggiungerà il leader. Zookeeper continuerà a ricevere ping e presumerà che il broker sia vivo e vegeto.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 23. Scenario 1: il broker viene rimosso dall'ISR se non viene ricevuta alcuna richiesta di recupero entro l'intervallo replica.lag.time.max.ms

Non c'è sospensione del cervello diviso o del nodo come in RabbitMQ. Invece, la ridondanza è ridotta.

Scenario 2: Il leader non vede nessun follower, ma vede comunque il Guardiano dello zoo

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 24. Scenario 2. Leader e due seguaci

Un'interruzione della connettività di rete separa il leader dai follower, ma il broker può ancora vedere Zookeeper. Come nel primo scenario, l'ISR si riduce, ma questa volta solo al leader poiché tutti i follower smettono di inviare richieste di recupero. Ancora una volta, non esiste una divisione logica. Si verifica invece una perdita di ridondanza per i nuovi messaggi fino al ripristino della connettività. Zookeeper continua a ricevere ping e ritiene che il broker sia vivo e vegeto.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 25. Scenario 2. L'ISR si è ridotto al solo leader

Scenario 3. Il seguace vede il leader, ma non vede il guardiano dello zoo

Il follower è separato dallo Zookeeper, ma non dall'intermediario con il leader. Di conseguenza, il follower continua a effettuare richieste di recupero ed essere membro dell'ISR. Zookeeper non riceve più ping e registra un crash del broker, ma poiché è solo un follower, non ci sono conseguenze dopo il ripristino.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 26. Scenario 3: Il follower continua a inviare richieste di recupero al leader

Scenario 4. Il leader vede i seguaci, ma non vede il guardiano dello zoo

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 27. Scenario 4. Leader e due seguaci

Il leader è separato dallo Zookeeper, ma non dagli intermediari con seguaci.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 28. Scenario 4: Leader isolato dal Guardiano dello zoo

Dopo un po' di tempo, Zookeeper registrerà un errore del broker e ne informerà il controllore. Sceglierà un nuovo leader tra i suoi seguaci. Tuttavia, il leader originale continuerà a pensare di essere il leader e continuerà ad accettare iscrizioni da acks=1. I follower non gli inviano più richieste di recupero, quindi li considererà morti e cercherà di ridurre l'ISR a se stesso. Ma poiché non ha una connessione con Zookeeper, non sarà in grado di farlo e a quel punto rifiuterà di accettare ulteriori voci.

Messaggi acks=tutto non riceverà un riconoscimento perché l'ISR attiva prima tutte le repliche e i messaggi non le raggiungono. Quando il leader originale tenta di rimuoverli dall'ISR, non sarà in grado di farlo e smetterà del tutto di accettare qualsiasi messaggio.

I clienti notano presto il cambio di leader e iniziano a inviare record al nuovo server. Una volta ripristinata la rete, il leader originale vede che non è più un leader e tronca il suo log al valore HW che aveva il nuovo leader al momento del fallimento per evitare la divergenza del log. Inizierà quindi a inviare richieste di recupero al nuovo leader. Tutti i record del leader originale che non vengono replicati nel nuovo leader verranno persi. Cioè, i messaggi che non sono stati riconosciuti dal leader originale in quei pochi secondi in cui due leader stavano lavorando andranno persi.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 29. Scenario 4. Il leader sul broker 1 diventa un follower dopo che la rete viene ripristinata

Scenario 5: il follower è completamente separato sia dagli altri nodi Kafka che da Zookeeper

Il follower è completamente isolato sia dagli altri nodi Kafka che da Zookeeper. Si allontana semplicemente dall'ISR finché la rete non viene ripristinata, quindi raggiunge gli altri.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 30. Scenario 5: il follower isolato viene rimosso da ISR

Scenario 6: il leader è completamente separato sia dagli altri nodi Kafka che da Zookeeper

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 31. Scenario 6. Leader e due seguaci

Il leader è completamente isolato dai suoi seguaci, dal controllore e dal guardiano dello zoo. Per un breve periodo continuerà ad accettare iscrizioni da acks=1.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 32. Scenario 6: Isolare il leader dagli altri nodi Kafka e Zookeeper

Non aver ricevuto richieste dopo la scadenza replica.lag.time.max.ms, proverà a ridurre l'ISR a se stesso, ma non sarà in grado di farlo perché non c'è comunicazione con Zookeeper, quindi smetterà di accettare scritture.

Nel frattempo, Zookeeper contrassegnerà il broker isolato come morto e il controllore eleggerà un nuovo leader.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 33. Scenario 6. Due leader

Il leader originale può accettare le voci per alcuni secondi, ma poi smette di accettare qualsiasi messaggio. I client vengono aggiornati ogni 60 secondi con i metadati più recenti. Saranno informati del cambio di leader e inizieranno a inviare iscrizioni al nuovo leader.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 34. Scenario 6: i produttori passano a un nuovo leader

Tutte le voci confermate effettuate dal leader originale dopo la perdita di connettività andranno perse. Una volta ripristinata la rete, il leader originale scoprirà tramite Zookeeper di non essere più il leader. Quindi troncherà il suo log all'HW del nuovo leader al momento dell'elezione e inizierà a inviare richieste come follower.

RabbitMQ vs Kafka: tolleranza agli errori e alta disponibilità
Riso. 35. Scenario 6: il leader originale diventa un follower dopo che la connettività di rete è stata ripristinata

In questa situazione, la separazione logica può verificarsi per un breve periodo, ma solo se acks=1 и repliche.min.insinc inoltre 1. La separazione logica termina automaticamente dopo che la rete viene ripristinata, quando il leader originale si rende conto di non essere più il leader, o quando tutti i clienti si rendono conto che il leader è cambiato e iniziano a scrivere al nuovo leader, a seconda di quale evento si verifica per primo. In ogni caso alcuni messaggi andranno persi, ma solo con acks=1.

Esiste un'altra variante di questo scenario in cui, poco prima della divisione della rete, i follower sono rimasti indietro e il leader ha compresso l'ISR solo su se stesso. Diventa quindi isolato a causa della perdita di connettività. Viene eletto un nuovo leader, ma anche il leader originale continua ad accettare iscrizioni acks=tutto, perché non c'è nessun altro nell'ISR tranne lui. Questi record andranno persi una volta ripristinata la rete. L'unico modo per evitare questa opzione è min.insincronia.repliche = 2.

Scenario 7: il nodo controller Kafka non riesce a vedere un altro nodo Kafka

In generale, una volta persa la connessione con un nodo Kafka, il controller non sarà in grado di trasmettergli alcuna informazione di cambio leader. Nel peggiore dei casi, ciò porterà a una separazione logica a breve termine, come nello scenario 6. Nella maggior parte dei casi, il broker semplicemente non diventerà un candidato alla leadership se quest’ultima fallisce.

Scenario 8: il controller Kafka non vede Zookeeper

Zookeeper non riceverà un ping dal controller caduto e selezionerà un nuovo nodo Kafka come controller. Il controller originale potrà continuare a presentarsi come tale, ma non riceverà notifiche da Zookeeper, quindi non avrà alcun compito da svolgere. Una volta ripristinata la rete, si renderà conto di non essere più un controller, ma di essere diventato un normale nodo Kafka.

Conclusioni dagli scenari

Vediamo che la perdita della connettività dei follower non comporta la perdita dei messaggi, ma riduce semplicemente temporaneamente la ridondanza fino al ripristino della rete. Ciò, ovviamente, può portare alla perdita di dati se uno o più nodi vengono persi.

Se il leader viene separato da Zookeeper a causa di una perdita di connettività, ciò potrebbe comportare la perdita dei messaggi acks=1. La mancanza di comunicazione con Zookeeper provoca una breve divisione logica tra i due leader. Questo problema è risolto dal parametro acks=tutto.

Parametro repliche.min.insinc in due o più repliche fornisce ulteriore garanzia che tali scenari a breve termine non comporteranno la perdita di messaggi come nello scenario 6.

Riepilogo dei messaggi persi

Elenchiamo tutti i modi in cui puoi perdere dati in Kafka:

  • Qualsiasi errore leader se i messaggi sono stati confermati utilizzando acks=1
  • Qualsiasi transizione impura della leadership, cioè verso un seguace esterno all'ISR, anche con acks=tutto
  • Isolare il leader da Zookeeper se i messaggi sono stati confermati utilizzando acks=1
  • Completo isolamento del leader che ha già ristretto a se stesso il gruppo ISR. Anche tutti i messaggi andranno persi acks=tutto. Questo è vero solo se min.insync.replicas=1.
  • Guasti simultanei di tutti i nodi della partizione. Poiché i messaggi vengono riconosciuti dalla memoria, alcuni potrebbero non essere ancora scritti su disco. Dopo aver riavviato i server, alcuni messaggi potrebbero mancare.

Le transizioni impure di leadership possono essere evitate vietandole o garantendo almeno due licenziamenti. La configurazione più duratura è una combinazione acks=tutto и repliche.min.insinc più di 1.

Confronto diretto dell'affidabilità di RabbitMQ e Kafka

Per garantire affidabilità ed elevata disponibilità, entrambe le piattaforme implementano un sistema di replica primario e secondario. Tuttavia, RabbitMQ ha un tallone d’Achille. Quando si riconnettono dopo un errore, i nodi scartano i propri dati e la sincronizzazione viene bloccata. Questo doppio problema mette in discussione la longevità delle grandi code in RabbitMQ. Dovrai accettare una ridondanza ridotta o tempi di blocco lunghi. La riduzione della ridondanza aumenta il rischio di una massiccia perdita di dati. Ma se le code sono piccole, per motivi di ridondanza è possibile gestire brevi periodi di indisponibilità (pochi secondi) utilizzando ripetuti tentativi di connessione.

Kafka non ha questo problema. Scarta i dati solo dal punto di divergenza tra leader e follower. Tutti i dati condivisi vengono salvati. Inoltre, la replica non blocca il sistema. Il leader continua ad accettare post mentre il nuovo follower si mette al passo, quindi per i devop unirsi o rientrare nel cluster diventa un compito banale. Naturalmente, ci sono ancora problemi come la larghezza di banda della rete durante la replica. Se aggiungi più follower contemporaneamente, potresti riscontrare un limite di larghezza di banda.

RabbitMQ è superiore a Kafka in termini di affidabilità quando più server in un cluster si guastano contemporaneamente. Come abbiamo già detto, RabbitMQ invia una conferma all'editore solo dopo che il messaggio è stato scritto su disco dal master e da tutti i mirror. Ma questo aggiunge ulteriore latenza per due motivi:

  • fsync ogni poche centinaia di millisecondi
  • Il fallimento del mirror può essere notato solo dopo che è scaduta la vita dei pacchetti che controllano la disponibilità di ciascun nodo (net tick). Se lo specchio rallenta o cade, ciò aggiunge un ritardo.

La scommessa di Kafka è che se un messaggio viene archiviato su più nodi, può riconoscere i messaggi non appena raggiungono la memoria. Per questo motivo esiste il rischio di perdere messaggi di qualsiasi tipo (anche acks=tutto, min.insync.replicas=2) in caso di guasto simultaneo.

Nel complesso, Kafka mostra prestazioni software migliori ed è progettato da zero per i cluster. Il numero di follower può essere aumentato a 11 se necessario per affidabilità. Fattore di replica 5 e numero minimo di repliche in sincronizzazione min.insync.replicas=3 renderà la perdita dei messaggi un evento molto raro. Se la tua infrastruttura è in grado di supportare questo rapporto di replica e livello di ridondanza, puoi scegliere questa opzione.

Il clustering RabbitMQ è utile per le code di piccole dimensioni. Ma anche le piccole code possono crescere rapidamente quando il traffico è intenso. Una volta che le code diventano grandi, dovrai fare scelte difficili tra disponibilità e affidabilità. Il clustering RabbitMQ è più adatto per situazioni non tipiche in cui i vantaggi della flessibilità di RabbitMQ superano gli eventuali svantaggi del clustering.

Un antidoto alla vulnerabilità di RabbitMQ alle code di grandi dimensioni è suddividerle in molte code più piccole. Se non è necessario ordinare completamente l'intera coda, ma solo i messaggi rilevanti (ad esempio, i messaggi di un cliente specifico) o non ordinare nulla, allora questa opzione è accettabile: guarda il mio progetto Riequilibratore per dividere la coda (il progetto è ancora in una fase iniziale).

Infine, non dimenticare una serie di bug nei meccanismi di clustering e replica sia di RabbitMQ che di Kafka. Nel corso del tempo, i sistemi sono diventati più maturi e stabili, ma nessun messaggio sarà mai sicuro al 100% dalla perdita! Inoltre, nei data center si verificano incidenti su larga scala!

Se mi sono perso qualcosa, ho commesso un errore o non sei d'accordo con uno qualsiasi dei punti, sentiti libero di scrivere un commento o contattarmi.

Spesso mi viene chiesto: “Cosa scegliere, Kafka o RabbitMQ?”, “Quale piattaforma è migliore?”. La verità è che dipende davvero dalla tua situazione, dall'esperienza attuale, ecc. Sono titubante nel dare la mia opinione perché sarebbe una semplificazione eccessiva raccomandare un'unica piattaforma per tutti i casi d'uso e le possibili limitazioni. Ho scritto questa serie di articoli in modo che tu possa formarti la tua opinione.

Voglio dire che entrambi i sistemi sono leader in questo settore. Potrei essere un po' di parte perché dalla mia esperienza con i progetti tendo a dare valore a cose come l'ordine garantito dei messaggi e l'affidabilità.

Vedo altre tecnologie che mancano di questa affidabilità e di un ordine garantito, quindi guardo RabbitMQ e Kafka e mi rendo conto dell'incredibile valore di entrambi questi sistemi.

Fonte: habr.com

Aggiungi un commento