2013-10-30 11 views
13

Ich bin daran interessiert zu erfahren, wie andere Menschen mit der offiziellen RabbitMQ Java-Client-Bibliothek von einer fehlerhaften Verbindung wiederherstellen. Wir verwenden es, um unsere Anwendungsserver mit unserem RabbitMQ-Cluster zu verbinden, und wir haben ein paar verschiedene Möglichkeiten implementiert, um nach einem Verbindungsfehler wiederherzustellen, aber keiner von ihnen fühlt sich ganz richtig an.Wie behandeln Sie die Wiederherstellung von einer fehlerhaften Verbindung mithilfe der RabbitMQ Java-Client-Bibliothek?

diese Pseudo-Anwendung Stellen Sie sich vor:

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? 
     } 
    } 
} 

In der realen Welt, die wir mehrere hundert Verbraucher haben. Was passiert also, wenn die Verbindung abstirbt? Im obigen Beispiel kann Consumer1 nicht wiederherstellen, wenn die Verbindung geschlossen wird, schließt der Channel auch, ein Zustand, aus dem wir nicht wiederherstellen können. So können auf einige Möglichkeiten suchen, diese zu lösen:

Lösung A)

jeder Verbraucher Lassen Sie ihre eigene Verbindung haben und die Ereignisse registrieren, die ausgelöst werden, wenn die Verbindung stirbt und dann behandeln wieder anschließen.

Vorteile: Es funktioniert

Nachteile:

  • Da wir viele Verbraucher haben, wir wollen wahrscheinlich nicht, dass viele Verbindungen.
  • Wir könnten möglicherweise viel duplizierten Code haben für Neuanschluss an Kaninchen und Griff

Lösung B)

jeder Verbraucher die gleiche Verbindung verwenden wieder anschließen und abonnieren Sie es Verbindungsfehlerereignisse ist.

Vorteile: Weniger Verbindungen als in Lösung A

Nachteile: Da die Verbindung geschlossen ist wir brauchen sie wieder zu öffnen/ersetzen. Die Java-Client-Bibliothek scheint keine Möglichkeit zu bieten, die Verbindung erneut zu öffnen. Daher müssten wir sie durch eine neue Verbindung ersetzen und dann irgendwie alle Verbraucher über diese neue Verbindung informieren und sie müssten die Kanäle und die Verbraucher neu erstellen . Noch einmal, eine Menge Logik, die ich nicht im Verbraucher sehen will, endet dort.

Lösung C)

Wrap Connection und Channel Klassen Klassen, die die Wiederverbindungslogik behandeln, der Verbraucher muss nur über die WrappedChannel Klasse kennen. Bei einem Verbindungsfehler wird sich die WrappedConnection mit dem Wiederherstellen der Verbindung befassen und sobald sie verbunden ist, erstellt die WrappedConnection automatisch neue Kanäle und registriert die Verbraucher.

Pros: Es funktioniert - das ist eigentlich die Lösung, die wir heute verwenden.

Nachteile: Es fühlt sich an wie ein Hack, ich denke, das ist etwas, das eleganter von der zugrunde liegenden Bibliothek gehandhabt werden sollte.

Vielleicht gibt es einen viel besseren Weg? Die API-Dokumentation spricht nicht so viel über die Wiederherstellung von einer fehlerhaften Verbindung.Jede Eingabe wird geschätzt :)

Antwort

6

Ich habe ein paar gute Antworten auf der RabbitMQ-Mailingliste, die im Grunde genommen die Lösung C vorschlägt, wie ich oben aufgeführt habe.

Lösung C)

Wrap-Verbindung und Channel-Klassen Klassen, die die Wiederverbindungslogik behandeln, der Verbraucher muss nur über die WrappedChannel Klasse kennen. Bei einem Verbindungsfehler wird die WrappedConnection mit dem Wiederherstellen der Verbindung und dem Verbinden der WrappedConnection automatisch neue Channels erstellen und Consumer registrieren.

Pros: Es funktioniert - das ist eigentlich die Lösung, die wir heute verwenden.

Nachteile: Es fühlt sich an wie ein Hack, ich denke, das ist etwas, das eleganter von der zugrunde liegenden Bibliothek gehandhabt werden sollte.

Dies ist, was die beiden Clients oben auf dem Java - Langohr und March Hare - gebaut haben. Es ist kein Hack, sondern eine notwendige Arbeit um , weil Verbindung Wiederherstellung wird derzeit nicht von der Java Client durchgeführt (es sollte eine Kernfunktion sein, wenn Sie mich fragen).

Das ist also ein praktikabler Ansatz.

Werfen Sie einen Blick auf Lyra, auch: https://github.com/jhalterman/lyra.

MK

Software Engineer, Pivotal/RabbitMQ

Und:

Hallo Peter,

Lösung C ist eigentlich ziemlich vernünftig. Es gibt nicht viel zu gewinnen von der Verwendung mehrerer Verbindungen zu demselben Server, wenn Sie versuchen, Schutz gegen Netzwerkfehler oder Cluster-Partitionen. Wenn eine Verbindung stirbt, werden alle wahrscheinlich. Wrapping und Wiederherstellung Verbindungen/Kanäle funktioniert gut, und wie Michael erwähnt, könnten Sie auch überprüfen, Lyra, da es die verschiedenen Eckfälle beteiligt in Recovery-Ressourcen für Sie behandelt.

Cheers, Jonathan

den vollständigen Thread lesen Sie hier:

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

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

+0

Können Sie einen Hinweis geben, wie genau es zu codieren ist. Da scheint es keinen Rückruf zu geben, auf dem wir alle Kanäle, Warteschlangen und Bindungen wiederherstellen können. Kannst du mir sagen wie genau ich die Verbindung wickeln soll ?? – jeevs

+0

Sie müssen die Verbindung und den Kanal umbrechen, es gibt keine Möglichkeit, einen Kanal wiederherzustellen, nachdem die Verbindung getrennt wurde, so dass Sie einen neuen erstellen müssen. –

10

Seit Version 3.3.0 können Sie die automatische Wiederherstellung verwenden, das ist eine neue Funktion von der Java-Client. Von der Java API Guide (http://www.rabbitmq.com/api-guide.html#recovery)

Um die automatische Wiederherstellung der Verbindung zu aktivieren, Fabrik verwendet werden.setAutomaticRecovery (true):