2013-10-30 15 views
13

Sono interessato a sapere come altre persone gestiscono il ripristino da una connessione errata utilizzando la libreria client java RabbitMQ ufficiale. Lo stiamo usando per connettere i nostri server applicativi al nostro cluster RabbitMQ e abbiamo implementato alcuni modi diversi per recuperare da un errore di connessione, ma nessuno di loro sembra giusto.Come gestite il ripristino da una connessione errata utilizzando la libreria client java RabbitMQ?

Immaginate questa applicazione pseudo:

public class OurClassThatStartsConsumers { 
    Connection conn; 

    public void start() { 
     ConnectionFactory factory = new ConnectionFactory(); 
     factory.setUsername("someusername"); 
     factory.setPassword("somepassword"); 
     factory.setHost("somehost"); 
     conn = factory.newConnection(); 

     new Thread(new Consumer(conn.createChannel())).start(); 
    } 
    } 

class Consumer1 implements Runnable { 
    public Consumer1(Channel channel) { 
     this.channel = channel; 
    } 

    @Override 
    public void run() { 
     while (true) { 
      ... consume incoming messages on the channel... 
      // How do we handle that the connection dies? 
     } 
    } 
} 

Nel mondo reale abbiamo diverse centinaia di consumatori. Quindi cosa succede se la connessione muore? Nell'esempio sopra Consumer1 non può recuperare, quando la connessione si chiude, si chiude anche il canale, uno stato dal quale non possiamo recuperare. Quindi, consente di guardare alcuni modi per risolvere questo:

Soluzione A)

Lasciate ogni consumatore hanno il loro collegamento e registrare gli eventi che si innescano quando la connessione muore e poi gestire la riconnessione.

Pro: Funziona

Contro:

  • Dal momento che abbiamo un sacco di consumatori, che probabilmente non si vuole che molti connessioni.
  • Potremmo eventualmente avere un sacco di codice duplicato per riconnessione al coniglio e gestire ricollegare

Soluzione B)

Avere ogni consumatore usa la stessa connessione e iscriviti alla sua eventi di errore di connessione.

Pro: meno connessioni rispetto nella Soluzione A

Contro: Poiché la connessione è chiusa dobbiamo riaprire/sostituirlo. La libreria client java non sembra fornire un modo per riaprire la connessione, quindi dovremmo sostituirla con una nuova connessione e quindi in qualche modo notificare a tutti gli utenti questa nuova connessione e dovranno ricreare i canali e i consumatori . Ancora una volta, molta logica che non voglio vedere nel consumatore finisce lì.

Soluzione C)

Wrap Connection e Channel classi è classi che gestiscono la logica ri-connessione, il consumatore ha solo bisogno di conoscere la classe WrappedChannel. In caso di errore di connessione, il WrappedConnection si occuperà di ristabilire la connessione e, una volta connesso, lo WrappedConnection creerà automaticamente nuovi canali e registrerà i consumatori.

Pro: Funziona: questa è in realtà la soluzione che stiamo utilizzando oggi.

Contro: Sembra un trucco, penso che questo sia qualcosa che dovrebbe essere gestito in modo più elegante dalla libreria sottostante.

Forse c'è un modo migliore? La documentazione dell'API non parla molto del ripristino da una connessione difettosa.Qualsiasi input è apprezzato :)

risposta

6

Ottenuto alcune buone risposte sulla mailing list RabbitMQ, sostanzialmente suggerendo la soluzione C come ho elencato sopra.

Soluzione C)

Wrap connessione e classi canale è classi che gestiscono la logica ri-connessione, il consumatore ha solo bisogno di conoscere la classe WrappedChannel. In caso di errore di connessione, WrappedConnection si occupa di ristabilire la connessione e, una volta connesso, lo WrappedConnection creerà automaticamente nuovi canali e registrerà i consumatori .

Pro: Funziona: questa è in realtà la soluzione che stiamo utilizzando oggi.

Contro: Sembra un trucco, penso che questo sia qualcosa che dovrebbe essere gestito in modo più elegante dalla libreria sottostante.

Questo è ciò che i due client hanno costruito sopra a quello Java - Langohr e March Hare - do. Non è un trucco ma un lavoro necessario attorno allo perché il ripristino della connessione non è attualmente eseguito dal client Java (dovrebbe essere una funzionalità di base, se me lo chiedi).

Quindi questo è un approccio praticabile.

Dai un'occhiata anche a Lyra: https://github.com/jhalterman/lyra.

MK

Software Engineer, Pivotal/RabbitMQ

E:

Ciao Peter,

Soluzione C è in realtà abbastanza ragionevole. Non c'è molto da guadagnare dall'utilizzo di più connessioni allo stesso server se si sta tentando di proteggere da guasti di rete o partizioni cluster. Se una connessione muore, probabilmente lo faranno. L'avvolgimento e il ripristino delle connessioni/canali funziona correttamente e, come menzionato da Michael, è possibile controllare Lyra poiché gestisce i vari casi d'angolo coinvolti nello nel recupero delle risorse.

Cheers, Jonathan

Leggi l'intero thread qui:

http://lists.rabbitmq.com/pipermail/rabbitmq-discuss/2013-October/031564.html

http://lists.rabbitmq.com/pipermail/rabbitmq-discuss/2013-November/031573.html

+0

Puoi dare un suggerimento su come esattamente codificarlo. Poiché sembra non esserci nessuna chiamata richiamata su cui possiamo recuperare tutti i canali, le code e le associazioni. Puoi dirmi esattamente come dovrei avvolgere la connessione ?? – jeevs

+0

Dovrai racchiudere Connessione e Canale, non c'è modo di recuperare un canale dopo che è stato disconnesso, quindi dovrai crearne uno nuovo. –

10

Dalla versione 3.3.0 è possibile utilizzare il ripristino automatico, che è una nuova funzionalità di il client Java. Dalla guida API Java (http://www.rabbitmq.com/api-guide.html#recovery)

per consentire il ripristino di connessione automatica, utilizzare fabbrica.setAutomaticRecovery (true):