В
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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!
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.
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.
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
- 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.
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:
- Troncherà il log locale in un HW conosciuto e invierà una richiesta al nuovo leader per i messaggi dopo questo segno.
- 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
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.
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
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.
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.
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
Riso. 27. Scenario 4. Leader e due seguaci
Il leader è separato dallo Zookeeper, ma non dagli intermediari con seguaci.
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.
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.
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
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.
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.
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.
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.
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
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