RabbitMQ i relacja między kanałem a połączeniem

176

Klient RabbitMQ Java ma następujące pojęcia:

  • Connection - połączenie z instancją serwera RabbitMQ
  • Channel - ???
  • Pula wątków konsumenta - pula wątków, które zużywają komunikaty z kolejek serwera RabbitMQ
  • Kolejka - struktura przechowująca wiadomości w kolejności FIFO

Próbuję zrozumieć związek, a co ważniejsze , skojarzenia między nimi.

  1. Nadal nie jestem do końca pewien, czym Channeljest a , poza faktem, że jest to struktura, z której publikujesz i konsumujesz, i że jest ona tworzona z otwartego połączenia. Gdyby ktoś mógł mi wyjaśnić, co reprezentuje „kanał”, mogłoby to pomóc wyjaśnić kilka rzeczy.
  2. Jaki jest związek między kanałem a kolejką? Czy ten sam kanał może być używany do komunikacji z wieloma kolejkami, czy też musi to być 1: 1?
  3. Jaka jest relacja między kolejką a pulą konsumentów? Czy wielu konsumentów może być subskrybowanych w tej samej kolejce? Czy ten sam konsument może korzystać z wielu kolejek? A może relacja 1: 1?

Z góry dziękuję za pomoc!


źródło
Odpowiedzi na to pytanie sprawiły, że zgłosiłem ten problem z klientem golang, zamiast zadawać to pytanie tutaj.
Bruce Adams
Kanał jest logiczną koncepcją używaną do multipleksowania pojedynczego fizycznego połączenia TCP między klientem a węzłem. Numer kanału jest zawarty w nagłówku wiadomości ramki AMQP.
ymas

Odpowiedzi:

196
  1. A Connectionreprezentuje rzeczywiste połączenie TCP z brokerem komunikatów, podczas gdy a Channeljest połączeniem wirtualnym (połączenie AMQP) w nim. W ten sposób możesz używać dowolnej liczby (wirtualnych) połączeń w aplikacji bez przeciążania brokera połączeniami TCP.

  2. Możesz użyć jednego Channeldo wszystkiego. Jeśli jednak masz wiele wątków, sugeruje się użycie innego Channeldla każdego wątku.

    Bezpieczeństwo wątków kanału w przewodniku API klienta Java :

    Instancje kanału można bezpiecznie używać przez wiele wątków. Żądania do kanału są serializowane, przy czym tylko jeden wątek może jednocześnie uruchamiać polecenie w kanale. Mimo to aplikacje powinny preferować używanie kanału na wątek zamiast udostępniania tego samego kanału w wielu wątkach.

    Nie ma bezpośredniego związku między Channela Queue. A Channelsłuży do wysyłania poleceń AMQP do brokera. Może to być utworzenie kolejki lub coś podobnego, ale te pojęcia nie są ze sobą powiązane.

  3. Każdy Consumerdziała we własnym wątku przydzielonym z puli wątków konsumenta. Jeśli wielu konsumentów subskrybuje tę samą kolejkę, broker używa okrężnego działania do równomiernego rozprowadzania komunikatów między nimi. Zobacz samouczek drugi: „Kolejki robocze” .

    Możliwe jest również dołączenie tego samego Consumerdo wielu kolejek. Konsumentów można rozumieć jako wywołania zwrotne. Są one wywoływane za każdym razem, gdy wiadomość dociera do kolejki, z którą związany jest konsument. W przypadku klienta Java każdy Konsument ma metodę handleDelivery(...), która reprezentuje metodę wywołania zwrotnego. Zwykle robisz podklasę DefaultConsumeri przesłonięcie handleDelivery(...). Uwaga: jeśli dołączysz tę samą instancję konsumenta do wielu kolejek, ta metoda będzie wywoływana przez różne wątki. Zadbaj więc o synchronizację, jeśli to konieczne.

Bengt
źródło
4
Wystarczy dodać z dokumentacji: wywołania zwrotne do konsumentów są wysyłane w wątku innym niż wątek zarządzany przez połączenie. Oznacza to, że konsumenci mogą bezpiecznie wywoływać metody blokowania w połączeniu lub kanale, takie jak queueDeclare, txCommit, basicCancel lub basicPublish. Każdy kanał ma swój własny wątek wysyłania. W przypadku najczęstszego przypadku użycia jednego Konsumenta na kanał oznacza to, że Konsumenci nie zatrzymują innych Konsumentów. Jeśli masz wielu Konsumentów na Kanał, pamiętaj, że od dawna Konsument może wstrzymywać wysyłanie wywołań zwrotnych do innych Konsumentów w tym Kanale.
filip
1
Jeśli dołączysz tę samą instancję konsumenta do wielu kolejek z tego samego kanału, oznaczałoby to, że wywołania zwrotne są wysyłane w tym samym wątku. W takim razie nie potrzebowałbyś synchronizacji, prawda?
filip
Czy mogę używać tylko jednego połączenia i puli kanałów zamiast puli połączeń? Czy wpłynie to na przepustowość publikowania wiadomości?
qeek
4
Myślę, że to odniesienie do Java Client API jest teraz nieaktualne i faktycznie dzisiejsze odniesienie jest bezpośrednio sprzeczne z cytatem w tej odpowiedzi. Dzisiejsze odniesienie mówi, że „Instancje kanału nie mogą być udostępniane między wątkami”.
Edwin Dalorzo
1
@EdwinDalorzo - wygląda na to, że ten, kto pierwotnie napisał dokumentację, nie w pełni rozumiał dychotomię połączenia kanałów. Podstawowa architektura AMQP 0.9.1 naprawdę traktuje kanał jako sesję, więc różne wątki współużytkujące sesję to naprawdę nonsens. Domyślam się, że to jest powód tej zmiany.
theMayer
53

W tym miejscu przydatne jest dobre koncepcyjne zrozumienie tego, co protokół AMQP robi „pod maską”. Chciałbym zaoferować, że dokumentacja i interfejs API, które AMQP 0.9.1 wybrał do wdrożenia, sprawiają, że jest to szczególnie mylące, więc samo pytanie jest tym, z którym wiele osób musi się zmagać.

TL; DR

Połączenie jest negocjowane fizyczne gniazdo TCP z serwerem AMQP. Prawidłowo zaimplementowani klienci będą mieli jeden z nich na aplikację, bezpieczny dla wątków, współdzielony między wątkami.

Kanał jest pojedyncza sesja aplikacja na połączenia. Wątek będzie miał jedną lub więcej takich sesji. Architektura AMQP 0.9.1 polega na tym, że nie mają one być współużytkowane między wątkami i powinny zostać zamknięte / zniszczone, gdy wątek, który go utworzył, zostanie zakończony. Są również zamykane przez serwer, gdy wystąpią różne naruszenia protokołu.

Konsument jest wirtualnym konstrukt oznacza obecność „skrzynki pocztowej” na danym kanale. Użycie konsumenta instruuje brokera, aby wypychał komunikaty z określonej kolejki do tego punktu końcowego kanału.

Fakty dotyczące połączeń

Po pierwsze, jak słusznie zauważyli inni, połączenie to obiekt reprezentujący rzeczywiste połączenie TCP z serwerem. Połączenia są określane na poziomie protokołu w AMQP, a cała komunikacja z brokerem odbywa się za pośrednictwem co najmniej jednego połączenia.

  • Ponieważ jest to rzeczywiste połączenie TCP, ma adres IP i numer portu.
  • Parametry protokołu są negocjowane dla każdego klienta w ramach konfigurowania połączenia (proces nazywany uzgadnianiem .
  • Jest przeznaczony do długowieczności ; istnieje kilka przypadków, w których zamknięcie połączenia jest częścią projektu protokołu.
  • Z punktu widzenia OSI, prawdopodobnie znajduje się on gdzieś w okolicach warstwy 6
  • Bicie serca można skonfigurować do monitorowania stanu połączenia, ponieważ protokół TCP sam w sobie nie zawiera niczego, co mogłoby to zrobić.
  • Najlepiej jest mieć dedykowany wątek zarządzający odczytami i zapisami do bazowego gniazda TCP. Większość, jeśli nie wszyscy, klienci RabbitMQ to robią. Pod tym względem są na ogół bezpieczne dla wątków.
  • Relatywnie mówiąc, tworzenie połączeń jest „drogie” (ze względu na uścisk dłoni), ale praktycznie nie ma to znaczenia. Większość procesów naprawdę potrzebuje tylko jednego obiektu połączenia. Możesz jednak utrzymywać połączenia w puli, jeśli uznasz, że potrzebujesz większej przepustowości niż może zapewnić pojedynczy wątek / gniazdo (mało prawdopodobne przy obecnej technologii obliczeniowej).

Informacje o kanale

Kanał jest sesja aplikacja, która jest otwarta dla każdego kawałka swojej aplikacji do komunikacji z brokerem RabbitMQ. Działa na jednym połączeniu i reprezentuje sesję z brokerem.

  • Ponieważ reprezentuje logiczną część logiki aplikacji, każdy kanał zwykle istnieje we własnym wątku.
  • Zazwyczaj wszystkie kanały otwarte przez Twoją aplikację będą współdzielić jedno połączenie (są to lekkie sesje działające na szczycie połączenia). Połączenia są bezpieczne dla wątków, więc to jest w porządku.
  • Większość operacji AMQP odbywa się za pośrednictwem kanałów.
  • Z punktu widzenia warstwy OSI kanały prawdopodobnie znajdują się wokół warstwy 7 .
  • Kanały są zaprojektowane jako przejściowe ; częścią projektu AMQP jest to, że kanał jest zwykle zamykany w odpowiedzi na błąd (np. ponowne zadeklarowanie kolejki z innymi parametrami przed usunięciem istniejącej kolejki).
  • Ponieważ są one przejściowe, aplikacja nie powinna łączyć kanałów.
  • Serwer używa liczby całkowitej do identyfikacji kanału. Gdy wątek zarządzający połączeniem odbiera pakiet dla określonego kanału, używa tego numeru do poinformowania brokera, do którego kanału / sesji należy pakiet.
  • Kanały nie są generalnie bezpieczne dla wątków, ponieważ nie ma sensu udostępniać ich między wątkami. Jeśli masz inny wątek, który musi korzystać z brokera, potrzebny jest nowy kanał.

Fakty konsumenckie

Konsument to obiekt zdefiniowany przez protokół AMQP. Nie jest to kanał ani połączenie, a zamiast tego jest czymś, czego Twoja aplikacja używa jako swoistej „skrzynki pocztowej” do odrzucania wiadomości.

  • „Tworzenie konsumenta” oznacza, że ​​mówisz brokerowi (używając kanału przez połączenie ), że chcesz, aby wiadomości były do ​​Ciebie przesyłane przez ten kanał. W odpowiedzi broker zarejestruje, że masz konsumenta na kanale i zacznie przesyłać do Ciebie wiadomości.
  • Każdy komunikat przesłany przez połączenie będzie odnosił się zarówno do numeru kanału, jak i numeru klienta . W ten sposób wątek zarządzający połączeniami (w tym przypadku w Java API) wie, co zrobić z komunikatem; wtedy wątek obsługujący kanał również wie, co zrobić z wiadomością.
  • Implementacja konsumencka ma największe zróżnicowanie, ponieważ jest dosłownie specyficzna dla aplikacji. W mojej implementacji zdecydowałem się wyodrębnić zadanie za każdym razem, gdy wiadomość dotarła przez konsumenta; w ten sposób miałem wątek zarządzający połączeniem, wątek zarządzający kanałem (i, co za tym idzie, konsumentem) oraz jeden lub więcej wątków zadań dla każdej wiadomości dostarczonej przez konsumenta.
  • Zamknięcie połączenia powoduje zamknięcie wszystkich kanałów połączenia. Zamknięcie kanału zamyka wszystkich konsumentów w kanale. Istnieje również możliwość anulowania konsumenta (bez zamykania kanału). Istnieją różne przypadki, w których ma sens zrobienie którejkolwiek z trzech rzeczy.
  • Zazwyczaj implementacja konsumenta w kliencie AMQP przydziela konsumentowi jeden dedykowany kanał, aby uniknąć konfliktów z działaniami innych wątków lub kodu (w tym publikowania).

Jeśli chodzi o to, co rozumiesz przez konsumencką pulę wątków, podejrzewam, że klient Java robi coś podobnego do tego, co zaprogramowałem dla mojego klienta (mój był oparty na kliencie .Net, ale był mocno zmodyfikowany).

theMayer
źródło
1
„kanały nie powinny być łączone”, tego właśnie szukam
ospider
„Ponieważ są one przejściowe, kanały nie powinny być łączone przez aplikację”. - czy możesz wyjaśnić, jak doszedłeś do tego wniosku. Dokumentacja zaleca łączenie kanałów, jeśli implementacja „jeden kanał na wątek” wykorzystuje zbyt dużo zasobów, zobacz tutaj: rabbitmq.com/channels.html#resource-usage
ymas
@ymas - Dokumentacja, do której się odnosisz, ma charakter spekulacyjny i moim zdaniem kiepskie wytyczne. Czytam kod źródłowy i specyfikację protokołu. Kanały nie powinny być łączone, kropka. Co więcej, jeden kanał na gwint jest prowadzeniem opartym na tej samej zasadzie. Jeśli zauważysz, że masz tak wiele otwartych kanałów, że serwer jest ograniczony zasobami, musisz ponownie ocenić swoją architekturę (tj. Przełączyć się na schemat wysokiej dostępności i / lub zmniejszyć współbieżność).
theMayer
21

Znalazłem ten artykuł, który wyjaśnia wszystkie aspekty modelu AMQP, którego jednym jest kanał. Uważam, że jest to bardzo pomocne w pogłębianiu mojego zrozumienia

https://www.rabbitmq.com/tutorials/amqp-concepts.html

Niektóre aplikacje wymagają wielu połączeń z brokerem AMQP. Jednak jednoczesne pozostawianie otwartych wielu połączeń TCP jest niepożądane, ponieważ powoduje to zużycie zasobów systemowych i utrudnia konfigurowanie zapór. Połączenia AMQP 0-9-1 są multipleksowane z kanałami, które można traktować jako „lekkie połączenia, które współużytkują pojedyncze połączenie TCP”.

W przypadku aplikacji, które używają wielu wątków / procesów do przetwarzania, bardzo często otwiera się nowy kanał dla każdego wątku / procesu i nie udostępnia kanałów między nimi.

Komunikacja na określonym kanale jest całkowicie oddzielona od komunikacji na innym kanale, dlatego każda metoda AMQP przenosi również numer kanału, którego klienci używają do ustalenia, dla którego kanału jest ta metoda (a tym samym, na przykład, który program obsługi zdarzeń musi zostać wywołany) .

CamW
źródło
4

Istnieje relacja między jak połączenie TCP może mieć wiele kanałów .

Kanał : jest to wirtualne połączenie wewnątrz połączenia. Podczas publikowania lub konsumowania wiadomości z kolejki - wszystko odbywa się za pośrednictwem kanału, natomiast Połączenie : Jest to połączenie TCP między Twoją aplikacją a brokerem RabbitMQ.

W architekturze wielowątkowej może być potrzebne oddzielne połączenie na wątek. Może to prowadzić do niepełnego wykorzystania połączenia TCP, a także zwiększa obciążenie systemu operacyjnego, aby ustanowić tyle połączeń TCP, ile wymaga w czasie szczytu sieci. Wydajność systemu mogłaby zostać drastycznie zmniejszona. W tym miejscu przydaje się kanał, który tworzy wirtualne połączenia wewnątrz połączenia TCP. Od razu zmniejsza narzut systemu operacyjnego, a także pozwala nam wykonywać operacje asynchroniczne w szybszy, bardziej niezawodny i jednocześnie sposób. wprowadź opis obrazu tutaj

Atul Jain
źródło