{"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: resilienza e alta disponibilit\u00e0","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" 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\/\">un articolo precedente<\/a><\/noindex> Abbiamo esaminato la clusterizzazione di RabbitMQ per garantire la resilienza e l'alta disponibilit\u00e0. Ora approfondiamo Apache Kafka.<\/p>\n<p>In questo contesto, l'unit\u00e0 di replica \u00e8 la partizione. Ogni argomento ha una o pi\u00f9 partizioni. In ogni partizione c'\u00e8 un leader con o senza follower. Quando si crea un argomento, si specifica il numero di partizioni e il fattore di replica. Il valore tipico \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: resilienza e alta disponibilit\u00e0\" src=\"\/wp-content\/uploads\/2019\/11\/36deb6d506223c2ee2ec147d5c215789.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 1. Quattro partizioni 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 collegano mai ai follower; questi ultimi esistono solo per ridondanza e resilienza.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" 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 cade, spesso i leader di diverse partizioni smettono di funzionare. In ognuna di esse, un follower di un altro nodo diventa il nuovo leader. In realt\u00e0, ci\u00f2 non avviene sempre, poich\u00e9 influisce anche il fattore di sincronizzazione: ci sono follower sincronizzati e, se non ci sono, \u00e8 consentito passare a una replica non sincronizzata. Ma non complicchiamo per ora.<\/p>\n<p>Il broker 3 esce dalla rete, e per la partizione 2 viene scelto un nuovo leader sul broker 2.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" 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 scelto come 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: resilienza e alta disponibilit\u00e0\" 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 solo broker con zero ridondanza<\/i><\/p>\n<p>Quando il broker 1 ritorna in rete, aggiunge quattro follower, fornendo una certa ridondanza a ogni partizione. Ma tutti i leader rimangono ancora sul broker 2.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" 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 riavvia, torniamo a tre repliche per partizione. Ma tutti i leader rimangono ancora sul broker 2.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" 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 ha uno strumento per un riequilibrio dei leader di qualit\u00e0 superiore rispetto a RabbitMQ. Qui si doveva utilizzare un plugin o uno script esterno che modificava le politiche per migrare il nodo principale, riducendo la ridondanza durante la migrazione. Inoltre, per code di grandi dimensioni, si doveva accettare l'inaccessibilit\u00e0 durante la sincronizzazione.<\/p>\n<p>Kafka ha un concetto di \"repliche preferite\" per il ruolo di leader. Quando vengono creati i topic, Kafka cerca di distribuire uniformemente i leader tra i nodi e contrassegna questi primi leader come preferiti. Col passare del tempo, a causa del riavvio dei server, guasti e interruzioni 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 riassegnare automaticamente i leader alle repliche preferite, ripristinando cos\u00ec la distribuzione uniforme.\n<\/li>\n<li>L'amministratore pu\u00f2 eseguire lo script <i>kafka-preferred-replica-election.sh<\/i> per effettuare una riassegnazione manuale.<\/li>\n<\/ul>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" src=\"\/wp-content\/uploads\/2019\/11\/831930b06809637018fecb6d7d5a558d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 6. Repliche dopo il ri 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 complicato qui. Tutto si riduce a repliche sincronizzate (In-Sync Replicas, ISR).<\/p>\n<h1>Repliche sincronizzate (ISR)<\/h1>\n<p>\nISR \u00e8 un insieme di repliche di un partizione che \u00e8 considerata \"sincronizzata\". Qui c'\u00e8 un leader, e i follower possono anche non esserci. Un follower \u00e8 considerato sincronizzato se ha fatto copie esatte di tutti i messaggi del leader prima della scadenza dell'intervallo <i>replica.lag.time.max.ms<\/i>.<\/p>\n<p>Un follower viene rimosso dall'insieme di 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 entro l'intervallo <i>replica.fetch.wait.max.ms<\/i>, che per impostazione predefinita \u00e8 di 500 ms.<\/p>\n<p>Per spiegare chiaramente l'obiettivo di ISR, \u00e8 necessario esaminare gli acknowledgments dal produttore e alcuni scenari di guasto. I produttori possono scegliere quando il broker invia un acknowledgment:<\/p>\n<ul>\n<li>acks=0, non viene inviato alcun acknowledgment\n<\/li>\n<li>acks=1, l'acknowledgment viene inviato dopo che il leader ha registrato il messaggio nel proprio log locale\n<\/li>\n<li>acks=all, l'acknowledgment viene inviato dopo che tutte le repliche in ISR hanno registrato il messaggio nei log locali<\/li>\n<\/ul>\n<p>\nNella terminologia di Kafka, se l'ISR ha salvato un messaggio, avviene il suo \u00abcommit\u00bb. Acks=all \u00e8 l'opzione pi\u00f9 sicura, ma comporta anche un'ulteriore latenza. Consideriamo due esempi di guasto e come le diverse opzioni '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 aspetta di ricevere ogni messaggio da tutti i follower, allora in caso di guasto del leader potrebbero esserci perdite di dati. Il passaggio a un follower non sincronizzato pu\u00f2 essere consentito o vietato tramite configurazione. <i>unclean.leader.election.enable<\/i>.<\/p>\n<p>In questo esempio, il produttore ha impostato il valore di 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 solo di un secondo. Il nostro produttore invia un messaggio e riceve rapidamente un ack, senza overhead per follower lenti o morti, che il leader non sta aspettando.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" 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 si guasta e il produttore riceve un errore di connessione. Dopo il passaggio di 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 questo \u00e8 crollato.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" src=\"\/wp-content\/uploads\/2019\/11\/367f219daebafefe585059f67fdedf6f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 8. Messaggi persi in caso di guasto<\/i><\/p>\n<p>Nella configurazione <i>bootstrap.servers<\/i> il produttore elenca 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: resilienza e alta disponibilit\u00e0\" 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. Fa richieste di fetch, ma non riesce a sincronizzarsi. Questo potrebbe essere dovuto a una connessione di rete lenta tra i broker, problemi di archiviazione, ecc. Viene rimosso dall'ISR. Ora l'ISR \u00e8 composto da una sola replica: il leader! Il produttore continua a inviare messaggi e ricevere conferme.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" 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 crolla e il ruolo di leader passa al broker 3 con una perdita di 15286 messaggi! Il produttore riceve un messaggio di errore di connessione. Il passaggio al leader fuori dall'ISR \u00e8 stato possibile solo a causa della configurazione <i>unclean.leader.election.enable=true<\/i>. Se \u00e8 impostato su <i>false<\/i>, il passaggio non sarebbe avvenuto e tutte le richieste di lettura e scrittura sarebbero state rifiutate. In questo 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: resilienza e alta disponibilit\u00e0\" src=\"\/wp-content\/uploads\/2019\/11\/30f01ca715ccc194890ae061a3ef7396.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 11. Il broker 1 si guasta. In caso di guasto 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 sezione. Inizia a inviare messaggi al broker 3.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" src=\"\/wp-content\/uploads\/2019\/11\/986532d9b22b6514b6039c8460b1beb4.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 12. Dopo una breve pausa, i messaggi vengono nuovamente inviati nella sezione 0<\/i><\/p>\n<p>Abbiamo visto che, oltre ai brevi intervalli per stabilire nuove connessioni e cercare un nuovo leader, il produttore inviava continuamente messaggi. Questa configurazione garantisce la 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 ritardo del broker 3 \u00e8 in media di quattro secondi. Il produttore invia un messaggio con <i>acks=all<\/i>, e ora non riceve una risposta rapida. Il leader attende che il messaggio venga memorizzato da tutte le repliche in ISR.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" src=\"\/wp-content\/uploads\/2019\/11\/95b1abdc92e699f7bc41ebab249a2e08.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 13. ISR con tre repliche. Una \u00e8 lenta, causando un ritardo nella registrazione<\/i><\/p>\n<p>Dopo quattro secondi di ulteriore ritardo, il broker 2 invia ack. Tutte le repliche sono ora completamente aggiornate.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" 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 e viene rimosso da ISR. Il ritardo diminuisce notevolmente, poich\u00e9 non ci sono pi\u00f9 repliche lente in ISR. Il broker 2 ora aspetta solo il broker 1, che ha un lag medio di 500 ms.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" src=\"\/wp-content\/uploads\/2019\/11\/5d3bd67dc53cb868fa40b358ed483a1d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 15. La replica sul broker 3 viene rimossa da ISR<\/i><\/p>\n<p>Poi il broker 2 viene a mancare e la leadership passa al broker 1 senza perdita di messaggi.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" src=\"\/wp-content\/uploads\/2019\/11\/e3f0417aa7714ea5eae8a8e8d61662bd.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 16. Il broker 2 va in crash<\/i><\/p>\n<p>Il produttore trova un nuovo leader e inizia a inviargli messaggi. Il ritardo diminuisce ulteriormente, poich\u00e9 ora ISR consiste in una sola replica! Quindi l'opzione <i>acks=all<\/i> non aggiunge ridondanza.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" src=\"\/wp-content\/uploads\/2019\/11\/fec9aae9977757d5f61c2909ceae0536.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 17. La replica sul broker 1 assume la leadership senza perdita di messaggi<\/i><\/p>\n<p>Poi il broker 1 va a mancare e la leadership passa al broker 3 con una perdita di 14238 messaggi!<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" 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 l'impostazione unclean porta a una vasta perdita di dati<\/i><\/p>\n<p>Potremmo non impostare l'opzione <i>unclean.leader.election.enable<\/i> a valore <i>true<\/i>. Per impostazione predefinita \u00e8 <i>false<\/i>. L'impostazione <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 vedete, possiamo comunque perdere 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 protegger\u00e0 necessariamente dalla perdita di dati. Se il leader crolla in modo grave e porta via i dati, i messaggi andranno comunque persi, oltre a rendere inaccessibile il sistema finch\u00e9 l'amministratore non ripristina la situazione.<\/p>\n<p>\u00c8 meglio garantire la ridondanza di tutti i messaggi, altrimenti \u00e8 consigliabile astenersi dalla registrazione. In questo modo, 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. Esaminiamo nuovamente 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, mentre il follower sul broker 3 \u00e8 rimosso dall'ISR.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" src=\"\/wp-content\/uploads\/2019\/11\/5831463293f1837d3232756894e97162.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 19. ISR composto da due repliche<\/i><\/p>\n<p>Il broker 2 crolla e la leadership passa al broker 1 senza perdita di messaggi. Ma ora l'ISR \u00e8 composto solo da una replica. Ci\u00f2 non soddisfa il numero minimo per la registrazione, e quindi il broker risponde a un tentativo di registrazione con un errore. <i>NotEnoughReplicas<\/i>.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" 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 specificato 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. Ci\u00f2 fornisce al produttore una maggiore sicurezza. Qui, la perdita di messaggi \u00e8 possibile solo in caso di guasto simultaneo di due repliche in un breve intervallo di tempo, finch\u00e9 il messaggio non \u00e8 stato replicato a un ulteriore follower, il che \u00e8 improbabile. Ma se sei superparanoico, puoi impostare il fattore di replicazione a 5, e <i>min.insync.replicas<\/i> a 3. In questo caso, devono crollare simultaneamente tre broker per perdere una registrazione! Naturalmente, per tale affidabilit\u00e0 pagherai un ulteriore ritardo.<\/p>\n<h1>Quando la disponibilit\u00e0 \u00e8 necessaria per la sicurezza dei dati<\/h1>\n<p>\nCome nel <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 questo:<\/p>\n<ul>\n<li>Pu\u00f2 il publisher semplicemente restituire un errore, e il servizio superiore o l'utente riprovare in seguito?\n<\/li>\n<li>Il publisher pu\u00f2 salvare il messaggio localmente o nel database per riprovare pi\u00f9 tardi?<\/li>\n<\/ul>\n<p>\nSe la risposta \u00e8 negativa, allora l'ottimizzazione della disponibilit\u00e0 aumenta la sicurezza dei dati. Perderai meno dati se scegli la disponibilit\u00e0 rispetto al rifiuto della registrazione. In questo modo, si tratta di trovare un equilibrio, e la decisione dipende dalla situazione specifica.<\/p>\n<h1>Il senso di ISR<\/h1>\n<p>\nIl set ISR consente di scegliere il miglior equilibrio tra sicurezza dei dati e latenza. Ad esempio, garantire la disponibilit\u00e0 in caso di malfunzionamento 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 durante <i>acks=all<\/i>. Il valore predefinito \u00e8 dieci secondi. Se per te \u00e8 troppo lungo, puoi ridurlo. Tuttavia, 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 semplicemente un insieme di specchi che devono essere replicati. Gli specchi lenti introducono una latenza aggiuntiva, e per gli specchi morti si pu\u00f2 attendere 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 della latenza. Ma rischiamo di perdere ridondanza, poich\u00e9 l'ISR pu\u00f2 ridursi solo al leader. Per evitare questo rischio, utilizza la configurazione <i>min.insync.replicas<\/i>.<\/p>\n<h1>La garanzia di connessione dei clienti<\/h1>\n<p>\nNelle impostazioni <i>bootstrap.servers<\/i> produttore e consumatore pu\u00f2 specificare pi\u00f9 broker per la connessione dei clienti. L'idea \u00e8 che, se un nodo si disconnette, rimangano diversi backup a cui il cliente pu\u00f2 collegarsi. Non devono necessariamente essere i leader delle partizioni, ma semplicemente un punto di riferimento per il caricamento iniziale. Il cliente pu\u00f2 chiedere loro dove risiede il leader di partizione per lettura\/scrittura.<\/p>\n<p>In RabbitMQ, i clienti possono connettersi a qualsiasi nodo, e il routing interno invia la richiesta dove necessario. Questo significa che puoi posizionare un bilanciatore di carico davanti a RabbitMQ. Kafka richiede che i clienti si connettano al nodo in cui si trova il leader della rispettiva partizione. In tal caso, non \u00e8 possibile installare un bilanciatore di carico. L'elenco <i>bootstrap.servers<\/i> \u00e8 cruciale affinch\u00e9 i clienti possano accedere ai nodi necessari e trovarli dopo un guasto.<\/p>\n<h1>L'architettura di consenso di Kafka<\/h1>\n<p>\nFino a ora non abbiamo considerato come il cluster apprenda il guasto di un broker e come venga scelto un nuovo leader. Per comprendere come Kafka gestisce le divisioni di rete, \u00e8 necessario prima capire l'architettura di consenso.<\/p>\n<p>Ogni cluster Kafka viene distribuito insieme a un cluster Zookeeper, che \u00e8 un servizio di consenso distribuito che consente al sistema di raggiungere consenso su uno stato specifico, dando priorit\u00e0 alla coerenza piuttosto che alla disponibilit\u00e0. Per approvare le operazioni di lettura e scrittura \u00e8 necessario il consenso della maggioranza dei nodi Zookeeper.<\/p>\n<p>Zookeeper memorizza lo stato del cluster:<\/p>\n<ul>\n<li>Elenco dei topic, partizioni, configurazione, repliche leader correnti, repliche preferenziali.\n<\/li>\n<li>Membri del cluster. Ogni broker invia un ping al cluster Zookeeper. Se non riceve un ping entro un determinato periodo di tempo, Zookeeper registra il broker come non disponibile.\n<\/li>\n<li>Scelta dei nodi principale e secondario per il controller.<\/li>\n<\/ul>\n<p>\nIl nodo controller \u00e8 uno dei broker Kafka che \u00e8 responsabile dell'elezione dei leader delle repliche. Zookeeper invia al controller notifiche sui cambiamenti della membership nel cluster e dei 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 ogni partizione, cercando di ottimizzare la distribuzione dei leader tra i broker. <\/p>\n<p>Per ogni partizione, il controller:<\/p>\n<ul>\n<li>aggiorna le informazioni in Zookeeper su 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 che \u00e8 leader si guasta, Zookeeper invia una notifica al controller, che sceglie un nuovo leader. Anche in questo caso, il controller prima aggiorna Zookeeper e poi invia un comando a ogni broker, notificandoli del cambiamento di leadership.<\/p>\n<p>Ogni leader \u00e8 responsabile del set ISR. La configurazione <i>replica.lag.time.max.ms<\/i> determina chi ne far\u00e0 parte. Quando ISR cambia, il leader comunica a Zookeeper le nuove informazioni.<\/p>\n<p>Zookeeper \u00e8 sempre informato di qualsiasi cambiamento, in modo che in caso di guasto la leadership possa passare senza problemi a un nuovo leader.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" 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 replicazione<\/h1>\n<p>\nComprendere i dettagli della replicazione aiuta a capire meglio i potenziali scenari di perdita di dati.<\/p>\n<h3>Richieste di estrazione, Log End Offset (LEO) e Highwater Mark (HW)<\/h3>\n<p>\nAbbiamo esaminato come i follower inviano periodicamente al leader richieste di recupero (fetch). L'intervallo predefinito \u00e8 di 500 ms. Questo si differenzia da RabbitMQ, in quanto in RabbitMQ la replica \u00e8 avviata non da uno specchio della coda, ma dal master. Il master invia le modifiche agli specchi.<\/p>\n<p>Il leader e tutti i follower mantengono l'offset della fine del log (Log End Offset, LEO) e il marcatore Highwater (HW). Il marcatore LEO conserva 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 memorizzato in tutte le repliche ISR. Questo significa che LEO di solito precede leggermente HW.<\/p>\n<p>Quando il leader riceve un messaggio, lo memorizza localmente. Il follower invia una richiesta di recupero, passando il proprio LEO. Il leader quindi invia un pacchetto di messaggi, a partire da questo LEO, e fornisce anche l'attuale HW. Quando il leader riceve notizie che tutte le repliche hanno memorizzato il messaggio con l'offset specificato, sposta il marcatore HW. Solo il leader pu\u00f2 spostare HW, e cos\u00ec tutti i follower apprendono il valore attuale nelle risposte alle loro richieste. Ci\u00f2 significa che i follower possono rimanere indietro rispetto al leader sia nei messaggi che nella conoscenza di HW. I consumatori ricevono messaggi solo fino al corrente HW.<\/p>\n<p>Si noti che 'persistito' (persisted) significa memorizzato in memoria, non su disco. Per motivi di prestazioni, Kafka esegue la sincronizzazione su disco a intervalli prestabiliti. Anche RabbitMQ ha tale intervallo, ma confermer\u00e0 il publisher solo dopo che il master e tutti gli specchi hanno memorizzato il messaggio su disco. I programmatori di Kafka, per motivi di prestazioni, hanno deciso di inviare ack non appena il messaggio \u00e8 memorizzato in memoria. Kafka scommette che la ridondanza compenser\u00e0 il rischio di conservare temporaneamente i messaggi confermati solo in memoria.<\/p>\n<h1>Guasto del leader<\/h1>\n<p>\nQuando il leader cade, Zookeeper avvisa il controller, che sceglie una nuova replica leader. Il nuovo leader stabilisce un nuovo marcatore HW in base al proprio LEO. Le informazioni sul nuovo leader vengono quindi trasmesse ai follower. A seconda della versione di Kafka, il follower sceglier\u00e0 uno dei due scenari:<\/p>\n<ol>\n<li>Tronca il log locale fino all'HW noto e invia al nuovo leader una richiesta di messaggi successivi a questo marcatore.\n<\/li>\n<li>Invia una richiesta al leader per conoscere l'HW al momento della sua elezione, quindi tronca il log a quel punto. Inizier\u00e0 quindi a effettuare richieste periodiche per il campionamento, a partire da questo offset.<\/li>\n<\/ol>\n<p>\nIl follower potrebbe dover troncare il log per le seguenti ragioni:<\/p>\n<ul>\n<li>Quando si verifica un guasto del leader, il primo follower del set ISR registrato in Zookeeper vince le elezioni e diventa il leader. Tutti i follower in ISR, sebbene considerati \"sincronizzati\", potrebbero non aver ricevuto copie di tutti i messaggi dal precedente leader. \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 troncare il proprio log fino al valore HW del nuovo leader al momento della sua elezione. Questo \u00e8 un ulteriore motivo per cui la configurazione <i>acks=all<\/i> \u00e8 cos\u00ec importante per la coerenza.\n<\/li>\n<li>I messaggi vengono periodicamente scritti su disco. Se tutti i nodi del cluster falliscono contemporaneamente, sui dischi saranno salvate repliche con offset diversi. \u00c8 possibile che quando i broker tornano in rete, il nuovo leader, che verr\u00e0 eletto, risulti indietro rispetto ai suoi follower, poich\u00e9 si \u00e8 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 nel caso di un guasto del leader: controllano la replica del leader e troncano il proprio log fino al suo HW (al momento dell'elezione). A differenza, 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 corrente in un nuovo specchio in modalit\u00e0 \"e lasciamo 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 registro distribuito e, in generale, conserva pi\u00f9 messaggi di una coda RabbitMQ, dove i dati vengono rimossi dalla coda dopo la lettura. Le code attive devono rimanere relativamente piccole. Ma Kafka \u00e8 un registro con una propria politica di conservazione, che pu\u00f2 stabilire un termine di giorni o settimane. L'approccio con il blocco della coda e la sincronizzazione completa \u00e8 assolutamente inaccettabile per un registro distribuito. Invece, i follower di Kafka semplicemente accorciano il loro registro fino all'HW leader (al momento della sua elezione) nel caso in cui la loro copia superi il leader. Nel caso pi\u00f9 probabile, in cui il follower \u00e8 in ritardo, inizia semplicemente a fare richieste di polling, a partire dal proprio attuale LEO.<\/p>\n<p>I nuovi follower o quelli ricostituiti iniziano al di fuori dell'ISR e non partecipano ai commit. Lavorano semplicemente a fianco del gruppo, ricevendo i messaggi il pi\u00f9 velocemente possibile, finch\u00e9 non raggiungono il leader e non entrano nell'ISR. Non ci sono blocchi e non \u00e8 necessario scartare tutti i propri dati.<\/p>\n<h1>Violazione della coerenza<\/h1>\n<p>\nKafka ha pi\u00f9 componenti rispetto a RabbitMQ, quindi qui c'\u00e8 un insieme di comportamenti pi\u00f9 complesso quando la connettivit\u00e0 nel cluster viene compromessa. Ma Kafka \u00e8 stato progettato fin dall'inizio per i cluster, quindi le soluzioni sono molto ben ponderate.<\/p>\n<p>Di seguito sono riportati alcuni scenari di violazione della 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 nessun 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 che da Zookeeper.\n<\/li>\n<li>Scenario 6. Il leader \u00e8 completamente isolato sia dagli altri nodi Kafka che 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>\nOgni scenario prevede 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: resilienza e alta disponibilit\u00e0\" 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 violazione della connettivit\u00e0 isola il broker 3 dai broker 1 e 2, ma non da Zookeeper. Il broker 3 non pu\u00f2 pi\u00f9 inviare richieste di polling. Al termine del 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 polling e si unir\u00e0 all'ISR quando raggiunger\u00e0 il leader. Zookeeper continuer\u00e0 a ricevere i ping e considerer\u00e0 che il broker sia vivo e vegeto.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" 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 polling 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. Invece, si riduce la ridondanza. <\/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: resilienza e alta disponibilit\u00e0\" src=\"\/wp-content\/uploads\/2019\/11\/ff6aaa053d73e8b7c97111979bcf97aa.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 24. Scenario 2. Il leader e due follower<\/i><\/p>\n<p>Una perdita di 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 polling. Ancora una volta, non c'\u00e8 alcuna separazione logica. Si verifica invece una perdita di ridondanza per i nuovi messaggi, fino a quando la connettivit\u00e0 non viene ripristinata. Zookeeper continua a ricevere i ping e considera che il broker sia vivo e vegeto.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" src=\"\/wp-content\/uploads\/2019\/11\/3c69e8327da241407f76719fc022c37a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 25. Scenario 2. L'ISR si \u00e8 compresso solo al leader<\/i><\/p>\n<h3>Scenario 3. Il follower vede il leader, ma non vede Zookeeper<\/h3>\n<p>\nIl follower \u00e8 separato da Zookeeper, ma non dal broker con il leader. Di conseguenza, il follower continua a fare richieste di polling e a essere membro dell'ISR. Zookeeper non riceve pi\u00f9 ping e registra il crash del broker, ma poich\u00e9 \u00e8 solo un follower, non ci sono conseguenze dopo il ripristino.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" 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: resilienza e alta disponibilit\u00e0\" 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: resilienza e alta disponibilit\u00e0\" 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 scritture con <i>acks=1<\/i>. I follower non gli inviano pi\u00f9 richieste di polling, quindi li considerer\u00e0 morti e cercher\u00e0 di comprimere l'ISR fino a se stesso. Ma poich\u00e9 non ha alcuna connessione con Zookeeper, non sar\u00e0 in grado di farlo, e a quel punto rinuncer\u00e0 a ricevere ulteriori scritture. <\/p>\n<p>Messaggi <i>acks=all<\/i> non riceveranno conferma, perch\u00e9 inizialmente ISR include tutte le repliche, e i messaggi non arrivano a loro. Quando il leader originale cercher\u00e0 di rimuoverli dall'ISR, non sar\u00e0 in grado di farlo e smetter\u00e0 di ricevere qualsiasi messaggio.<\/p>\n<p>I clienti si accorgono presto del cambio di leader e iniziano a inviare registrazioni al nuovo server. Non appena la rete si ripristina, 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 divergenze nei log. In seguito, inizier\u00e0 a inviare richieste di accesso al nuovo leader. Tutte le registrazioni del leader originale, non replicate al nuovo leader, andranno perse. Ci\u00f2 significa che andranno persi i messaggi non confermati dal leader originale in quei pochi secondi in cui c'erano due leader.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" 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 la ripresa 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 ripristina, per poi recuperare gli altri.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" src=\"\/wp-content\/uploads\/2019\/11\/b092607f777014fd945f18734dd7f4e7.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 30. Scenario 5. Il follower isolato viene rimosso dall'ISR<\/i><\/p>\n<h3>Scenario 6. Il leader \u00e8 completamente isolato sia dagli altri nodi Kafka che da Zookeeper<\/h3>\n<p>\n<img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" src=\"\/wp-content\/uploads\/2019\/11\/bb808d534dbf65748eb0b481f86b4926.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 31. Scenario 6. Leader e due follower<\/i><\/p>\n<p>Il leader \u00e8 completamente isolato dai suoi follower, dal controller e da Zookeeper. Per un breve periodo continuer\u00e0 a ricevere registrazioni con <i>acks=1<\/i>.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" src=\"\/wp-content\/uploads\/2019\/11\/6fda78bcd26ef6b916579d447e9fb1f0.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 32. Scenario 6. Isolamento del leader dagli altri nodi Kafka e Zookeeper<\/i><\/p>\n<p>Non ricevendo richieste trascorso <i>replica.lag.time.max.ms<\/i>, tenter\u00e0 di comprimere l'ISR fino a se stesso, ma non potr\u00e0 farlo poich\u00e9 non c'\u00e8 connessione con Zookeeper, quindi smetter\u00e0 di ricevere registrazioni. <\/p>\n<p>Nel frattempo, Zookeeper segnaler\u00e0 il broker isolato come morto, e il controller sceglier\u00e0 un nuovo leader.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" src=\"\/wp-content\/uploads\/2019\/11\/73d611a411fc64d835af2c714e9eba0a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 33. Scenario 6. Due leader<\/i><\/p>\n<p>Il leader originale pu\u00f2 ricevere registrazioni per alcuni secondi, ma poi smette di ricevere qualsiasi messaggio. I clienti si aggiornano ogni 60 secondi con gli ultimi metadati. Saranno informati del cambio di leader e inizieranno a inviare registrazioni al nuovo leader.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" src=\"\/wp-content\/uploads\/2019\/11\/ae99380c8a84fac15f440b699b9c552b.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 34. Scenario 6. I produttori si spostano sul nuovo leader<\/i><\/p>\n<p>Tutte le registrazioni confermate fatte dal leader iniziale dal momento della perdita di connettivit\u00e0 andranno perse. Una volta ripristinata la rete, il leader iniziale tramite Zookeeper scoprir\u00e0 di non essere pi\u00f9 il leader. Quindi tratter\u00e0 il suo registro fino all'HW del nuovo leader al momento dell'elezione e inizier\u00e0 a inviare richieste come follower.<\/p>\n<p><img decoding=\"async\" alt=\"RabbitMQ contro Kafka: resilienza e alta disponibilit\u00e0\" src=\"\/wp-content\/uploads\/2019\/11\/10f0983a829b03ca9bbc62e12cbf8a5d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Fig. 35. Scenario 6. Il leader iniziale diventa follower dopo il ripristino della connettivit\u00e0 di rete.<\/i><\/p>\n<p>In questa situazione, per un breve periodo si pu\u00f2 osservare una divisione logica, ma solo se <i>acks=1<\/i> e <i>min.insync.replicas<\/i> anch'essa 1. La divisione logica si conclude automaticamente o dopo il ripristino della rete, quando il leader iniziale si rende conto di non essere pi\u00f9 il leader, oppure quando tutti i client comprendono che il leader \u00e8 cambiato e iniziano a scrivere al nuovo leader, a seconda di ci\u00f2 che accade prima. In ogni caso ci sar\u00e0 la perdita di alcuni messaggi, ma solo con <i>acks=1<\/i>.<\/p>\n<p>C'\u00e8 un'altra variante di questo scenario, quando direttamente prima della divisione della rete i follower sono rimasti indietro e il leader ha ristretto 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 oltre a lui. Queste registrazioni andranno perse dopo il ripristino della rete. L'unico modo per evitare questa variante \u00e8 <i>min.insync.replicas = 2<\/i>.<\/p>\n<h3>Scenario 7. Il nodo controller 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 inviare alcuna informazione riguardante il cambio di leader. Nel peggiore dei casi, ci\u00f2 porter\u00e0 a una breve divisione logica, come nello scenario 6. Nella maggior parte dei casi, il broker non diventer\u00e0 semplicemente un candidato alla leadership in caso di fallimento dell'ultimo.<\/p>\n<h3>Scenario 8. Il controller Kafka non vede Zookeeper.<\/h3>\n<p>\nDallo Zookeeper isolato, il controller non ricever\u00e0 ping e sceglier\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 compiti da svolgere. Una volta ripristinata la rete, capir\u00e0 di non essere pi\u00f9 un controller, ma di essere diventato un nodo Kafka normale.<\/p>\n<h3>Conclusioni sugli scenari<\/h3>\n<p>\nOsserviamo che la perdita di connessione dei follower non porta alla perdita di messaggi, ma riduce temporaneamente la ridondanza finch\u00e9 la rete non si ripristina. Questo, ovviamente, pu\u00f2 causare la perdita di dati se uno o pi\u00f9 nodi vengono persi.<\/p>\n<p>Se a causa della perdita di connessione il leader si disconnette da Zookeeper, questo pu\u00f2 portare alla perdita di messaggi con <i>acks=1<\/i>. La mancanza di connessione a Zookeeper causa una temporanea divisione logica con due leader. Questo problema \u00e8 risolvibile tramite il parametro <i>acks=all<\/i>.<\/p>\n<p>Parametro <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 nel caso 6.<\/p>\n<h1>Riepilogo sulla perdita di messaggi<\/h1>\n<p>\nElenciamo tutti i modi in cui \u00e8 possibile perdere dati in Kafka:<\/p>\n<ul>\n<li>Qualsiasi guasto del leader, se i messaggi sono stati confermati tramite <i>acks=1<\/i>\n<\/li>\n<li>Qualsiasi passaggio di leadership sporco (unclean), quindi su 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 sono stati 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. Verranno persi tutti i messaggi, 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 stati registrati su disco. Dopo il riavvio dei server, potrebbero mancare alcuni messaggi.<\/li>\n<\/ul>\n<p>\nI passaggi di leadership sporchi possono essere evitati, sia vietandoli sia garantendo almeno una ridondanza di due. La configurazione pi\u00f9 robusta \u00e8 una combinazione di <i>acks=all<\/i> e <i>min.insync.replicas<\/i> superiore a 1.<\/p>\n<h1>Confronto diretto tra l'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 punto debole. Quando si riconnettono dopo un guasto, i nodi scartano i loro dati e la sincronizzazione viene bloccata. Questo doppio colpo mette in discussione la longevit\u00e0 delle grandi code in RabbitMQ. Dovrai accontentarti di una riduzione della ridondanza o di lunghi blocchi. La riduzione della ridondanza aumenta il rischio di una massiccia perdita di dati. Ma se le code sono piccole, la ridondanza con brevi periodi di inattivit\u00e0 (qualche secondo) pu\u00f2 essere gestita attraverso tentativi di riconnessione.<\/p>\n<p>In Kafka non esiste questo problema. Scarta i dati solo dal punto di divergenza tra il leader e il follower. Tutti i dati comuni vengono mantenuti. Inoltre, la replica non blocca il sistema. Il leader continua ad accettare registrazioni mentre il nuovo follower lo raggiunge, rendendo l'aggiunta o il reinserimento del cluster un compito banale per gli sviluppatori DevOps. Certo, ci sono ancora problemi come la larghezza di banda di rete durante la replica. Se vengono aggiunti pi\u00f9 follower contemporaneamente, si pu\u00f2 incontrare il limite della larghezza di banda.<\/p>\n<p>RabbitMQ supera Kafka in affidabilit\u00e0 nel caso di guasti simultanei di pi\u00f9 server nel cluster. Come gi\u00e0 detto, RabbitMQ invia una conferma al publisher solo dopo che il messaggio \u00e8 stato scritto su disco dal master e da tutti i mirror. Ma questo aggiunge una latenza aggiuntiva per due motivi:<\/p>\n<ul>\n<li>fsync ogni poche centinaia di millisecondi\n<\/li>\n<li>I guasti dei mirror possono essere rilevati solo trascorrendo il tempo di vita dei pacchetti che controllano la disponibilit\u00e0 di ciascun nodo (net tick). Se un mirror rallenta o \u00e8 caduto, ci\u00f2 aggiunge latenza.<\/li>\n<\/ul>\n<p>\nKafka punta sul fatto che se un messaggio \u00e8 memorizzato su pi\u00f9 nodi, i messaggi possono essere confermati non appena arrivano in memoria. Questo comporta il rischio di perdita di messaggi di qualsiasi tipo (anche <i>acks=all<\/i>, <i>min.insync.replicate=2<\/i>) in caso di guasto simultaneo.<\/p>\n<p>In generale, Kafka dimostra prestazioni pi\u00f9 elevate e inizialmente \u00e8 progettato per cluster. Il numero di follower pu\u00f2 aumentare fino a 11, se necessario per l'affidabilit\u00e0. Un rapporto di replica di 5 e il 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 rapporto di replica e livello di ridondanza, puoi scegliere questa opzione.<\/p>\n<p>La clusterizzazione di RabbitMQ \u00e8 buona per piccole code. Ma anche piccole code possono crescere rapidamente con un alto volume di traffico. Una volta che 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 comuni, dove i vantaggi della flessibilit\u00e0 di RabbitMQ superano eventuali svantaggi della sua clusterizzazione.<\/p>\n<p>Uno dei rimedi per la vulnerabilit\u00e0 di RabbitMQ riguardo alle code di grandi dimensioni \u00e8 suddividerle in molteplici pi\u00f9 piccole. Se non \u00e8 necessario mantenere un ordinamento completo di tutta la coda, ma solo dei messaggi rilevanti (ad esempio, messaggi di un cliente specifico), oppure non ordinare affatto, questa soluzione \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\">Ribilanciatore<\/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. Con il tempo, i sistemi sono diventati pi\u00f9 maturi e stabili, ma nessun messaggio sar\u00e0 mai completamente protetto dalla perdita! Inoltre, nei data center si verificano eventi catastrofici su vasta scala!<\/p>\n<p>Se ho trascurato qualcosa, commesso errori o non siete d'accordo con uno qualsiasi dei punti, non esitate a lasciare un commento o a contattarmi.<\/p>\n<p>Mi viene spesso chiesto: \u00abCosa scegliere, Kafka o RabbitMQ?\u00bb, \u00abQuale piattaforma \u00e8 migliore?\u00bb. La verit\u00e0 \u00e8 che dipende davvero dalla vostra situazione, dall'esperienza attuale, ecc. Non mi sento di esprimere un'opinione, poich\u00e9 sarebbe un'eccessiva semplificazione raccomandare una piattaforma unica per tutti gli usi e le possibili limitazioni. Ho scritto questo ciclo di articoli affinch\u00e9 possiate formarvi un'opinione personale.<\/p>\n<p>Voglio dire che entrambi i sistemi sono leader in questo campo. Forse sono un po' di parte, perch\u00e9 per esperienza nei miei progetti tendo a valutare di pi\u00f9 aspetti come l'ordinamento garantito dei messaggi e l'affidabilit\u00e0. <\/p>\n<p>Vedo altre tecnologie che mancano di questa affidabilit\u00e0 e di un 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.2 - 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.2\" \/>\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: tolleranza ai guasti 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}]}}