2014-11-24 18 views
7

Qualcuno può spiegare cosa sta succedendo dietro le quinte in un cluster RabbitMQ con più nodi e code in modo speculare quando si pubblica su un nodo slave?RabbitMQ comportamento delle code di mirroring e dei mirror dietro le quinte

Da quello che ho letto, sembra che tutte le azioni diverse da quelle pubblicate vadano solo al master e il master trasmette quindi l'effetto delle azioni agli schiavi (questo è dalla documentazione). Formando la mia comprensione significa che un consumatore consumerà sempre il messaggio dalla coda principale. Inoltre, se invio una richiesta a uno slave per il consumo di un messaggio, lo slave eseguirà un salto extra raggiungendo il master per il recupero di quel messaggio.

Ma cosa succede quando pubblico su un nodo slave? Questo nodo farà la stessa cosa di inviare prima il messaggio al master?

Sembra che ci siano così tanti salti in più quando si ha a che fare con gli schiavi, quindi sembra che potresti avere prestazioni migliori se conosci solo il master. Ma come gestisci il master failure? Allora uno degli schiavi sarà eletto padrone, quindi devi sapere dove connetterti?

Chiedere tutto questo perché stiamo usando il cluster RabbitMQ con HAProxy in primo piano, in modo da poter disaccoppiare la struttura del cluster dalle nostre app. In questo modo, ogni volta che un nodo viene terminato, l'HAProxy si reindirizzerà ai nodi viventi. Ma abbiamo problemi quando uccidiamo uno dei nodi del coniglio. La connessione a coniglio è permanente, quindi se fallisce, devi ricrearla. Inoltre, devi inviare nuovamente i messaggi in questo caso, altrimenti li perderai.

Anche con tutto questo, i messaggi possono ancora essere persi, perché potrebbero essere in transito quando uccido un nodo (in alcuni buffer, da qualche parte sulla rete, ecc.). Pertanto, è necessario utilizzare le transazioni o confermare l'editore, che garantisce la consegna dopo che tutti i mirror sono stati riempiti con il messaggio. Ma qui un altro problema. Potresti avere messaggi duplicati, perché il broker potrebbe aver inviato una conferma che non ha mai raggiunto il produttore (a causa di errori di rete, ecc.). Pertanto, le applicazioni consumer dovranno eseguire la deduplicazione o gestire i messaggi in arrivo in modo idempotente.

C'è un modo per evitarlo? O devo decidere se posso perdere un paio di messaggi rispetto alla duplicazione di alcuni messaggi?

risposta

14

Qualcuno può spiegare cosa sta succedendo dietro le quinte in un cluster RabbitMQ con più nodi e code in modo speculare quando si pubblica su un nodo slave?

This il blog delinea esattamente ciò che accade.

Ma cosa succede quando pubblico su un nodo slave? Questo nodo farà la stessa cosa di inviare prima il messaggio al master?

Il messaggio verrà reindirizzato alla coda principale, ovvero il nodo su cui è stata creata la coda.

Ma come si gestisce l'errore principale? Allora uno degli schiavi sarà eletto padrone, quindi devi sapere dove connetterti?

Ancora, questo è coperto here. In sostanza, è necessario un servizio separato che esegue il polling su RabbitMQ e determina se i nodi sono vivi o meno. RabbitMQ fornisce uno management API per questo.Le tue applicazioni di pubblicazione e consumo devono fare riferimento a questo servizio direttamente o tramite un archivio dati reciproco al fine di determinare il nodo corretto da pubblicare o utilizzare.

La connessione a coniglio è permanente, quindi se fallisce, è necessario ricrearla. Inoltre, devi inviare nuovamente i messaggi in questo caso, altrimenti li perderai.

È necessario abbonarsi agli eventi interrotti dalla connessione per rispondere alle connessioni interrotte. Sarà necessario creare un certo livello di ridondanza sul client per garantire che i messaggi non vadano persi. Suggerisco, come sopra, di introdurre un servizio specificamente progettato per interrogare RabbitMQ. Il client può tentare di pubblicare un messaggio sull'ultima connessione attiva nota e, in caso di esito negativo, il client potrebbe chiedere al servizio di monitoraggio di visualizzare un elenco aggiornato del cluster RabbitMQ. Supponendo che ci sia almeno un nodo attivo, il client può quindi stabilire una connessione ad esso e pubblicare il messaggio con successo.

Anche con tutto questo, i messaggi possono ancora essere perso, perché possono essere in transito quando mi uccidere un nodo

Ci sono alcuni edge-casi che non si può coprire con la ridondanza, e nemmeno RabbitMQ. Ad esempio, quando un messaggio viene inserito in una coda e il criterio HA richiama un processo in background per copiare il messaggio in un nodo di backup. Durante questo processo, è possibile che il messaggio venga perso prima che venga mantenuto nel nodo di backup. Se il nodo attivo dovesse fallire immediatamente, il messaggio andrebbe perso definitivamente. Non c'è nulla che possa essere fatto al riguardo. Sfortunatamente, quando arriviamo al livello di byte effettivi che viaggiano attraverso il filo, c'è un limite alla quantità di salvaguardie che possiamo costruire.

Le applicazioni consumer devono pertanto eseguire la deduplicazione o gestire i messaggi in arrivo in modo idempotente.

È possibile gestire questo numero di modi. Ad esempio, impostando message-ttl su un valore relativamente basso si assicura che i messaggi duplicati non rimangano sulla coda per lunghi periodi di tempo. È inoltre possibile taggare ciascun messaggio con un riferimento univoco e verificare tale riferimento a livello di consumatore. Ovviamente, ciò richiederebbe l'archiviazione di una cache di messaggi elaborati per confrontare i messaggi in arrivo; l'idea è che se arriva un messaggio elaborato in precedenza, il suo tag sarà stato memorizzato nella cache dal consumatore e il messaggio può essere ignorato.

Una cosa che vorrei sottolineare con AMQP e soluzioni basate su code in generale è che l'infrastruttura fornisce gli strumenti, ma non l'intera soluzione. Devi colmare queste lacune in base alle esigenze della tua azienda. Spesso, la soluzione migliore è derivata da tentativi ed errori. Spero che i miei suggerimenti siano utili. Ho un blog su un certo numero di soluzioni di design RabbitMQ qui, compresi i problemi che hai citato, here se sei interessato.

+1

Grazie, Paul. Sei un dio. Giusto per assicurarmi che prima di passare all'implementazione puoi per favore confermare questo: 1) Posso usare ancora usare HAProxy e l'editore conferma e non perderò alcun messaggio. Avrò messaggi duplicati, che devo rimuovere in qualche modo. Avrò problemi di prestazioni (dovuti al luppolo extra al master quando raggiungo gli schiavi), ma i miei dati saranno "a prova di proiettile". 2) Al fine di aumentare le prestazioni, creerò un servizio di monitoraggio, quindi invierò le mie richieste solo al master ogni volta, ma devo ancora occuparmi dei duplicati. Grazie. –

+1

È ancora possibile utilizzare HAProxy, ma si incorre in ulteriori passaggi di rete con una configurazione round robin. Se vuoi raggiungere anche il bilanciamento del carico, leggi questo: http://insidethecpu.com/2014/11/17/load-balancing-a-rabbitmq-cluster/ È molto improbabile che tu abbia messaggi duplicati.Penso che l'impostazione della proprietà message-ttl sia sufficiente per rimuovere i duplicati, sebbene l'aggiunta di un reference-tag, come ho detto, risolverà il problema. Rilascerò una libreria RabbitMQ in C# che raggiunge quanto sopra, a breve. Continua a monitorare il mio blog per gli aggiornamenti. –

+1

In realtà ho finito per avere messaggi duplicati. Ho eseguito un test un paio di volte pubblicando 10000 messaggi su un cluster Rabbit a 2 nodi. Ho ucciso un nodo e ho ricevuto 10011-10012 messaggi. Una delle mie API di consumo è idempotente, quindi il risultato finale era ok. Molte grazie. –