2013-10-30 10 views
13

Chciałbym wiedzieć, jak inne osoby radzą sobie z odzyskiwaniem po błędnym połączeniu przy użyciu oficjalnej biblioteki klienta java RabbitMQ. Używamy go do łączenia naszych serwerów aplikacji z naszym klastrem RabbitMQ i wdrożyliśmy kilka różnych sposobów na odzyskanie po awarii połączenia, ale żaden z nich nie czuje się dobrze.Jak radzisz sobie z odzyskiwaniem po błędnym połączeniu za pomocą biblioteki klienta java RabbitMQ?

Wyobraźmy sobie tę aplikację 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? 
     } 
    } 
} 

w rzeczywistym świecie mamy kilkaset konsumentów. Co się stanie, jeśli połączenie zginie? W powyższym przykładzie Consumer1 nie może odzyskać, gdy połączenie zostanie zamknięte, Kanał również się zamknie, stan, z którego nie możemy odzyskać. Więc spójrzmy na kilka sposobów, aby rozwiązać ten problem:

roztwór A)

Niech każdy konsument ma swoje własne połączenia i rejestrowania zdarzeń, które powodują, kiedy umiera połączenie, a następnie obsługiwać podłączając.

Plusy: Działa

Wady:

  • Ponieważ mamy dużo konsumentów, prawdopodobnie nie chce, że wiele połączeń.
  • Możemy ewentualnie mieć dużo kodu duplikowane dla podłączając do królika i obsługiwać podłączając

roztwór B)

mieć każdy konsument używać tego samego połączenia i zapisz się to z połączeniem zdarzeń awaryjnych.

Plusy: mniej połączeń niż w roztworze A

Wady: Ponieważ połączenie jest zamykane musimy ponownie otworzyć/wymienić. Biblioteka klienta Java nie wydaje się być sposobem na ponowne otwarcie połączenia, więc musielibyśmy zastąpić go nowym połączeniem, a następnie jakoś powiadomić wszystkich konsumentów o tym nowym połączeniu i musieliby odtworzyć kanały i konsumentów . Ponownie pojawia się tam wiele logiki, których nie chcę widzieć u konsumenta.

Roztwór C)

Wrap Connection i Channel zajęcia to zajęcia, które zajmują logikę ponownego połączenia, konsument musi tylko wiedzieć o klasie WrappedChannel. W przypadku błędu połączenia, WrappedConnection zajmie się ponownym nawiązaniem połączenia, a po podłączeniu WrappedConnection automatycznie utworzy nowe kanały i zarejestruje odbiorców.

Zalety: Działa - jest to właściwie rozwiązanie, którego używamy dzisiaj.

Minusy: Czuję się jak haker, myślę, że jest to coś, co powinno być obsługiwane bardziej elegancko przez leżącą pod nim bibliotekę.

Może jest o wiele lepszy sposób? Dokumentacja API nie mówi zbyt wiele o odzyskiwaniu po błędnym połączeniu.Wszelkie dane wejściowe są mile widziane :)

Odpowiedz

6

Mam kilka dobrych odpowiedzi na liście mailingowej RabbitMQ, sugerując rozwiązanie C jak wyżej.

Roztwór C)

Wrap połączenia i klasy Channel to zajęcia, które zajmują logikę ponownego połączenia, konsument musi tylko wiedzieć o klasie WrappedChannel. W przypadku niepowodzenia połączenia usługa WrappedConnection z ponownym nawiązaniem połączenia i po połączeniu z siecią WrappedConnection automatycznie utworzy nowe kanały i zarejestruje użytkowników o numerach .

Zalety: To działa - jest to właściwie rozwiązanie, którego używamy dzisiaj.

Minusy: Czuję się jak haker, myślę, że jest to coś, co powinno być obsługiwane bardziej elegancko przez leżącą pod nim bibliotekę.

To jest to, co dwaj klienci zbudowali na bazie Javy - Langohr i March Hare - do. Nie jest to haker, ale niezbędna praca wokół numeru , ponieważ odzyskiwanie połączenia nie jest obecnie wykonywane przez klienta Java (powinna to być funkcja podstawowa, jeśli mnie o to pytasz).

Jest to opłacalne podejście.

Spójrz na Lyrę też: https://github.com/jhalterman/lyra.

MK

Software Engineer, Pivotal/RabbitMQ

I:

Cześć Peter,

Rozwiązanie C jest rzeczywiście bardzo rozsądne. Nie ma wiele korzyści, aby uzyskać korzystanie z wielu połączeń z tym samym serwerem, jeśli próbujesz uniknąć błędów sieci lub partycji klastrowych. Jeśli jedno połączenie zostanie zgaszone, najprawdopodobniej to zrobi. Pakowanie i odzyskiwanie połączeń/kanałów działa dobrze, a jak wspomniał Michael, możesz również sprawdzić Lyrę, ponieważ obsługuje ona różne przypadki narożne związane z odzyskiwaniem zasobów dla ciebie .

Cheers, Jonathan

Przeczytaj cały wątek tutaj:

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

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

+0

Czy możesz podać podpowiedź, jak to zakodować. Ponieważ wydaje się, że nie ma wywołania zwrotnego, na którym możemy odzyskać wszystkie kanały, kolejki i powiązania. Czy możesz mi powiedzieć, jak dokładnie powinienem zawinąć połączenie? – jeevs

+0

Będziesz musiał owinąć Połączenie i Kanał, nie ma możliwości odzyskania kanału po jego rozłączeniu, więc będziesz musiał utworzyć nowy. –

10

Od wersji 3.3.0 można użyć automatycznego odzyskiwania, co jest nowością klient Java. Z przewodnika po języku Java API (http://www.rabbitmq.com/api-guide.html#recovery)

Aby włączyć automatyczne odzyskiwanie połączenia, należy użyć fabryki .setAutomaticRecovery (true):

Powiązane problemy