{"id":52541,"date":"2019-11-11T00:00:00","date_gmt":"2019-11-10T21:00:00","guid":{"rendered":"https:\/\/prohoster.info\/blog\/blog_prohoster\/rabbitmq-protiv-kafka-otkazoustojchivost-i-vysokaya-dostupnost"},"modified":"2020-02-18T14:00:17","modified_gmt":"2020-02-18T11:00:17","slug":"rabbitmq-protiv-kafka-otkazoustojchivost-i-vysokaya-dostupnost","status":"publish","type":"post","link":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/rabbitmq-protiv-kafka-otkazoustojchivost-i-vysokaya-dostupnost","title":{"rendered":"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/6557ce69c2b3070622feca8b3c228b09.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIn <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/itsumma\/blog\/471858\/\">precedente articolo<\/a><\/noindex> abbiamo esaminato la clusterizzazione di RabbitMQ per garantire disponibilit\u00e0 e tolleranza agli errori. Ora andiamo pi\u00f9 a fondo in Apache Kafka.<\/p>\n<p>Qui l'unit\u00e0 di replica \u00e8 la partizione (partition). Ogni topic ha una o pi\u00f9 partizioni. In ogni partizione c'\u00e8 un leader con dei follower o senza di essi. Quando si crea un topic, si specifica il numero di partizioni e il fattore di replica. Un valore comune \u00e8 3, il che significa tre repliche: un leader e due follower.<br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/36deb6d506223c2ee2ec147d5c215789.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 1. Quattro partizioni sono distribuite tra tre broker<\/i><\/p>\n<p>Tutte le richieste di lettura e scrittura vengono inviate al leader. I follower inviano periodicamente richieste al leader per ottenere gli ultimi messaggi. I consumatori non si rivolgono mai ai follower, che esistono solo per ridondanza e tolleranza agli errori.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/715c51d75cb45863cfad4b37e81b9a9a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<h1>Guasto della partizione<\/h1>\n<p>\nQuando un broker va offline, spesso si interrompono i leader di diverse partizioni. In ognuna di esse, il leader diventa un follower di un altro nodo. In realt\u00e0, non \u00e8 sempre cos\u00ec, poich\u00e9 influisce anche il fattore di sincronizzazione: ci sono follower sincronizzati e, se non ci sono, \u00e8 permesso il passaggio a una replica non sincronizzata. Ma per ora non complicchiamo le cose.<\/p>\n<p>Il broker 3 esce dalla rete e per la partizione 2 viene eletto un nuovo leader sul broker 2.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/b8cfce64cf6b848b0659de023f9d9b63.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 2. Il broker 3 muore e il suo follower sul broker 2 viene eletto nuovo leader della partizione 2.<\/i><\/p>\n<p>Poi il broker 1 esce e anche la partizione 1 perde il suo leader, il cui ruolo passa al broker 2.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/9f5409c723da7ff059b93f9b23e7d5f6.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 3. Rimane solo un broker. Tutti i leader si trovano su un unico broker con zero ridondanza.<\/i><\/p>\n<p>Quando il broker 1 torna in rete, aggiunge quattro follower, garantendo una certa ridondanza a ciascuna partizione. Ma tutti i leader sono ancora rimasti sul broker 2.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/f9c8e42f51258b7fd7f6f35dc7b8cc3b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 4. I leader rimangono sul broker 2.<\/i><\/p>\n<p>Quando il broker 3 si riattiva, torniamo a tre repliche per partizione. Ma tutti i leader sono ancora sul broker 2.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/9c8c02be4161f8468b5dbc1e3f6ecb3a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 5. Distribuzione sbilanciata dei leader dopo il ripristino dei broker 1 e 3.<\/i><\/p>\n<p>Kafka offre uno strumento per un bilanciamento dei leader di qualit\u00e0 superiore rispetto a RabbitMQ. In quest'ultimo era necessario utilizzare un plugin di terze parti o uno script per modificare le politiche di migrazione del nodo principale, riducendo la ridondanza durante la migrazione. Inoltre, per code di grandi dimensioni era necessario accettare l'inaccessibilit\u00e0 durante la sincronizzazione.<\/p>\n<p>Kafka introduce il concetto di \"repliche preferenziali\" per il ruolo di leader. Quando vengono creati i topic, Kafka cerca di distribuire i leader uniformemente tra i nodi e segna questi primi leader come preferenziali. Nel tempo, a causa di riavvii dei server, guasti e problemi di connettivit\u00e0, i leader possono trovarsi su altri nodi, come nel caso estremo descritto sopra.<\/p>\n<p>Per risolvere questo problema, Kafka offre due opzioni:<\/p>\n<ul>\n<li>Opzione <i>auto.leader.rebalance.enable=true<\/i> consente al nodo controller di ripristinare automaticamente i leader alle repliche preferenziali, ripristinando cos\u00ec una distribuzione uniforme.\n<\/li>\n<li>L'amministratore pu\u00f2 eseguire lo script <i>kafka-preferred-replica-election.sh<\/i> per rieseguire manualmente la nomina.<\/li>\n<\/ul>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/831930b06809637018fecb6d7d5a558d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 6. Repliche dopo il bilanciamento<\/i><\/p>\n<p>Questa era una versione semplificata del guasto, ma la realt\u00e0 \u00e8 pi\u00f9 complessa, anche se non c'\u00e8 nulla di troppo difficile qui. Tutto si riduce a repliche sincronizzate (In-Sync Replicas, ISR).<\/p>\n<h1>Repliche sincronizzate (ISR)<\/h1>\n<p>\nL'ISR \u00e8 un insieme di repliche di una partizione che \u00e8 considerato \"sincronizzato\" (in-sync). Qui c'\u00e8 un leader, e potrebbero non esserci follower. Un follower \u00e8 considerato sincronizzato se ha fatto copie esatte di tutti i messaggi del leader entro l'intervallo di tempo stabilito. <i>replica.lag.time.max.ms<\/i>.<\/p>\n<p>Un follower viene rimosso dall'insieme ISR se:<\/p>\n<ul>\n<li>non ha effettuato una richiesta di fetch entro l'intervallo <i>replica.lag.time.max.ms<\/i> (considerato morto)\n<\/li>\n<li>non \u00e8 riuscito ad aggiornarsi entro l'intervallo <i>replica.lag.time.max.ms<\/i> (considerato lento)<\/li>\n<\/ul>\n<p>\nI follower effettuano richieste di fetch nell'intervallo <i>replica.fetch.wait.max.ms<\/i>, che per impostazione predefinita \u00e8 di 500 ms.<\/p>\n<p>Per spiegare chiaramente l'obiettivo dell'ISR, \u00e8 necessario esaminare le conferme dal produttore (producer) e alcuni scenari di guasto. I produttori possono scegliere quando il broker invia una conferma:<\/p>\n<ul>\n<li>acks=0, la conferma non viene inviata\n<\/li>\n<li>acks=1, la conferma viene inviata dopo che il leader ha registrato il messaggio nel proprio log locale\n<\/li>\n<li>acks=all, la conferma viene inviata dopo che tutte le repliche nell'ISR hanno registrato il messaggio nei log locali<\/li>\n<\/ul>\n<p>\nNella terminologia di Kafka, se l'ISR ha mantenuto il messaggio, si verifica il suo \"commit\". Acks=all \u00e8 l'opzione pi\u00f9 sicura, ma comporta anche una ritardo aggiuntivo. Esaminiamo due esempi di guasto e come le diverse opzioni di 'acks' interagiscono con il concetto di ISR.<\/p>\n<h3>Acks=1 e ISR<\/h3>\n<p>\nIn questo esempio vedremo che se il leader non attende che ogni messaggio venga memorizzato da tutti i follower, \u00e8 possibile che si verifichi una perdita di dati in caso di errore del leader. Il passaggio a un follower non sincronizzato pu\u00f2 essere consentito o vietato tramite l'impostazione <i>unclean.leader.election.enable<\/i>.<\/p>\n<p>In questo esempio, il produttore ha impostato acks=1. La partizione \u00e8 distribuita su tutti e tre i broker. Il broker 3 \u00e8 in ritardo, si \u00e8 sincronizzato con il leader otto secondi fa e ora \u00e8 in ritardo di 7456 messaggi. Il broker 1 \u00e8 in ritardo di solo un secondo. Il nostro produttore invia un messaggio e riceve rapidamente un ack, senza sovraccarico per i follower lenti o morti, che il leader non attende.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/f194e6309b732b772574392eff482a8b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 7. ISR con tre repliche<\/i><\/p>\n<p>Il broker 2 va in errore, e il produttore riceve un errore di connessione. Dopo il passaggio della leadership al broker 1, perdiamo 123 messaggi. Il follower sul broker 1 era nell'ISR, ma non si era completamente sincronizzato con il leader quando \u00e8 caduto.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/367f219daebafefe585059f67fdedf6f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 8. I messaggi vengono persi in caso di guasto<\/i><\/p>\n<p>Nella configurazione <i>bootstrap.servers<\/i> al produttore sono elencati diversi broker, e pu\u00f2 chiedere a un altro broker chi \u00e8 diventato il nuovo leader della partizione. Poi stabilisce una connessione con il broker 1 e continua a inviare messaggi.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/ba45c51f4ce1f63f10b2fa0e1487b223.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 9. L'invio dei messaggi riprende dopo una breve interruzione<\/i><\/p>\n<p>Il broker 3 \u00e8 in ulteriore ritardo. Effettua richieste di recupero, ma non riesce a sincronizzarsi. Questo pu\u00f2 essere dovuto a una connessione di rete lenta tra i broker, problemi di archiviazione, ecc. Viene rimosso dall'ISR. Ora l'ISR consiste in una sola replica: il leader! Il produttore continua a inviare messaggi e a ricevere conferme.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/592c74632e3a8d80c2b4fc15bde5d401.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 10. Il follower sul broker 3 viene rimosso dall'ISR<\/i><\/p>\n<p>Il broker 1 va in gi\u00f9 e il ruolo di leader passa al broker 3 con una perdita di 15286 messaggi! Il produttore riceve un errore di connessione. Il passaggio al leader al di fuori dell'ISR \u00e8 stato possibile solo grazie alla configurazione. <i>unclean.leader.election.enable=true<\/i>. Se impostato su <i>false<\/i>, il passaggio non sarebbe avvenuto e tutte le richieste di lettura e scrittura sarebbero state rifiutate. In tal caso, aspettiamo il ritorno del broker 1 con i suoi dati intatti nella replica, che riprender\u00e0 la leadership.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/30f01ca715ccc194890ae061a3ef7396.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 11. Il broker 1 va in gi\u00f9. Durante il fallimento si perdono un gran numero di messaggi.<\/i><\/p>\n<p>Il produttore stabilisce una connessione con l'ultimo broker e vede che ora \u00e8 il leader della partizione. Inizia a inviare messaggi al broker 3.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/986532d9b22b6514b6039c8460b1beb4.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 12. Dopo una breve interruzione, i messaggi ricominciano a essere inviati alla partizione 0.<\/i><\/p>\n<p>Abbiamo visto che, oltre a brevi interruzioni per stabilire nuove connessioni e cercare un nuovo leader, il produttore ha continuato a inviare messaggi. Questa configurazione garantisce disponibilit\u00e0 a scapito della coerenza (sicurezza dei dati). Kafka ha perso migliaia di messaggi, ma ha continuato a ricevere nuove registrazioni.<\/p>\n<h3>Acks=all e ISR<\/h3>\n<p>\nRipetiamo questo scenario ancora una volta, ma con <i>acks=all<\/i>. Il broker 3 ha in media un ritardo di quattro secondi. Il produttore invia un messaggio con <i>acks=all<\/i>, e ora non riceve una risposta veloce. Il leader aspetta che il messaggio venga salvato da tutte le repliche in ISR.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/95b1abdc92e699f7bc41ebab249a2e08.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 13. ISR con tre repliche. Una funziona lentamente, il che porta a un ritardo nella registrazione<\/i><\/p>\n<p>Dopo quattro secondi di ulteriore ritardo, il broker 2 invia un ack. Tutte le repliche sono ora completamente aggiornate.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/64356dc8d2641a3e22947126dd047f39.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 14. Tutte le repliche memorizzano i messaggi e viene inviato ack<\/i><\/p>\n<p>Il broker 3 ora \u00e8 ulteriormente in ritardo ed \u00e8 rimosso dall'ISR. Il ritardo diminuisce notevolmente, poich\u00e9 non ci sono pi\u00f9 repliche lente nell'ISR. Il broker 2 sta ora aspettando solo il broker 1, che ha un ritardo medio di 500 ms.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/5d3bd67dc53cb868fa40b358ed483a1d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 15. Replica sul broker 3 rimossa dall'ISR<\/i><\/p>\n<p>Poi cade il broker 2, e la leadership passa al broker 1 senza perdita di messaggi.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/e3f0417aa7714ea5eae8a8e8d61662bd.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 16. Broker 2 in caduta<\/i><\/p>\n<p>Il produttore trova un nuovo leader e inizia a inviargli messaggi. Il ritardo diminuisce ulteriormente, dato che ora l'ISR \u00e8 composto da una sola replica! Pertanto, l'opzione <i>acks=all<\/i> non aggiunge ridondanza.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/fec9aae9977757d5f61c2909ceae0536.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 17. Replica sul broker 1 assume la leadership senza perdita di messaggi<\/i><\/p>\n<p>Poi cade il broker 1, e la leadership passa al broker 3 con una perdita di 14238 messaggi!<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/730b3951fb75ab3a782fc6d064615212.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 18. Il broker 1 muore, e il passaggio di leadership con la configurazione unclean porta a una significativa perdita di dati<\/i><\/p>\n<p>Potremmo non impostare l'opzione <i>unclean.leader.election.enable<\/i> su <i>true<\/i>. Per impostazione predefinita \u00e8 <i>false<\/i>. La configurazione <i>acks=all<\/i> con <i>unclean.leader.election.enable=true<\/i> garantisce la disponibilit\u00e0 con una certa sicurezza aggiuntiva dei dati. Ma, come puoi vedere, possiamo comunque perdere i messaggi.<\/p>\n<p>Ma cosa succede se vogliamo aumentare la sicurezza dei dati? Possiamo impostare <i>unclean.leader.election.enable = false<\/i>, ma questo non ci protegger\u00e0 necessariamente dalla perdita di dati. Se il leader \u00e8 andato gi\u00f9 in modo critico e ha portato via i dati, i messaggi sono comunque persi, e inoltre viene persa la disponibilit\u00e0 finch\u00e9 l'amministratore non ripristina la situazione.<\/p>\n<p>\u00c8 meglio garantire la ridondanza di tutti i messaggi, altrimenti rinunciare alla registrazione. In questo modo, almeno dal punto di vista del broker, la perdita di dati \u00e8 possibile solo in caso di due o pi\u00f9 guasti simultanei.<\/p>\n<h3>Acks=all, min.insync.replicas e ISR<\/h3>\n<p>\nCon la configurazione del topic <i>min.insync.replicas<\/i> aumentiamo il livello di sicurezza dei dati. Rivediamo l'ultima parte dello scenario precedente, ma questa volta con <i>min.insync.replicas=2<\/i>.<\/p>\n<p>Quindi, il broker 2 ha un leader replica, e il follower sul broker 3 \u00e8 stato rimosso dall'ISR.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/5831463293f1837d3232756894e97162.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 19. ISR di due repliche<\/i><\/p>\n<p>Il broker 2 si interrompe, mentre la leadership passa al broker 1 senza perdita di messaggi. Ma ora l'ISR \u00e8 composto da una sola replica. Ci\u00f2 non soddisfa il numero minimo necessario per registrare i dati, quindi il broker risponde con un errore alla richiesta di scrittura. <i>NotEnoughReplicas<\/i>.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/6b2ee477f4c33ec84f3068b792814e5d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 20. Il numero di ISR \u00e8 uno in meno rispetto a quanto indicato in min.insync.replicas.<\/i><\/p>\n<p>Questa configurazione sacrifica la disponibilit\u00e0 per la coerenza. Prima di confermare un messaggio, garantiamo che venga registrato su almeno due repliche. Questo offre al produttore una maggiore sicurezza. Qui la perdita di messaggi \u00e8 possibile solo in caso di guasto simultaneo di due repliche in un breve lasso di tempo, prima che il messaggio venga replicato a un follower aggiuntivo, il che \u00e8 poco probabile. Ma se sei molto paranoico, puoi impostare un fattore di replica di 5. <i>min.insync.replicas<\/i> e 3. Qui tre broker devono fallire simultaneamente per perdere la registrazione! Certamente, per questa affidabilit\u00e0 pagherai un ritardo aggiuntivo.<\/p>\n<h1>Quando la disponibilit\u00e0 \u00e8 necessaria per la sicurezza dei dati<\/h1>\n<p>\nCome in <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/itsumma\/blog\/471858\/\">nel caso di RabbitMQ<\/a><\/noindex>, a volte la disponibilit\u00e0 \u00e8 necessaria per la sicurezza dei dati. Devi considerare quanto segue:<\/p>\n<ul>\n<li>Un publisher pu\u00f2 semplicemente restituire un errore e il servizio superiore o l'utente pu\u00f2 riprovare pi\u00f9 tardi?\n<\/li>\n<li>Pu\u00f2 un publisher memorizzare un messaggio localmente o in un database per riprovare in seguito?<\/li>\n<\/ul>\n<p>\nSe la risposta \u00e8 negativa, l'ottimizzazione della disponibilit\u00e0 aumenta la sicurezza dei dati. Si perderanno meno dati scegliendo la disponibilit\u00e0 invece del rifiuto della registrazione. In questo modo, tutto si riduce alla ricerca di un equilibrio, e la decisione dipende dalla situazione specifica.<\/p>\n<h1>Significato di ISR<\/h1>\n<p>\nIl set di ISR consente di trovare il giusto equilibrio tra sicurezza dei dati e latenza. Ad esempio, garantire la disponibilit\u00e0 in caso di guasto della maggior parte delle repliche, minimizzando l'impatto delle repliche morte o lente in termini di latenza.<\/p>\n<p>Scegliamo noi stessi il valore <i>replica.lag.time.max.ms<\/i> in base alle nostre esigenze. In sostanza, questo parametro indica quale latenza siamo disposti ad accettare. <i>acks=all<\/i>Il valore predefinito \u00e8 di dieci secondi. Se per te \u00e8 troppo lungo, puoi ridurlo. In tal caso, aumenter\u00e0 la frequenza delle modifiche in ISR, poich\u00e9 i follower verranno rimossi e aggiunti pi\u00f9 frequentemente.<\/p>\n<p>In RabbitMQ ci sono solo insiemi di specchi da replicare. Gli specchi lenti introducono un ulteriore ritardo, e la risposta dei mirror morti pu\u00f2 essere attesa fino alla scadenza del tempo di vita dei pacchetti che verificano la disponibilit\u00e0 di ciascun nodo (net tick). ISR \u00e8 un modo interessante per evitare questi problemi di aumento del ritardo. Ma rischiamo di perdere ridondanza, poich\u00e9 ISR pu\u00f2 ridursi solo al leader. Per evitare questo rischio, utilizzare la configurazione <i>min.insync.replicas<\/i>.<\/p>\n<h1>Garanzia di connessione per i clienti<\/h1>\n<p>\nNelle impostazioni <i>bootstrap.servers<\/i> del produttore e del consumatore \u00e8 possibile specificare pi\u00f9 broker per la connessione dei clienti. L'idea \u00e8 che, in caso di disconnessione di un nodo, rimangano diversi di riserva con cui il cliente pu\u00f2 stabilire una connessione. Questi non devono necessariamente essere i leader delle partizioni, ma semplicemente un punto di partenza per il caricamento iniziale. Il cliente pu\u00f2 chiedere loro su quale nodo \u00e8 situato il leader della partizione per lettura\/scrittura.<\/p>\n<p>In RabbitMQ, clients can connect to any node, and the internal routing sends requests where they need to go. This means you can place a load balancer in front of RabbitMQ. Kafka requires clients to connect to the node where the leader of the corresponding partition is hosted. In this situation, a load balancer cannot be placed. The list <i>bootstrap.servers<\/i> is critical for clients to access the necessary nodes and locate them after a failure.<\/p>\n<h1>Kafka Consensus Architecture<\/h1>\n<p>\nSo far, we have not discussed how a cluster becomes aware of a broker failure and how a new leader is selected. To understand how Kafka operates with network partitions, it is essential first to grasp the consensus architecture.<\/p>\n<p>Each Kafka cluster is deployed along with a Zookeeper cluster \u2014 a distributed consensus service that allows the system to achieve consensus on some defined state, prioritizing consistency over availability. Approval from the majority of Zookeeper nodes is required for read and write operations.<\/p>\n<p>Zookeeper stores the state of the cluster:<\/p>\n<ul>\n<li>Elenco dei topic, delle partizioni, della configurazione, delle repliche del leader attuale e delle repliche preferite.\n<\/li>\n<li>Membri del cluster. Ogni broker invia un ping al cluster Zookeeper. Se quest'ultimo non riceve un ping per un periodo di tempo definito, registra il broker come non disponibile.\n<\/li>\n<li>Selezione dei nodi primari e secondari per il controller.<\/li>\n<\/ul>\n<p>\nIl nodo controller \u00e8 uno dei broker Kafka responsabile dell'elezione dei leader delle repliche. Zookeeper invia notifiche al controller riguardo ai cambiamenti nella composizione del cluster e nei topic, e il controller deve agire in base a queste modifiche.<\/p>\n<p>Ad esempio, consideriamo un nuovo topic con dieci partizioni e un fattore di replica di 3. Il controller deve scegliere un leader per ciascuna partizione, cercando di distribuire ottimamente i leader tra i broker. <\/p>\n<p>Per ciascuna partizione, il controller:<\/p>\n<ul>\n<li>aggiorna le informazioni in Zookeeper riguardo a ISR e leader;\n<\/li>\n<li>invia il comando LeaderAndISRCommand a ogni broker che ospita una replica di quella partizione, informando i broker su ISR e leader.<\/li>\n<\/ul>\n<p>\nQuando un broker crolla, Zookeeper invia una notifica al controller, il quale sceglie un nuovo leader. Anche in questo caso, il controller aggiorna prima Zookeeper e poi invia un comando a ciascun broker, informandoli del cambiamento di leadership.<\/p>\n<p>Ogni leader \u00e8 responsabile dell'insieme di ISR. La configurazione <i>replica.lag.time.max.ms<\/i> definisce chi ne far\u00e0 parte. Quando l'ISR cambia, il leader comunica a Zookeeper le nuove informazioni.<\/p>\n<p>Zookeeper \u00e8 sempre informato su qualsiasi cambiamento, in modo che in caso di guasti la leadership possa passare senza problemi a un nuovo leader.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/3adb1d204b28e3ed85bef3530fa2b738.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 21. Consenso Kafka<\/i><\/p>\n<h1>Protocollo di replica<\/h1>\n<p>\nComprendere i dettagli della replica aiuta a capire meglio i potenziali scenari di perdita di dati.<\/p>\n<h3>Richieste di fetch, Log End Offset (LEO) e Highwater Mark (HW)<\/h3>\n<p>\nAbbiamo visto che i follower inviano periodicamente richieste di fetch al leader. L'intervallo predefinito \u00e8 di 500 ms. Questo \u00e8 diverso da RabbitMQ, dove la replica \u00e8 avviata non dal mirror della coda, ma dal master. Il master invia le modifiche ai mirror.<\/p>\n<p>Il leader e tutti i follower mantengono il Log End Offset (LEO) e il segno Highwater (HW). Il segno LEO memorizza l'offset dell'ultimo messaggio nella replica locale, mentre HW rappresenta l'offset dell'ultimo commit. Ricordate che per lo stato 'commit' il messaggio deve essere salvato in tutte le repliche ISR. Questo significa che di solito LEO precede HW.<\/p>\n<p>Quando il leader riceve un messaggio, lo memorizza localmente. Un follower fa una richiesta di recupero, passando il proprio LEO. Successivamente, il leader invia un pacchetto di messaggi, a partire da questo LEO, e comunica l'attuale HW. Quando il leader riceve informazioni che tutte le repliche hanno salvato il messaggio con l'offset specificato, sposta il segno HW. Solo il leader pu\u00f2 spostare HW, quindi tutti i follower conoscono il valore attuale nelle risposte alla loro richiesta. Questo significa che i follower possono essere in ritardo rispetto al leader sia per i messaggi che per la conoscenza di HW. I consumatori ricevono messaggi solo fino all'attuale HW.<\/p>\n<p>Si prega di notare che \"persistito\" significa memorizzato in memoria, non su disco. Per motivi di prestazioni, Kafka sincronizza su disco a intervalli prestabiliti. Anche RabbitMQ ha un intervallo simile, ma invier\u00e0 la conferma al publisher solo dopo che il master e tutte le repliche hanno memorizzato il messaggio su disco. Gli sviluppatori di Kafka, per motivi di prestazioni, hanno deciso di inviare l'ack non appena il messaggio \u00e8 memorizzato in memoria. Kafka si affida al fatto che la ridondanza compensi il rischio di mantenere i messaggi confermati solo in memoria per un breve periodo.<\/p>\n<h1>Guasto del leader<\/h1>\n<p>\nQuando il leader cade, Zookeeper avvisa il controller, e questo sceglie una nuova replica come leader. Il nuovo leader stabilisce un nuovo watermark HW in base al suo LEO. Le informazioni sul nuovo leader vengono quindi ricevute dai follower. A seconda della versione di Kafka, il follower sceglier\u00e0 uno dei due scenari:<\/p>\n<ol>\n<li>Troncher\u00e0 il log locale fino a un HW noto e invier\u00e0 una richiesta al nuovo leader per i messaggi dopo quella marcatura.\n<\/li>\n<li>Invier\u00e0 una richiesta al leader per conoscere l'HW al momento della sua elezione, quindi trimmer\u00e0 il log fino a quel punto. Successivamente inizier\u00e0 a fare richieste periodiche di campionamento, partendo da questa posizione.<\/li>\n<\/ol>\n<p>\nUn follower potrebbe dover trimmare il log per i seguenti motivi:<\/p>\n<ul>\n<li>Quando si verifica un fallimento del leader, il primo follower del set ISR, registrato in Zookeeper, vince le elezioni e diventa leader. Tutti i follower nell'ISR, sebbene considerati \"sincronizzati\", potrebbero non aver ricevuto dal precedente leader copie di tutti i messaggi. \u00c8 possibile che il follower eletto non abbia la copia pi\u00f9 aggiornata. Kafka garantisce che non ci siano discrepanze tra le repliche. Pertanto, per evitare discrepanze, ogni follower deve trimmare il proprio log fino al valore HW del nuovo leader al momento della sua elezione. Questa \u00e8 un'altra ragione per cui la configurazione <i>acks=all<\/i> \u00e8 cos\u00ec importante per la coerenza.\n<\/li>\n<li>I messaggi vengono registrati periodicamente su disco. Se tutti i nodi del cluster falliscono contemporaneamente, le repliche con offset diversi verranno salvate sui dischi. \u00c8 possibile che, quando i broker torneranno in rete, un nuovo leader, che sar\u00e0 eletto, si trovi indietro rispetto ai suoi follower, poich\u00e9 \u00e8 stato salvato su disco prima degli altri.<\/li>\n<\/ul>\n<p><\/p>\n<h3>Riconnessione al cluster<\/h3>\n<p>\nDurante la riconnessione al cluster, le repliche si comportano come in caso di fallimento del leader: controllano la replica del leader e troncheranno il loro log fino al suo HW (al momento dell'elezione). A differenza di ci\u00f2, RabbitMQ considera i nodi riconnessi 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 attuale in un nuovo mirror con il metodo 'e che il mondo aspetti'. Durante questa operazione, il master non accetta alcuna operazione di lettura o scrittura. Questo approccio crea problemi in grandi code.<\/p>\n<p>Kafka \u00e8 un log distribuito e, in generale, conserva pi\u00f9 messaggi rispetto alla coda RabbitMQ, dove i dati vengono rimossi dalla coda dopo essere stati letti. Le code attive devono rimanere relativamente piccole. Ma Kafka \u00e8 un log con una propria politica di conservazione, che pu\u00f2 stabilire un termine di giorni o settimane. L'approccio con blocco della coda e sincronizzazione totale \u00e8 completamente inaccettabile per un log distribuito. Invece, i follower di Kafka semplicemente accorciano il loro log fino al leader HW (al momento della sua elezione) se la loro copia supera il leader. Nel caso pi\u00f9 probabile, quando un follower \u00e8 in ritardo, inizia semplicemente a fare richieste di polling, partendo dal suo attuale LEO.<\/p>\n<p>I nuovi follower o quelli riuniti iniziano al di fuori dell'ISR e non partecipano ai commit. Lavorano semplicemente accanto al gruppo, ricevendo messaggi il pi\u00f9 rapidamente possibile, finch\u00e9 non raggiungono il leader e non entrano nell'ISR. Qui non ci sono blocchi e non \u00e8 necessario scartare tutti i propri dati.<\/p>\n<h1>Violazione della connettivit\u00e0<\/h1>\n<p>\nKafka ha pi\u00f9 componenti rispetto a RabbitMQ, quindi si presenta un insieme pi\u00f9 complesso di comportamenti quando si verifica una perdita di connettivit\u00e0 nel cluster. Tuttavia, Kafka \u00e8 stato progettato fin dall'inizio per i cluster, quindi le soluzioni sono ben ragionate.<\/p>\n<p>Di seguito sono riportati alcuni scenari di perdita di connettivit\u00e0:<\/p>\n<ul>\n<li>Scenario 1. Il follower non vede il leader, ma vede ancora Zookeeper.\n<\/li>\n<li>Scenario 2. Il leader non vede alcun follower, ma vede ancora Zookeeper.\n<\/li>\n<li>Scenario 3. Il follower vede il leader, ma non vede Zookeeper.\n<\/li>\n<li>Scenario 4. Il leader vede i follower, ma non vede Zookeeper.\n<\/li>\n<li>Scenario 5. Il follower \u00e8 completamente isolato sia dagli altri nodi Kafka sia da Zookeeper.\n<\/li>\n<li>Scenario 6. Il leader \u00e8 completamente isolato sia dagli altri nodi Kafka sia da Zookeeper.\n<\/li>\n<li>Scenario 7. Il nodo controller di Kafka non vede un altro nodo Kafka.\n<\/li>\n<li>Scenario 8. Il controller di Kafka non vede Zookeeper.<\/li>\n<\/ul>\n<p>\nPer ogni scenario \u00e8 previsto un comportamento specifico.<\/p>\n<h3>Scenario 1. Il follower non vede il leader, ma vede ancora Zookeeper<\/h3>\n<p>\n<img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/5f51ae679933b2b5a69e21831465d121.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 22. Scenario 1. ISR di tre repliche<\/i><\/p>\n<p>La perdita di connettivit\u00e0 separa il broker 3 dai broker 1 e 2, ma non da Zookeeper. Il broker 3 non pu\u00f2 pi\u00f9 inviare richieste di fetch. Dopo un certo periodo di tempo <i>replica.lag.time.max.ms<\/i> viene rimosso dall'ISR e non partecipa ai commit dei messaggi. Non appena la connettivit\u00e0 viene ripristinata, riprender\u00e0 le richieste di fetch e si unir\u00e0 all'ISR quando raggiunger\u00e0 il leader. Zookeeper continuer\u00e0 a ricevere ping e considerer\u00e0 il broker vivo e vegeto.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/976b7ff080ee6a6d76a165f614f40e95.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 23. Scenario 1. Il broker viene rimosso dall'ISR se non riceve una richiesta di fetch entro l'intervallo replica.lag.time.max.ms<\/i><\/p>\n<p>Non c'\u00e8 alcuna separazione logica (split-brain) o pausa del nodo, come in RabbitMQ. Piuttosto, la ridondanza viene ridotta. <\/p>\n<h3>Scenario 2. Il leader non vede alcun follower, ma vede ancora Zookeeper<\/h3>\n<p>\n<img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/ff6aaa053d73e8b7c97111979bcf97aa.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 24. Scenario 2. Leader e due follower<\/i><\/p>\n<p>La violazione della connettivit\u00e0 di rete separa il leader dai follower, ma il broker vede ancora Zookeeper. Come nel primo scenario, l'ISR si riduce, ma questa volta solo al leader, poich\u00e9 tutti i follower smettono di inviare richieste di fetch. Ancora una volta, non c'\u00e8 alcuna separazione logica. Invece, si verifica una perdita di ridondanza per i nuovi messaggi finch\u00e9 la connettivit\u00e0 non viene ripristinata. Zookeeper continua a ricevere ping e considera il broker vivo e vegeto.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/3c69e8327da241407f76719fc022c37a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 25. Scenario 2. ISR ridotto solo al leader<\/i><\/p>\n<h3>Scenario 3. Il follower vede il leader, ma non vede Zookeeper<\/h3>\n<p>\nIl follower si separa da Zookeeper, ma non dal broker con il leader. Di conseguenza, il follower continua a fare richieste di polling ed \u00e8 membro dell'ISR. Zookeeper non riceve pi\u00f9 ping e registra il crash del broker, ma poich\u00e9 si tratta solo di un follower, non ci sono conseguenze una volta che il broker viene ripristinato.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/1183bcfe45a3225ae3ef1a0651f61350.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 26. Scenario 3. Il follower continua a inviare richieste di polling al leader<\/i><\/p>\n<h3>Scenario 4. Il leader vede i follower, ma non vede Zookeeper<\/h3>\n<p>\n<img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/b3bf27fcb0eb806b27ad00f098e50a26.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 27. Scenario 4. Il leader e due follower<\/i><\/p>\n<p>Il leader \u00e8 separato da Zookeeper, ma non dai broker con i follower. <\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/82d9f2e5868566678befc414d1885bfd.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 28. Scenario 4. Il leader \u00e8 isolato da Zookeeper<\/i><\/p>\n<p>Dopo un po' Zookeeper registrer\u00e0 il crash del broker e ne informer\u00e0 il controller. Questi sceglier\u00e0 un nuovo leader tra i follower. Tuttavia, il leader originale continuer\u00e0 a pensare di essere il leader e continuer\u00e0 a ricevere registrazioni con <i>acks=1<\/i>. I follower non gli inviano pi\u00f9 richieste di polling, quindi lui li considerer\u00e0 morti e tenter\u00e0 di comprimere l'ISR fino a se stesso. Ma poich\u00e9 non ha un collegamento a Zookeeper, non sar\u00e0 in grado di farlo e in quel momento smetter\u00e0 di accettare ulteriori registrazioni. <\/p>\n<p>Messaggi <i>acks=all<\/i> non riceveranno conferma, poich\u00e9 l'ISR include prima tutte le repliche e i messaggi non arrivano a esse. Quando il leader originale cercher\u00e0 di rimuoverli dall'ISR, non potr\u00e0 farlo e smetter\u00e0 completamente di ricevere messaggi.<\/p>\n<p>I clienti noteranno presto il cambio di leader e inizieranno a inviare registrazioni al nuovo server. Una volta che la rete si ristabilisce, il leader originale vede che non \u00e8 pi\u00f9 il leader e riduce il proprio log al valore HW che aveva il nuovo leader al momento del guasto, per evitare incongruenze. Poi inizier\u00e0 a inviare richieste di recupero al nuovo leader. Tutte le registrazioni del leader originale non replicate al nuovo leader andranno perse. Ovvero, andranno persi i messaggi non confermati dal leader originale nei pochi secondi in cui sono stati attivi due leader.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/d88d6f33c13dccb814c0f206ec72512b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 29. Scenario 4. Il leader sul broker 1 diventa follower dopo il ripristino della rete<\/i><\/p>\n<h3>Scenario 5. Il follower \u00e8 completamente isolato sia dagli altri nodi Kafka che da Zookeeper<\/h3>\n<p>\nIl follower \u00e8 completamente isolato sia dagli altri nodi Kafka che da Zookeeper. Viene semplicemente rimosso dall'ISR fino a quando la rete non si ristabilisce, e poi recupera gli altri.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/b092607f777014fd945f18734dd7f4e7.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 30. Scenario 5. The isolated follower is removed from the ISR<\/i><\/p>\n<h3>Scenario 6. The leader is completely separated from both other Kafka nodes and Zookeeper<\/h3>\n<p>\n<img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/bb808d534dbf65748eb0b481f86b4926.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 31. Scenario 6. The leader and two followers<\/i><\/p>\n<p>The leader is completely isolated from its followers, the controller, and Zookeeper. For a short period, it will continue to accept writes from <i>acks=1<\/i>.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/6fda78bcd26ef6b916579d447e9fb1f0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 32. Scenario 6. Leader isolation from other Kafka nodes and Zookeeper<\/i><\/p>\n<p>After not receiving requests for <i>replica.lag.time.max.ms<\/i>, it will attempt to shrink the ISR to itself, but it will be unable to do so due to loss of connection with Zookeeper, at which point it will stop accepting writes. <\/p>\n<p>Meanwhile, Zookeeper marks the isolated broker as dead, and the controller will elect a new leader.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/73d611a411fc64d835af2c714e9eba0a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 33. Scenario 6. Two leaders<\/i><\/p>\n<p>The original leader may accept writes for a few seconds, but will then stop accepting any messages. Clients are updated every 60 seconds with the latest metadata. They will be notified of the leadership change and will start sending writes to the new leader.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/ae99380c8a84fac15f440b699b9c552b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 34. Scenario 6. Producers switch to the new leader<\/i><\/p>\n<p>Tutte le registrazioni confermate fatte dal leader originale dal momento della perdita di connettivit\u00e0 andranno perse. Una volta ripristinata la rete, il leader originale attraverso Zookeeper scoprir\u00e0 di non essere pi\u00f9 il leader. Dopodich\u00e9, troncher\u00e0 il proprio log fino all'HW del nuovo leader al momento della sua elezione e inizier\u00e0 a inviare richieste come follower.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: disponibilit\u00e0 e tolleranza agli errori\" src=\"\/wp-content\/uploads\/2019\/11\/10f0983a829b03ca9bbc62e12cbf8a5d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 35. Scenario 6. Il leader originale diventa un follower dopo il ripristino della connettivit\u00e0 di rete<\/i><\/p>\n<p>In questa situazione, per un breve periodo, pu\u00f2 verificarsi una divisione logica, ma solo se <i>acks=1<\/i> e <i>min.insync.replicas<\/i> anche 1. La divisione logica si conclude automaticamente o dopo il ripristino della rete, quando il leader originale comprende che non \u00e8 pi\u00f9 il leader, oppure quando tutti i client capiscono che il leader \u00e8 cambiato e iniziano a scrivere al nuovo leader \u2014 a seconda di cosa accade prima. In ogni caso, ci sar\u00e0 una perdita di alcuni messaggi, ma solo con <i>acks=1<\/i>.<\/p>\n<p>C'\u00e8 un'altra opzione per questo scenario, in cui prima della divisione della rete i follower rimangono indietro e il leader riduce l'ISR a se stesso. Poi si isola a causa della perdita di connettivit\u00e0. Viene eletto un nuovo leader, ma il leader iniziale continua a ricevere registrazioni, anche <i>acks=all<\/i>, perch\u00e9 nell'ISR non c'\u00e8 nessun altro. Queste registrazioni andranno perse dopo il ripristino della rete. L'unico modo per evitare questo scenario \u00e8 <i>min.insync.replicas = 2<\/i>.<\/p>\n<h3>Scenario 7. Il nodo controller di Kafka non vede un altro nodo Kafka<\/h3>\n<p>\nIn generale, dopo la perdita di connessione con un nodo Kafka, il controller non sar\u00e0 in grado di trasmettergli alcuna informazione riguardo alla modifica del leader. Nella peggiore delle ipotesi, ci\u00f2 porter\u00e0 a una breve divisione logica, come nello scenario 6. Pi\u00f9 frequentemente, il broker non diventer\u00e0 semplicemente candidato alla leadership in caso di guasto dell'ultimo.<\/p>\n<h3>Scenario 8. Il controller di Kafka non vede Zookeeper<\/h3>\n<p>\nUn controller Zookeeper disconnesso non ricever\u00e0 ping e selezioner\u00e0 un nuovo nodo Kafka come controller. Il controller originale pu\u00f2 continuare a presentarsi come tale, ma non riceve notifiche da Zookeeper, quindi non avr\u00e0 n\u00e9 compiti n\u00e9 responsabilit\u00e0. Una volta che la rete sar\u00e0 ripristinata, capir\u00e0 di non essere pi\u00f9 un controller, ma un normale nodo Kafka.<\/p>\n<h3>Conclusioni dagli scenari<\/h3>\n<p>\nOsserviamo che la perdita di connettivit\u00e0 dei follower non porta alla perdita di messaggi, ma riduce temporaneamente la ridondanza fino a quando la rete non si ripristina. Questo, ovviamente, pu\u00f2 portare a una perdita di dati se uno o pi\u00f9 nodi risultano persi.<\/p>\n<p>Se, a causa della perdita di connettivit\u00e0, il leader viene separato da Zookeeper, ci\u00f2 pu\u00f2 portare a una perdita di messaggi con <i>acks=1<\/i>. L'assenza di connessione con Zookeeper provoca una breve divisione logica con due leader. Questo problema viene risolto dal parametro <i>acks=all<\/i>.<\/p>\n<p>Caratteristica <i>min.insync.replicas<\/i> in due o pi\u00f9 repliche fornisce garanzie aggiuntive che tali scenari a breve termine non porteranno alla perdita di messaggi, come nello scenario 6.<\/p>\n<h1>Riepilogo sulla perdita di messaggi<\/h1>\n<p>\nElenchiamo tutti i modi in cui \u00e8 possibile perdere dati in Kafka:<\/p>\n<ul>\n<li>Qualsiasi guasto del leader, se i messaggi venivano confermati tramite <i>acks=1<\/i>\n<\/li>\n<li>Qualsiasi passaggio di leadership sporco (unclean), ovvero a un follower al di fuori dell'ISR, anche con <i>acks=all<\/i>\n<\/li>\n<li>Isolamento del leader da Zookeeper, se i messaggi venivano confermati tramite <i>acks=1<\/i>\n<\/li>\n<li>Isolamento totale del leader, che ha gi\u00e0 ridotto il gruppo ISR a se stesso. Tutti i messaggi andranno persi, anche <i>acks=all<\/i>. Questo \u00e8 vero solo se <i>min.insync.replicas=1<\/i>.\n<\/li>\n<li>Guasti simultanei di tutti i nodi della partizione. Poich\u00e9 i messaggi vengono confermati dalla memoria, alcuni potrebbero non essere ancora scritti su disco. Dopo il riavvio dei server, potrebbero mancare alcuni messaggi.<\/li>\n<\/ul>\n<p>\nI passaggi sporchi di leadership possono essere evitati, vietandoli oppure garantendo una ridondanza di almeno due. La configurazione pi\u00f9 robusta \u00e8 una combinazione di <i>acks=all<\/i> e <i>min.insync.replicas<\/i> pi\u00f9 di 1.<\/p>\n<h1>Confronto diretto dell'affidabilit\u00e0 di RabbitMQ e Kafka<\/h1>\n<p>\nPer garantire affidabilit\u00e0 e alta disponibilit\u00e0, entrambe le piattaforme implementano un sistema di replica primaria e secondaria. Tuttavia, RabbitMQ ha un tallone d'Achille. Durante la riconnessione dopo un guasto, i nodi scartano i loro dati e la sincronizzazione si blocca. Questo doppio colpo mette in dubbio la longevit\u00e0 delle grandi code in RabbitMQ. Dovrete accettare o una riduzione della ridondanza o lunghe fasi di blocco. La diminuzione della ridondanza aumenter\u00e0 il rischio di una massiccia perdita di dati. Tuttavia, se le code sono piccole, per garantire la ridondanza con brevi periodi di inattivit\u00e0 (alcuni secondi), si pu\u00f2 affrontare attraverso tentativi di riconnessione.<\/p>\n<p>In Kafka, this problem doesn't exist. It only drops data from the point of divergence between the leader and the follower. All shared data is preserved. Furthermore, replication does not block the system. The leader continues to accept records while the new follower catches up, making joining or reconnecting to the cluster a trivial task for DevOps. Of course, issues like network bandwidth when replicating still remain. If multiple followers are added simultaneously, one may encounter bandwidth limits.<\/p>\n<p>RabbitMQ surpasses Kafka in reliability during simultaneous failures of multiple servers in the cluster. As we mentioned, RabbitMQ sends a confirmation to the publisher only after the message is written to disk by the master and all mirrors. However, this introduces additional latency for two reasons:<\/p>\n<ul>\n<li>fsync every few hundred milliseconds\n<\/li>\n<li>A mirror failure can only be detected after the expiration of the packet lifespan that checks the availability of each node (net tick). If a mirror lags or fails, it adds to the delay.<\/li>\n<\/ul>\n<p>\nKafka scommette sul fatto che se un messaggio \u00e8 memorizzato su pi\u00f9 nodi, \u00e8 possibile confermare i messaggi non appena entrano in memoria. Questo comporta un rischio di perdita di qualsiasi tipo di messaggio (anche <i>acks=all<\/i>, <i>min.insync.replicas=2<\/i>) in caso di guasto simultaneo.<\/p>\n<p>In generale, Kafka dimostra prestazioni superiori ed \u00e8 stato progettato fin dall'inizio per i cluster. Il numero di follower pu\u00f2 essere aumentato fino a 11, se necessario per l'affidabilit\u00e0. Un fattore di replica di 5 e un numero minimo di repliche in stato sincronizzato <i>min.insync.replicas=3<\/i> renderanno la perdita di messaggi un evento molto raro. Se la tua infrastruttura \u00e8 in grado di garantire tale fattore di replica e livello di ridondanza, puoi optare per questa opzione.<\/p>\n<p>La clusterizzazione di RabbitMQ \u00e8 utile per piccole code. Ma anche piccole code possono crescere rapidamente con alto traffico. Quando le code diventano grandi, sar\u00e0 necessario fare una scelta difficile tra disponibilit\u00e0 e affidabilit\u00e0. La clusterizzazione di RabbitMQ \u00e8 pi\u00f9 adatta a situazioni non tipiche, dove i vantaggi di flessibilit\u00e0 di RabbitMQ superano eventuali svantaggi della sua clusterizzazione.<\/p>\n<p>Una delle soluzioni per la vulnerabilit\u00e0 di RabbitMQ riguardo le code grandi \u00e8 suddividerle in pi\u00f9 code pi\u00f9 piccole. Se non \u00e8 necessario un ordinamento completo dell'intera coda, ma solo dei messaggi rilevanti (ad esempio, messaggi di un cliente specifico), oppure non ordinare affatto, questa opzione \u00e8 accettabile: dai un'occhiata al mio progetto <noindex><a rel=\"nofollow\" href=\"https:\/\/jack-vanlightly.com\/blog\/2018\/7\/22\/creating-consumer-groups-in-rabbitmq-with-rebalanser-part-1\">Rebilanciatore<\/a><\/noindex> per suddividere la coda (il progetto \u00e8 ancora in fase iniziale). <\/p>\n<p>Infine, non dimenticate una serie di bug nei meccanismi di clustering e replica sia di RabbitMQ che di Kafka. Col tempo, i sistemi sono diventati pi\u00f9 maturi e stabili, ma nessun messaggio sar\u00e0 mai al 100% protetto dalla perdita! Inoltre, nei data center possono verificarsi disastri su larga scala!<\/p>\n<p>Se ho tralasciato qualcosa, ho commesso un errore o non sei d'accordo con uno qualsiasi dei punti, non esitare a lasciare un commento o contattarmi.<\/p>\n<p>Spesso mi chiedono: \u00abCosa scegliere, Kafka o RabbitMQ?\u00bb, \u00abQual \u00e8 la piattaforma migliore?\u00bb. La verit\u00e0 \u00e8 che dipende davvero dalla tua situazione, esperienza attuale, e cos\u00ec via. Non mi sento di esprimere un'opinione, poich\u00e9 sarebbe troppo riduttivo raccomandare una sola piattaforma per tutte le possibili applicazioni e limitazioni. Ho scritto questo ciclo di articoli affinch\u00e9 possiate formarvi un'opinione personale.<\/p>\n<p>Voglio dire che entrambe le soluzioni sono leader nel loro campo. Forse sono un po' di parte, poich\u00e9 per esperienza personale nei miei progetti, tendo a dare valore a caratteristiche come l'ordinamento garantito dei messaggi e l'affidabilit\u00e0. <\/p>\n<p>Osservo altre tecnologie che mancano di questa affidabilit\u00e0 e ordinamento garantito, poi guardo a RabbitMQ e Kafka \u2014 e comprendo l'incredibile valore di entrambi questi sistemi.<br \/>\n<br \/>Fonte: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/itsumma\/blog\/474984\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0412 \u043f\u0440\u043e\u0448\u043b\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043b\u0438 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0438\u0437\u0430\u0446\u0438\u044e RabbitMQ \u0434\u043b\u044f \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f \u043e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u0438 \u0438 \u0432\u044b\u0441\u043e\u043a\u043e\u0439 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u0438. \u0422\u0435\u043f\u0435\u0440\u044c \u0433\u043b\u0443\u0431\u043e\u043a\u043e \u043f\u043e\u043a\u043e\u043f\u0430\u0435\u043c\u0441\u044f \u0432 Apache Kafka. \u0417\u0434\u0435\u0441\u044c \u0435\u0434\u0438\u043d\u0438\u0446\u0435\u0439 \u0440\u0435\u043f\u043b\u0438\u043a\u0430\u0446\u0438\u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0440\u0430\u0437\u0434\u0435\u043b (partition). \u0423 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0442\u043e\u043f\u0438\u043a\u0430 \u043e\u0434\u0438\u043d \u0438\u043b\u0438 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u043e\u0432. \u0412 \u043a\u0430\u0436\u0434\u043e\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435 \u0435\u0441\u0442\u044c \u043b\u0438\u0434\u0435\u0440 \u0441 \u0444\u043e\u043b\u043b\u043e\u0432\u0435\u0440\u0430\u043c\u0438 \u0438\u043b\u0438 \u0431\u0435\u0437 \u043d\u0438\u0445. \u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0442\u043e\u043f\u0438\u043a\u0430 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0440\u0430\u0437\u0434\u0435\u043b\u043e\u0432 \u0438 \u043a\u043e\u044d\u0444\u0444\u0438\u0446\u0438\u0435\u043d\u0442 \u0440\u0435\u043f\u043b\u0438\u043a\u0430\u0446\u0438\u0438. \u041e\u0431\u044b\u0447\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 3, \u044d\u0442\u043e [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-52541","post","type-post","status-publish","format-standard","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.0.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0412\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/rabbitmq-protiv-kafka-otkazoustojchivost-i-vysokaya-dostupnost\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.0.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"it_IT\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47RabbitMQ \u043f\u0440\u043e\u0442\u0438\u0432 Kafka: \u043e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u044c \u0438 \u0432\u044b\u0441\u043e\u043a\u0430\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u044c | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0412\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/rabbitmq-protiv-kafka-otkazoustojchivost-i-vysokaya-dostupnost\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-11-10T21:00:00+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-02-18T11:00:17+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0 | ProHoster","description":"In","canonical_url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/rabbitmq-protiv-kafka-otkazoustojchivost-i-vysokaya-dostupnost","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"it_IT","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47RabbitMQ \u043f\u0440\u043e\u0442\u0438\u0432 Kafka: \u043e\u0442\u043a\u0430\u0437\u043e\u0443\u0441\u0442\u043e\u0439\u0447\u0438\u0432\u043e\u0441\u0442\u044c \u0438 \u0432\u044b\u0441\u043e\u043a\u0430\u044f \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u044c | ProHoster","og:description":"\u0412","og:url":"https:\/\/prohoster.info\/it\/blog\/administrirovanie\/rabbitmq-protiv-kafka-otkazoustojchivost-i-vysokaya-dostupnost","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-11-10T21:00:00+00:00","article:modified_time":"2020-02-18T11:00:17+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"52541","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-24 03:57:21","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 20:41:24","updated":"2026-01-24 03:57:22","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/52541","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/comments?post=52541"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/posts\/52541\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/media?parent=52541"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/categories?post=52541"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/it\/wp-json\/wp\/v2\/tags?post=52541"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}