RabbitMQ
Marcin
Lewandowski
Marcin
Lewandowski
Marcin Lewandowski
- programista z ponad 15 letnim doświadczeniem,
- tworzę i rozwijam systemy dla logistyki,
- prowadzę bloga czterytygodnie.pl
Uczestnicy
- Imię i nazwisko
- Jaki jest dla mnie cel szkolenia ?
- Czy udało mi się wypełnić Kwestionariusz Oczekiwań przed szkoleniem ?
- Gdzie i w jaki sposób będę wykorzystywać wiedzę ze szkolenia ?
- Co aktualnie wiem o temacie szkolenia ?
- Jakie wykorzystuję oprogramowanie związane z tematem szkolenia ?
Marcin
Lewandowski
Informacje organizacyjne
Marcin
Lewandowski
09:00 do 09:15 - Rozpoczęcie dnia, sprawy organizacyjne
09:15 do 10:45 - Blok szkoleniowy
10:45 do 11.00 - Przerwa kawowa ( 15 min. )
11:00 do 13:00 - Blok szkoleniowy
13:00 do 13:45 - Przerwa obiadowa ( 45 min. )
13:45 do 14:45 - Blok szkoleniowy
14:45 do 15:00 - Przerwa kawowa ( 15 min. )
15:00 do 16:00 - Blok szkoleniowy
Plan szkolenia
- Przygotowanie środowiska
- Instalacja w systemie Linux
- Instalacja oparta o Docker-a
- Instalacja pluginu panelu administracyjnego
- Wprowadzenie do RabbitMQ
- Rola producenta,
- Przetwarzanie wiadomości przez RabbitMQ ( vhost, exchange, queue )
- Rola konsumenta
- Producent
- Jakiego formatu wiadomości używać ?
- Tworzenie wiadomości przez producenta
- Trwałość tworzonych wiadomości ( Persistence )
- TTL (Time To Live)
- Weryfikacja czy wiadomość została doręczona
- Virtual Hosts
- Centrale wiadomości - exchange
- Czym jest centrala wiadomości ( Exchange ) ?
- Fanout Exchange
- Direct Exchange
- Topic Exchange
- Kolejki - queue
- Zarządzanie kolejkami
- TTL (Time To Live)
- DLX (Dead Letter Exchange)
- kolejki tymczasowe
- Konsument
- Pobieranie wiadomości z kolejek
- Potwierdzanie wiadomości
- Obsługa błędów
- Zarządzanie RabbitMQ
- Konfiguracja vhost, exchange, queue za pomocą pliku konfiguracyjnego
- REST API
- Zarządzanie RabbitMQ z lini poleceń
Marcin
Lewandowski
Przygotowanie środowiska
Linux
apt-get install rabbitmq-server
Instalacja sprowadza się do wydania jednego polecenia:
Po instalacji sprawdzamy stan serwera
/etc/init.d/rabbitmq-server status
Instalacja serwera
apt-get update
Przed instalacją aktualizujemy repozytoria
Zalogowanie na administratora
sudo su
Linux
Możemy także sprawdzić stan serwera za pomocą polecenia
rabbitmqctl status
Polecenie to zwraca dużo więcej informacji o serwerze i jego stanie. Z wyświetlonych informacji możemy dowiedzieć się:
- jaka jest wersja serwera
- nazwa noda
- włączone pluginy
- gdzie przechowywane są dane
- jakie pliki konfiguracyjne zostały załadowane
- gdzie znajduje się plik z logami
- zużycie pamięci
- ilość wirtualnych hostów
Instalacja serwera
Do instalacji pluginów mamy specjalne polecenie:
rabbitmq-plugins
Linux
Instalacja pluginów
rabbitmq-plugins --help
Dodając flagę help dowiemy się jakie to polecenie ma możliwości
Nas interesuje sekcja Plugin Management
disable Disables one or more plugins
enable Enables one or more plugins
list Lists plugins and their state
set Enables one or more plugins, disables the rest
Sprawdźmy jakie pluginy możemy zainstalować
rabbitmq-plugins list
Linux
Instalacja pluginów
Jest ich sporo
[ ] rabbitmq_amqp1_0 3.8.2
[ ] rabbitmq_auth_backend_cache 3.8.2
[ ] rabbitmq_auth_backend_http 3.8.2
[ ] rabbitmq_auth_backend_ldap 3.8.2
[ ] rabbitmq_auth_backend_oauth2 3.8.2
[ ] rabbitmq_auth_mechanism_ssl 3.8.2
[ ] rabbitmq_consistent_hash_exchange 3.8.2
[ ] rabbitmq_event_exchange 3.8.2
[ ] rabbitmq_federation 3.8.2
[ ] rabbitmq_federation_management 3.8.2
...
Nas interesuje plugin rabbitmq_management i to go włączamy
rabbitmq-plugins enable rabbitmq_management
Linux
Instalacja pluginów
Co w rezultacie spowodowało automatyczne włączenie dwóch innych pluginów: rabbitmq_management_agent, rabbitmq_web_dispatch.
Enabling plugins on node rabbit1
rabbitmq_management
The following plugins have been configured:
rabbitmq_management
rabbitmq_management_agent
rabbitmq_web_dispatch
Applying plugin configuration to rabbit1
The following plugins have been enabled:
rabbitmq_management
rabbitmq_management_agent
rabbitmq_web_dispatch
started 3 plugins.
Aby nowo zainstalowany plugin działał konieczny jest restart serwera
/etc/init.d/rabbitmq-server restart
Linux
Instalacja pluginów
Teraz w przeglądarce otwieramy adres http://localhost:15672 pod którym powinniśmy zobaczyć ekran logowania do panelu administracyjnego.
Login: guest
Hasło: guest
Docker
Instalacja Docker
apt-get install docker.io
Instalacja Docker Compose
apt-get install docker-compose
Wymagania:
- Docker, dostarcza kontenery,
- Docker Compose, pozwala stworzyć plik z konfiguracją środowiska
docker-compose.yml
Plik z konfiguracją środowiska testowego
version: '3'
services:
rabbit:
image: rabbitmq:3.8-management
ports:
- "5673:5672"
- "15673:15672"
- wykorzystujemy obraz rabbitmq:3-management, który ma włączony plugin panelu administracyjnego,
- przekierowujemy porty,
- 5672 - RabbitMQ,
- 15672 - panel administracyjny
Docker
docker-compose.yml
Uruchomienie środowiska
docker-compose up
Docker
Uruchomienie środowiska w tle
docker-compose up -d
Sprawdzenie uruchomionych kontenerów
docker ps
Zatrzymanie środowiska
ctrl + c
Zatrzymanie środowiska
docker-compose down
Wprowadzenie
do RabbitMQ
Connection & Channel
Wprowadzenie do RabbitMQ
-
Aplikacja ustanawia jedno połączenie z RabbitMQ
-
Połączenie powinno trwać tak długo jak aplikacja żyje
-
Połączenie TCP
-
duży narzut związany z nawiązaniem połączenia,
-
przesyłanie nadmiarowych informacji dotyczących samego połączenia, a nie danych
-
Connection & Channel
Wprowadzenie do RabbitMQ
-
Aplikacja po nawiązaniu połączenia ustanawia kanały komunikacji,
-
Jedna aplikacja może ustanowić wiele kanałów komunikacji,
-
W ramach kanałów komunikacji możliwe jest:
-
deklarowanie central, kolejek, połączeń pomiędzy nimi itp.
-
publikowanie wiadomości,
-
pobieranie wiadomości
-
...
-
Połączenie TPC
AMQP
Protokoły
Wprowadzenie do RabbitMQ
MQTT
Wprowadzenie do RabbitMQ
-
lekki protokół opracowany przez IBM
-
broker pełni rolę serwera
-
aynchroniczny
- klient może pełnić rolę producenta i konsumenta
- klient publikuje / subskrybuje tematy
- dynamiczne tworzenie tematów
- wszyscy subskrybenci otrzymują wiadomości z danego tematu
MQTT
Wprowadzenie do RabbitMQ
MQTT
Wprowadzenie do RabbitMQ
Włączenie obsługi MQTT w RabbitMQ
rabbitmq-plugins enable rabbitmq_mqtt
# restart RabbitMQ
/etc/init.d/rabbitmq-server restart
Instalacja klienta MQTT
apt install mosquitto-clients
Subskrypcja tematu czujnik_1
mosquitto_sub -h 127.0.0.1 -p 1883 -t "czujnik_1"
Publikowanie wiadomości w temacie czujnik_1
mosquitto_pub -h 127.0.0.1 -p 1883 -t "czujnik_1" -m "Odczyt 1"
MQTT
Wprowadzenie do RabbitMQ
AMQP
Wprowadzenie do RabbitMQ
-
protokół podobny do HTTP, TCP
-
aynchroniczny
- Binding - możliwość określenia gdzie przesłać wiadomość,
- Queuing - kolejki,
- Exchange - centrale wiadomości
AMQP
Wprowadzenie do RabbitMQ
AMQP
Wprowadzenie do RabbitMQ
AMQP
Wprowadzenie do RabbitMQ
Virtual Hosts
Virtual Hosts
- Każdy virtual host posiada unikalną nazwę
- Są to wyizolowane brokery w serwerze zapewniające pełną separację:
- użytkowników,
- połączeń,
- kolejek,
- central wiadomości,
- obiektów powiązanych
- Standardowo serwer posiada zdefiniowanego jednego wirtualnego hosta /
- Rozwiązanie stworzone w celach administracyjnych
Virtual Hosts
Zarządzanie - Panel administracyjny
Virtual Hosts
Zarządzanie - Panel administracyjny
Lista Virtual Host
Dodawanie Virtual Host
Virtual Hosts
Zarządzanie - Panel administracyjny
Szczegóły dostępne po kliknięciu w nazwę
- przypisywanie uprawnień użytkownikom do virtual host,
- przypisywanie uprawnień do exchange,
- usuwanie
W podglądzie dostępnych jest klika bardzo istotnych opcji:
Virtual Hosts
Zarządzanie - Panel administracyjny
Virtual Hosts
Zarządzanie - CLI
rabbitmqctl list_vhosts
Lista
Dodawanie
rabbitmqctl add_vhost app_1
Usuwanie
rabbitmqctl delete_vhost app_1
Virtual Hosts
Zarządzanie - CLI
rabbitmqctl set_permissions -p app_1 guest ".*" ".*" ".*"
Przypisywanie uprawnień
rabbitmqctl set_topic_permissions -p app_1 guest amq.topic ".*" ".*"
Przypisywanie uprawnień do Topic
rabbitmqctl clear_permissions -p app_1 guest
rabbitmqctl clear_topic_permissions -p app_1 guest amq.topic
Użytkownicy
&
Uprawnienia
Użytkownicy
Uwierzytelnianie
- proste przez login i hasło,
- bardziej zaawansowane wykorzystujące certyfikaty
- domyślny użytkownik guest może logować się tylko z localhost
Tagi - definiują uprawnienia dla panelu administracyjnego
Uprawnienia - definiują możliwości użytkownika w zakresie wykonywanych operacji konfiguracyjnych, odczytu i zapisu wiadomości
Użytkownicy
Tagi - Panel administracyjny
W przypadku, gdy mówimy o uprawnieniach do panelu administracyjnego myślimy o Tagach. Dzięki nim mamy różne poziomy dostępu do panelu administracyjnego.
Użytkownicy
Tagi - Panel administracyjny
Użytkownicy
Tagi - Panel administracyjny
Nasz użytkownik guest na, którym obecnie pracujemy ma tag administrator. Dzięki czemu ma uprawnienia do wszystko w panelu administracyjnym.
Użytkownicy
Dodawanie użytkownika - PA
Użytkownicy
Dodawanie użytkownika - CLI
rabbitmqctl add_user app_1 password
Użytkownicy
Dodawanie użytkownika - CLI
# przypisujemy tag administrator
rabbitmqctl set_user_tags app_1 administrator
Użytkownicy
Uprawnienia
Mamy trzy rodzaje uprawnień:
- configure - konfiguracja, czyli zarządzanie kolejkami, centralami, połączeniami pomiędzy nimi,
- read - wszystko związane z odbiorem wiadomości,
- write - wszystko związane z odczytem wiadomości
Przypisywanie uprawnień, jest oparte o wyrażenia regularne.
- ustawienie uprawnień do dwóch kolejek "^(kolejka_1|kolejka_2)$"
- uprawnienia do wszystkiego ".*"
- brak uprawnień do czegokolwiek '^$' lub '""'
Użytkownicy
Uprawnienia - PA
Użytkownicy
Uprawnienia - CLI
rabbitmqctl list_user_permissions app_1
Lista uprawnień użytkownika
Usuwanie uprawnień
rabbitmqctl clear_permissions -p app_1 app_1
Dodawanie uprawnień
Producent
Producent
PRODUCENT
KONSUMENT
RabbitMQ
Producent
var amqp = require('amqplib/callback_api');
amqp.connect('amqp://localhost', function(err1, connection) {
if (err1)
{
return console.error(err1);
}
console.info('Connected');
connection.close();
});
connect.js
Połączenie z RabbitMQ
Producent
Połączenie z RabbitMQ
Scenariusze testowe:
- stworzenie użytkownika app_full z maksymalnymi uprawnieniami, test połączenia,
- stworzenie użytkownika app_read z uprawnieniami tylko do odczytu, test połączenia,
- stworzenie użytkownika app_write z uprawnieniami tylko do zapisu, test połączenia
amqp://username:password@localhost/vhost
Producent
Format wiadomości
RabbitMQ akceptuje dowolny ciąg znaków, co niesie ze sobą konsekwencje.
PRODUCENT 1
KONSUMENT
RabbitMQ
XML
XML
XML
Producent
Format wiadomości
RabbitMQ akceptuje dowolny ciąg znaków, co niesie ze sobą konsekwencje.
PRODUCENT 1
KONSUMENT
RabbitMQ
XML
XML JSON
PRODUCENT 2
JSON
Producent
Format wiadomości
RabbitMQ akceptuje dowolny ciąg znaków, co niesie ze sobą konsekwencje.
PRODUCENT 1
KONSUMENT
RabbitMQ
XML
XML JSON TXT
PRODUCENT 3
TXT
PRODUCENT 2
JSON
Producent
Format wiadomości
Wybierz format, który jest standardem jak JSON
Producent
Tworzenie wiadomości
var amqp = require('amqplib/callback_api');
amqp.connect('amqp://app_full:app_full@localhost/app_1', function(err1, connection) {
if (err1)
{
return console.error(err1);
}
console.info('Connected');
connection.createChannel(function(err2, channel) {
if (err2)
{
throw err2;
}
console.info('Channel created');
var queue = 'q_1';
var msg = JSON.stringify({
'text': 'Hello world'
});
channel.sendToQueue(queue, Buffer.from(msg));
console.log("[x] Sent %s", msg);
});
});
Producent
Tworzenie wiadomości
W panelu administracyjnym widzimy trwające połączenie i otwarty kanał komunikacji.
Producent
Tworzenie wiadomości
Nie widać, aby jakakolwiek wiadomość dotarła.
Producent
Tworzenie wiadomości
connection.createChannel(function(err2, channel) {
if (err2)
{
throw err2;
}
console.info('Channel created');
var queue = 'q_1';
var msg = JSON.stringify({
'text': 'Hello world'
});
channel.sendToQueue(queue, Buffer.from(msg));
console.log("[x] Sent %s", msg);
});
Producent
Tworzenie wiadomości
connection.createChannel(function(err2, channel) {
if (err2)
{
throw err2;
}
console.info('Channel created');
var queue = 'q_1';
var msg = JSON.stringify({
'text': 'Hello world'
});
// tworzy kolejkę jeśli nie istnieje
channel.assertQueue(queue, {
durable: false
});
channel.sendToQueue(queue, Buffer.from(msg));
console.log(" [x] Sent %s", msg);
});
Tworzymy kolejkę z poziomu kodu, jeśli nie istnieje
create_first_message_full.js
Producent
Tworzenie wiadomości
Producent
Tworzenie wiadomości
Czemu wysyłamy
do kolejki ??
Producent
Tworzenie wiadomości
Architektura
Producent
Tworzenie wiadomości
Architektura
Producent
TTL Wiadomości
channel.sendToQueue(queue, Buffer.from(msg), {
expiration: 15000
});
TTL czyli Time To Live to określenie czasu życia wiadomości, które może być zdefiniowane na poziomie pojedynczej wiadomości.
Aby zobaczyć jak mechanizm zadziała otwieramy plik create_first_message_ttl.js, który zawiera dodatkowy parametr określający czas życia wiadomości na 15 sek.
Producent
TTL Wiadomości
Producent
Weryfikacja czy wiadomość została doręczona
Możliwe problemy z doręczeniem wiadomości:
- brak routingu określonego w wiadomości,
- osiągnięto limit wiadomości w kolejce
Producent
Weryfikacja czy wiadomość została doręczona
Sprawdzimy scenariusz w którym osiągniemy limit wiadomości. W tym celu usuwamy kolejkę q_1 i tworzymy nową z dwoma parametrami.
Producent
Weryfikacja czy wiadomość została doręczona
Przechodzimy do pliku message_delivery_guaranteed.js
connection.createConfirmChannel(function(err2, channel) {
Pierwsza zmiana jaka zaszła to zmiana tworzonego kanału na kanał wymagający potwierdzeń createConfirmChannel
Dodany został kod generujący 10 wiadomości.
for (var i = 0; i < 10; i++)
{
var msg = JSON.stringify({
'text': 'Message ' + i
});
console.log(" [x] Sent %s", msg);
channel.sendToQueue(queue, Buffer.from(msg), {}, errorCallback(msg));
}
Producent
Weryfikacja czy wiadomość została doręczona
function errorCallback(msg) {
return function(err) {
if (err)
{
return console.log('Message: ' + msg + ' - NOT confirm');
}
console.log(msg + ' - confirm');
};
}
Przy każdym wysłaniu wiadomości do kolejki mamy funkcję, która jest wywoływana. Dozwala nam to obsłużyć błędy.
Producent
Weryfikacja czy wiadomość została doręczona
channel.waitForConfirms(function(err) {
if (err)
{
return console.log('Not confirm all message');
}
console.log('All messages confirm');
});
Ostatni element jaki został dodany to wywołanie specjalnej metody, która czeka aż wszystkie wiadomości się wykonają lub zwrócą błędy.
Producent
Weryfikacja czy wiadomość została doręczona
Mając tak przygotowaną aplikację możemy przeprowadzić testy, które pokażą czy rzeczywiście dostaniemy informacje o braku dostarczenia wiadomości.
Producent
Weryfikacja czy wiadomość została doręczona
Kolejne uruchomienie aplikacji zwróci nam same błędy.
Producent
Weryfikacja czy wiadomość została doręczona
Usuńmy 2 wiadomości z kolejki, aby sprawdzić czy rzeczywiście tylko 2 wiadomości trafią po ponownym uruchomieniu aplikacji.
Producent
Weryfikacja czy wiadomość została doręczona
Uruchamiamy jeszcze raz aplikację i sprawdzamy czy zostaną dodane dwie nowe wiadomości, a dla pozostałych otrzymamy błąd.
Exchange
Exchange
- Agent zarządzający przesyłaniem wiadomości do kolejek,
- Kilka rodzajów central wiadomości:
- Centrale wiadomości mogą mieć parametry:
- durable - przeżyje restart serwera,
- auto-delete - automatyczne usuwanie po odłączeniu ostatniej kolejki,
- dodatkowe parametry zależne od typu centrali oraz pluginów
- binding - link pomiędzy kolejką a centralą wiadomości,
- headers
- fanout
- direct
- topic
Exchange
Narzędzie do wizualizacji przepływu wiadomości w RabbitMQ
Exchange
Fanout
Wszystkie wiadomości przesłane do centrali będą przekazywane do powiązanych kolejek.
Exchange
Fanout
Wszystkie wiadomości przesłane do centrali będą przekazywane do powiązanych kolejek.
Exchange
Fanout
Wszystkie wiadomości przesłane do centrali będą przekazywane do powiązanych kolejek.
Exchange
Fanout
Definiujemy centralę wiadomości
fanout_ex
Exchange
Fanout
Definiujemy dwie kolejki
fanout_q1 i fanout_q2
Exchange
Fanout
Łączymy centralę z kolejkami binding
(możliwe z poziomu kolejki i centrali )
Exchange
Fanout
Po połączeniu powinniśmy zobaczyć
wizualizację połączeń
Exchange
Fanout
Wysyłamy wiadomość do centrali wiadomości
Exchange
Fanout
Po wysłaniu wiadomości powinniśmy otrzymać wiadomość w obu kolejkach
Exchange
Fanout
Treść możemy podejrzeć wchodząc do jednej z kolejek, a następnie w sekcji Get Messages mamy możliwość pobrania wiadomości z kolejki.
Exchange
Fanout
connection.createChannel(function(error1, channel) {
if (error1)
{
throw error1;
}
var exchange = 'fanout_ex_app';
var msg = JSON.stringify({
'text': 'Hello world'
});
// tworzy centralę wiadomości
// channel.assertExchange(exchange, 'fanout', {
// durable: false
// });
channel.publish(exchange, '', Buffer.from(msg));
console.log("[x] Sent %s", msg);
});
producer_exchange_fanout.js
Exchange
Fanout
connection.createChannel(function(error1, channel) {
if (error1){
throw error1;
}
var exchange = 'fanout_ex_app';
var queue1 = 'fanout_q1_app';
var msg = JSON.stringify({
'id': '145'
});
channel.assertExchange(exchange, 'fanout', {
durable: true
});
channel.assertQueue(queue1, {durable: true}, function(err2) {
if (err2){
throw err2;
}
channel.bindQueue(queue1, exchange);
producer_exchange_fanout_bind.js.js
Exchange
Direct
Wiadomości przesłane do centrali muszą posiadać parametr routingKey, aby zostały przesłane do kolejki o takim samym parametrze.
Exchange
Direct
Centrala w działaniu
Po co centrala ? Kolejka nie wystarczy ?
Exchange
Direct
Funkcjonalność pobierz wszystkie
Exchange
Direct
Odwzorozujemy strukturę w panelu administracyjnym
Exchange
Direct
connection.createChannel(function(error1, channel) {
if (error1)
{
throw error1;
}
var exchange = 'direct_ex';
var msg = JSON.stringify({
'id': '145'
});
channel.publish(exchange, 'epub', Buffer.from(msg));
console.log("[x] Sent %s", msg);
});
Exchange
Direct
connection.createChannel(function(error1, channel) {
if (error1) {
throw error1;
}
var exchange = 'direct_ex_app';
var queue1 = 'direct_epub_app';
var queue2 = 'direct_mobi_app';
var queue3 = 'direct_pdf_app';
var msg = JSON.stringify({
'id': '145'
});
channel.assertExchange(exchange, 'direct', {
durable: true
});
channel.assertQueue(queue1, {durable: true}, function(err2) {
if (err2){
throw err2;
}
channel.bindQueue(queue1, exchange, 'download_epub');
channel.assertQueue(queue2, {durable: true}, function(err3) {
if (err3){
throw err3;
}
channel.bindQueue(queue2, exchange, 'download_mobi');
channel.assertQueue(queue3, {durable: true}, function(err4) {
if (err4){
throw err4;
}
channel.bindQueue(queue3, exchange, 'download_pdf');
channel.publish(exchange, 'download_epub', Buffer.from(msg));
console.log("[x] Sent %s", msg);
});
});
});
});
Exchange
Topic
- Rozszerza możliwości parametru routingKey, gdzie podajemy listę słów rozdzielanych kropką
- * (gwiazdka), zastępuje pojedyncze słowo,
- # (hasz), zastępuje dowolną ilość słów
info.log
error.log
all.log
#.log
info.*
error.*
all.*
Exchange
Topic
Zastosowanie w praktyce bindowania z uwzględnieniem wyrażeń regularnych
Exchange
Topic
Tworzymy nową centralę wiadomości
topic_ex
Exchange
Topic
Tworzymy kolejki:
topic_info, topic_error, topic_all
Exchange
Topic
Tworzymy powiązanie
topic_info <--- info.* -----> topic_ex
Exchange
Topic
Tworzymy powiązanie
topic_error <--- error.* -----> topic_ex
Exchange
Topic
Tworzymy powiązanie
topic_all <--- *.log -----> topic_ex
Exchange
Topic
Wysyłamy wiadomość o routingu info.log
Exchange
Topic
Wysyłamy wiadomość o routingu error.log
Exchange
Topic
connection.createChannel(function(error1, channel) {
if (error1)
{
throw error1;
}
var exchange = 'topic_ex_app';
var queueInfo = 'topic_info_app';
var queueError = 'topic_error_app';
var queueAll = 'topic_all_app';
var msg = JSON.stringify({
'id': '145'
});
channel.assertExchange(exchange, 'topic', {
durable: true
});
channel.assertQueue(queueInfo, {durable: true}, function(err2) {
if (err2)
{
throw err2;
}
channel.bindQueue(queueInfo, exchange, 'info.*');
channel.assertQueue(queueError, {durable: true}, function(err2) {
if (err2)
{
throw err2;
}
channel.bindQueue(queueError, exchange, 'error.*');
channel.assertQueue(queueAll, {durable: true}, function(err2) {
if (err2)
{
throw err2;
}
channel.bindQueue(queueAll, exchange, '*.log');
console.log("Ready");
// channel.publish(exchange, 'info.log', Buffer.from(msg));
// console.log("[x] Sent %s", msg);
});
});
});
});
Exchange
Headers
- Bardzo podobny do typu direct z tą różnicą, że zamiast parametru routingKey wykorzystywane są nagłówki, a routingKey jest ignorowany.
- Nagłówki mogą przyjmować dowolne typy danych, a nie jak to miało miejsce w typie direct tylko string.
- Dodatkowo mamy specjalny nagłówek o nazwie x-match, który może przyjąć dwie wartości:
- any – wystarczy jedno dopasowanie, aby wiadomość trafiła do kolejki,
- all – wiadomości trafią do kolejki jedynie gdy wszystkie klucze zostaną dopasowane ( domyślne )
Exchange
Headers
RabbitMQ Simulator niestety nie wspiera tego typu centrali wiadomości. Dlatego zaprojektujemy od razu w panelu poniższą strukturę.
Exchange
Headers
Dodajemy centralę
Exchange
Headers
Dodajemy centralę
Exchange
Headers
Dodajemy kolejki
Exchange
Headers
Definiujemy połączenia pomiędzy centralą, a kolejkami.
headers_ex <-> header_info
Exchange
Headers
Definiujemy połączenia pomiędzy centralą, a kolejkami.
headers_ex <-> header_error
Exchange
Headers
Definiujemy połączenia pomiędzy centralą, a kolejkami.
headers_ex <-> header_all
Exchange
Headers
Po wszystkim powinniśmy w centrali headers_ex zobaczyć następujące połączenia
Możemy je teraz przetestować ;)
Exchange
Headers
Publikujemy wiadomości z poziomu centrali
Exchange
Headers
Publikujemy wiadomości z poziomu centrali
Exchange
Headers
Publikujemy wiadomości z poziomu centrali
Exchange
Headers
Aby zmienić zachowanie połączenia z kolejką header_all konieczne jest usunięcie bieżącego połączenia.
Exchange
Headers
Na miejsce usuniętego połączenia dodajemy nowe z uwzględnieniem parametru x-match
Exchange
Headers
Przed testami czyścimy zawartość kolejek, aby łatwiejsza była interpretacja wyników.
Exchange
Headers
Publikujemy wiadomość w centrali
headers_ex
Exchange
Headers
Publikujemy wiadomość w centrali
headers_ex
Exchange
Headers
connection.createChannel(function(error1, channel) {
// ... pominięto kod
var exchange = 'headers_ex_app';
var queueError = 'headers_log_error_app';
var queueInfo = 'headers_log_info_app';
var queueAll = 'headers_log_all_app';
var msg = JSON.stringify({
'id': '145'
});
channel.assertExchange(exchange, 'headers', {
durable: true
});
channel.assertQueue(queueError, {durable: true}, function(err2) {
// ... pominięto kod
channel.bindQueue(queueError, exchange, '', {
'log_error': '1'
});
channel.assertQueue(queueInfo, {durable: true}, function(err2) {
// ... pominięto kod
channel.assertQueue(queueAll, {durable: true}, function(err2) {
// ... pominięto kod
channel.bindQueue(queueAll, exchange, '', {
'log_info': '1',
'log_error': '1'
});
channel.publish(exchange, '', Buffer.from(msg), {
'headers': {
'log_error': '1'
}
});
console.log("[x] Sent %s", msg);
});
});
});
});
Exchange
Durable
/etc/init.d/rabbitmq-server restart
Exchange
Auto delete
- usunięcie ostatniego powiązania pomiędzy centralą, a kolejką powoduje usunięcie centrali,
- usunięcie ostatniej kolejki powiązanej z centralą spowoduje usunięcie centrali,
Exchange
Internal
Centrala wewnętrzna nie pozwala na bezpośrednie publikowanie wiadomości przez producentów.
Exchange
Internal
Centrala wewnętrzna nie pozwala na bezpośrednie publikowanie wiadomości przez producentów.
connection.createChannel(function(err1, channel) {
if (err1) {
throw err1;
}
var exchange = 'internal_ex_app';
var msg = JSON.stringify({
'id': '145'
});
channel.assertExchange(exchange, 'fanout', {
internal: true
});
channel.assertQueue('tmp_app', {durable: true}, function(err2) {
if (err2) {
throw err2;
}
channel.bindQueue('tmp_app', exchange, 'test');
channel.publish(exchange, 'test', Buffer.from(msg));
console.log("[x] Sent %s", msg);
});
});
Exchange
Alternate exchange
Jeśli wiadomość nie jest rutowalna to zostanie przesłana do innej centrali
Kolejki
Kolejki
- Dwa rodzaje kolejek:
- classic - klasyczna kolejka FIFO będąca buforem wiadomości,
- quorum - nowy rodzaj kolejek oparty o algorytm RAFT przeznaczony dla systemów rozproszonych,
- Kolejki mogą mieć parametry:
- durable - przeżyje restart serwera,
- auto-delete - automatyczne usunięcie kolejki po rozłączeniu konsumenta ( kolejki tymczasowe ),
- exclusive - dostępna tylko dla jednego kanału
Kolejki
Zarządzanie
Kolejki
Zarządzanie - CLI
rabbitmqctl list_queues -p app_1
Lista kolejek
Jeśli chcemy wyświetlić konkretne kolumny to podajemy je na końcu polecenia.
rabbitmqctl list_queues -p app_1 name durable
rabbitmqadmin -V app_1 declare queue name=test
Dodawanie kolejek
Kolejki
Durable - przeżyć restart serwera
connection.createChannel(function (err2, channel) {
if (err2) {
throw err2;
}
console.info('Channel created');
var queue = 'q_durable_fale_app';
var msg = JSON.stringify({
'text': 'Czy wiadomość przetrwa restart serwera ??'
});
channel.assertQueue(queue, {
durable: false
});
channel.sendToQueue(queue, Buffer.from(msg));
console.log("OK");
});
Producent tworzy kolejkę z ustawionym parametrem durable na false. Co spowoduje, że kolejka zostanie usunięta po restarcie serwera.
/etc/init.d/rabbitmq-server restart
durable_false_producer.js
Kolejki
TTL
Wcześniej definiowaliśmy TTL na poziomie wiadomości,
ale czas życia wiadomości może być zdefiniowany w kolejce.
Kolejki
TTL
Do tak zdefiniowanej kolejki możemy dodać wiadomość i zobaczyć czy rzeczywiście zostanie usunięta po 15 sekundach.
Kolejki
TTL
connection.createChannel(function (err2, channel) {
if (err2) {
throw err2;
}
console.info('Channel created');
var queue = 'q_ttl_app';
var msg = JSON.stringify({
'text': 'TTL 15s.'
});
channel.assertQueue(queue, {
messageTtl: 15000
});
channel.sendToQueue(queue, Buffer.from(msg));
console.log("OK");
});
ttl_producer.js
Producent tworzy kolejkę z ustawionym maksymalnym czasem życia wiadomości na 15 sek.
Kolejki
Expiry
connection.createChannel(function (err2, channel) {
if (err2) {
throw err2;
}
console.info('Channel created');
var queue = 'q_expiry_app';
channel.assertQueue(queue, {
expires: 15000
});
var msg = JSON.stringify({
'text': 'Hello world'
});
channel.sendToQueue(queue, Buffer.from(msg));
console.log(" [x] Sent %s", msg);
});
expiry_producer.js
Producent tworzy kolejkę z ustawionym maksymalnym czasem życia na 15 sek. Jeśli w tym czasie nie podłączy się żaden konsument to kolejka zostanie usunięta.
Kolejki
Expiry
connection.createChannel(function(err2, channel) {
if (err2)
{
throw err2;
}
channel.consume('q_expiry_app', function(msg) {
console.log(msg);
});
console.info('OK');
});
expiry_consumer.js
Konsument podtrzymujący życie kolejki do czasu rozłączenia. Brak potwierdzenia pobrania wiadomości spowoduje oznaczenie wiadomości jako Unacked
Kolejki
Tymczasowe
Kolejka jest usuwana, gdy ostatni konsument zakończy połączenie
Kolejki
Tymczasowe
Uruchamiamy plik consumer_connect.js jego jedynym zadaniem jest podłączenie do kolejki. Pobranie wiadomości jeśli są jakieś w kolejce i wyświetlenie ich w konsoli.
W kolejce wyświetli się informacja, że jest podłączony jeden konsument.
Kolejki
Tymczasowe
Po zakończeniu działania konsumenta Ctrl + C kolejka powinna zostać automatycznie usunięta. A nam w panelu wyświetli się poniższy komunikat.
Kolejki
Tymczasowe
connection.createChannel(function (err2, channel) {
if (err2) {
throw err2;
}
console.info('Channel created');
channel.assertQueue('q_auto_delete', {
autoDelete: true
});
console.log("OK");
});
Producent tworzy kolejkę, która zostanie usunięta automatycznie po rozłączeniu ostatniego konsumenta
auto_delete_producer.js
Kolejki
Tymczasowe
connection.createChannel(function(err2, channel) {
if (err2)
{
throw err2;
}
channel.consume('q_auto_delete', function(msg) {
console.log(msg);
});
console.info('OK');
});
Konsument kolejki po rozłączeniu spowoduje automatyczne usunięcie kolejki
auto_delete_consumer.js
Kolejki
Max Length
connection.createChannel(function(err2, channel) {
if (err2)
{
throw err2;
}
console.info('Channel created');
var queue = 'q_max_length_10_app';
channel.assertQueue(queue, {
maxLength: 10
});
for (var i = 0; i < 20; i++)
{
var msg = JSON.stringify({
'text': 'Message ' + i
});
console.log(" [x] Sent %s", msg);
channel.sendToQueue(queue, Buffer.from(msg));
}
});
Umożliwia określenie maksymalnej ilości wiadomości jaka może być przechowywana w kolejce.
max_length_producer.js
Kolejki
Max Length + Overflow
connection.createChannel(function(err2, channel) {
if (err2){
throw err2;
}
console.info('Channel created');
var queue = 'q_max_length_10_app';
channel.assertQueue(queue, {
maxLength: 10,
overflow: 'reject-publish'
});
for (var i = 0; i < 20; i++)
{
var msg = JSON.stringify({
'text': 'Message ' + i
});
console.log(" [x] Sent %s", msg);
channel.sendToQueue(queue, Buffer.from(msg));
}
});
Parametr x-max-length występuje w połączeniu z parametrem
x-overflow. A to dlatego, że przepełnienie kolejki może spowodować pewne zachowania:
- drop-head, usunięcie wiadomości z kolejki ( domyślne zachowanie ),
- reject-publish, odrzucenie przesyłanej wiadomości
max_length_overflow_reject_producer.js
Kolejki
Single Active Consumer
Pozwala na wykorzystywanie kolejki tylko jednemu konsumentowi.
Kolejki
Single Active Consumer
connection.createChannel(function(err2, channel) {
if (err2)
{
throw err2;
}
channel.consume('q_single_active_consumer_app', function(msg) {
setTimeout(function () {
console.log(msg.content.toString());
channel.ack(msg);
}, 1000);
});
console.info('OK');
});
single_active_consumer_consumer.js
Konsument
Kolejki
Lazy
- zapisuje wszystkie wiadomości na dysku natychmiast,
- wpływa na wydajność, gdyż zależna jest od IO dysku,
- rozwiązanie to tworzy bardziej stabilny klaster z przewidywalną wydajnością,
- zaleca się stosowanie, gdy spodziewamy się dużych ilości wiadomości, których konsument prawdopodobnie nie będzie w stanie obsłużyć,
- należy wyłączyć opcję, gdy oczekujemy bardzo dużej wydajności i jesteśmy pewni, że nasze kolejki będą krótkie
Kolejki
Dead Letter Exchange - DLX
Kolejki
Dead Letter Exchange - DLX
Kolejki
Dead Letter Exchange - DLX
Kolejki
Dead Letter Routing Key
Zastępuje routingKey, gdy wiadomość jest niepotwierdzona
Konsument
Konsument
PRODUCENT
KONSUMENT
RabbitMQ
Konsument
Pobieranie wiadomości
connection.createChannel(function(err2, channel) {
if (err2) {
throw err2;
}
channel.consume('report_app', function(msg) {
console.log(msg.content.toString());
});
console.info('OK');
});
Konsument
Pobieranie wiadomości
fields
- exchange,
- routingKey,
- redelivered
properties
- headers,
- expiration
content
Zwracana wiadomość zawiera:
Konsument
Potwierdzanie wiadomości
connection.createChannel(function(err2, channel) {
if (err2) {
throw err2;
}
channel.consume('test', function(msg) {
console.log(msg.content.toString());
// console.log('Potwierdzam przetworzenie');
// channel.ack(msg);
});
console.info('OK');
});
Konsument
Obsługa błędów
connection.createChannel(function(err2, channel) {
if (err2) {
throw err2;
}
channel.consume('report_app', function(msg) {
console.log(msg.content.toString());
console.log('Error - powrót do kolejki');
setTimeout(function() {
channel.nack(msg);
}, 15000);
});
console.info('OK');
});
Zarządzanie RabbitMQ
Zarządzanie RabbitMQ
Plik konfiguracyjny
/etc/rabbitmq/rabbitmq.conf
# od wersji 3.8
load_definitions = /etc/rabbitmq/definitions.json
# starsze wersje
# management.load_definitions = /etc/rabbitmq/definitions.json
/etc/init.d/rabbitmq-server restart
/etc/init.d/rabbitmq-server status
Zarządzanie RabbitMQ
Plik konfiguracyjny
/etc/rabbitmq/definitions.json
{
"users": [
{
"name": "app_2",
"password": "app_2",
"tags": "administrator"
}
]
}
Zarządzanie RabbitMQ
Plik konfiguracyjny
/etc/rabbitmq/definitions.json
{
"vhosts":[
{
"name":"app_2"
}
]
}
Zarządzanie RabbitMQ
Plik konfiguracyjny
/etc/rabbitmq/definitions.json
{
"permissions": [
{
"user": "app_2",
"vhost": "app_2",
"configure": ".*",
"write": ".*",
"read": ".*"
}
]
}
Zarządzanie RabbitMQ
Plik konfiguracyjny
/etc/rabbitmq/definitions.json
{
"exchanges": [
{
"vhost": "app_2",
"name": "reports_ex",
"type": "direct",
"durable": true,
"auto_delete": false,
"arguments": {}
}
]
}
Zarządzanie RabbitMQ
Plik konfiguracyjny
/etc/rabbitmq/definitions.json
{
"queues":[
{
"name":"reports_pdf",
"vhost":"app_2",
"durable":true,
"auto_delete":false,
"arguments":{}
}
]
}
Zarządzanie RabbitMQ
Plik konfiguracyjny
/etc/rabbitmq/definitions.json
{
"bindings": [
{
"arguments":{},
"destination":"reports_pdf",
"destination_type":"queue",
"routing_key":"download_pdf",
"source":"reports_ex",
"vhost":"app_2"
}
]
}
Zarządzanie RabbitMQ
Plik konfiguracyjny
/etc/rabbitmq/definitions.json
{
"users": [
{
"name": "app_2",
"password": "app_2",
"tags": "administrator"
}
],
"vhosts":[
{
"name":"app_2"
}
],
"permissions": [
{
"user": "app_2",
"vhost": "app_2",
"configure": ".*",
"write": ".*",
"read": ".*"
}
],
"parameters": [],
"policies": [],
"queues":[
{
"name":"reports_pdf",
"vhost":"app_2",
"durable":true,
"auto_delete":false,
"arguments":{}
}
],
"exchanges": [
{
"vhost": "app_2",
"name": "reports_ex",
"type": "direct",
"durable": true,
"auto_delete": false,
"arguments": {}
}
],
"bindings": [
{
"arguments":{},
"destination":"reports_pdf",
"destination_type":"queue",
"routing_key":"download_pdf",
"source":"reports_ex",
"vhost":"app_2"
}
]
}
Zarządzanie RabbitMQ
Plik konfiguracyjny
rabbitmqctl import_definitions /etc/rabbitmq/definitions.json
Import pliku - nie wymaga pluginu management
rabbitmqadmin import /etc/rabbitmq/definitions.json
Import pliku - wymaga pluginu management
curl --user guest:guest --data "@/etc/rabbitmq/definitions.json" --header "Content-Type: application/json" --request POST http://127.0.0.1:15672/api/definitions
Import pliku przez API
Zarządzanie RabbitMQ
Plik konfiguracyjny
rabbitmqctl export_definitions /etc/rabbitmq/definitions.file.json
Eksport danych do pliku - nie wymaga pluginu management
rabbitmqadmin export /etc/rabbitmq/definitions_export.json
Eksport danych do pliku - wymaga pluginu management
curl --user guest:guest --header "Content-Type: application/json" --request GET http://127.0.0.1:15672/api/definitions > export_data.json
Eksport do pliku przez API
Zarządzanie RabbitMQ
REST API
Zarządzanie RabbitMQ
REST API
http://localhost:15672/api/vhosts
Lista vhosts
http://localhost:15672/api/exchanges
Lista central
curl -u guest:guest http://localhost:15672/api/vhosts
Lista vhosts - CURL
curl -u guest:guest http://localhost:15672/api/vhosts | json_pp -json_opt pretty,canonical
Zarządzanie RabbitMQ
Z linii poleceń - CLI
rabbitmqctl list_queues name durable arguments
rabbitmqctl list_queues name type durable --formatter=pretty_table
Ładne formatowanie zwracanych informacji
Standardowe formatowanie zwracanych informacji
rabbitmqadmin list queues
Ładne formatowanie zwracanych informacji
rabbitmqctl list_queues name durable arguments --formatter=pretty_table --silent
Ładne formatowanie zwracanych informacji - bez nagłówka
Klaster
Klaster
Replikacja w RabbitMQ wspierana jest natywnie w trybie master-slave.
W RabbitMQ znajdziesz dwa typy węzłów:
- Węzeł dysku , gdzie wykonawcze stan klastra zapisywane RAM lub węzłów dysku.
- Węzeł RAM , która przechowuje stan wykonania w pamięci.
Klaster
docker run -d \
--name rabbit_cluster_1 \
--hostname docker1 \
-e RABBITMQ_ERLANG_COOKIE="cookie" \
-e RABBITMQ_NODENAME=rabbit1 \
-p 5673:5672 \
-p 15673:15672 \
-p 25673:25672 \
rabbitmq:3.8-management
Node 1 - master
Tworzymy klaster
Klaster
Tworzymy klaster
docker run -d \
--name rabbit_cluster_2 \
--hostname docker2 \
-e RABBITMQ_ERLANG_COOKIE="cookie" \
-e RABBITMQ_NODENAME=rabbit2 \
-p 5674:5672 \
-p 15674:15672 \
-p 25674:25672 \
--link rabbit_cluster_1 \
rabbitmq:3.8-management
Node 2 - slave
docker run -d \
--name rabbit_cluster_3 \
--hostname docker3 \
-e RABBITMQ_ERLANG_COOKIE="cookie" \
-e RABBITMQ_NODENAME=rabbit3 \
-p 5675:5672 \
-p 15675:15672 \
-p 25675:25672 \
--link rabbit_cluster_1 \
--link rabbit_cluster_2 \
rabbitmq:3.8-management
Node 3 - slave
Klaster
Panel administracyjny - brak węzłów
Klaster
docker exec -it rabbit_cluster_2 /bin/bash
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl join_cluster rabbit1@docker1
rabbitmqctl start_app
Konieczne jest usuniecie stanu środowiska uruchomieniowego RabbitMQ w tym węźle, aby pomyślnie dołączyć go do klastra
Zatrzymujemy wewnętrzne procesy
Dołączamy do klastra
Uruchamiamy wewnętrzne procesy
Dodawanie węzłów do klastra
Klaster
Panel administracyjny - po dodaniu węzła
Klaster
Konfiguracja
version: '3'
services:
rabbit1:
image: rabbitmq:3.8-management
hostname: docker1
environment:
- RABBITMQ_ERLANG_COOKIE=test
- RABBITMQ_NODENAME=rabbit1
ports:
- "5673:5672"
- "15673:15672"
- "25673:25672"
volumes:
- ./rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf
rabbit2:
image: rabbitmq:3.8-management
depends_on:
- rabbit1
hostname: docker2
ports:
- "5674:5672"
- "15674:15672"
- "25674:25672"
environment:
- RABBITMQ_ERLANG_COOKIE=test
- RABBITMQ_NODENAME=rabbit2
volumes:
- ./rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf
rabbit3:
image: rabbitmq:3.8-management
depends_on:
- rabbit1
hostname: docker3
ports:
- "5675:5672"
- "15675:15672"
- "25675:25672"
environment:
- RABBITMQ_ERLANG_COOKIE=test
- RABBITMQ_NODENAME=rabbit3
volumes:
- ./rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf
docker-compose.yml
Klaster
Plik konfiguracyjny
loopback_users = none
listeners.tcp.default = 5672
cluster_formation.peer_discovery_backend = rabbit_peer_discovery_classic_config
cluster_formation.classic_config.nodes.1 = rabbit1@docker1
cluster_formation.classic_config.nodes.2 = rabbit2@docker2
cluster_formation.classic_config.nodes.3 = rabbit3@docker3
rabbitmq.conf
docker-compose.yml
volumes:
- ./rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf
Klaster
Plik konfiguracyjny
global
log 127.0.0.1 local1
maxconn 4096
defaults
log global
mode tcp
option tcplog
retries 3
option redispatch
maxconn 2000
timeout connect 5000
timeout client 50000
timeout server 50000
listen stats
bind *:1936
mode http
stats enable
stats hide-version
stats realm Haproxy\ Statistics
stats uri /
listen rabbitmq
bind *:5672
mode tcp
balance roundrobin
timeout client 3h
timeout server 3h
option clitcpka
server rabbitmq1 rabbitmq1:5672 check inter 5s rise 2 fall 3
server rabbitmq2 rabbitmq2:5672 check inter 5s rise 2 fall 3
server rabbitmq3 rabbitmq3:5672 check inter 5s rise 2 fall 3
listen mgmt
bind *:15672
mode tcp
balance roundrobin
timeout client 3h
timeout server 3h
option clitcpka
server rabbitmq1 rabbitmq1:15672 check inter 5s rise 2 fall 3
server rabbitmq2 rabbitmq2:15672 check inter 5s rise 2 fall 3
server rabbitmq3 rabbitmq3:15672 check inter 5s rise 2 fall 3
haproxy.cfg
Klaster
Producent
let amqp = require('amqp-connection-manager');
let q = 'tasks_app';
function sleep(ms) {
if(ms <= 0){
return
}
return new Promise(resolve => setTimeout(resolve, ms));
}
let main = async () => {
var connection = amqp.connect([
'amqp://localhost:5672',
'amqp://localhost:5673',
'amqp://localhost:5674',
]);
var channelWrapper = connection.createChannel({
json: true,
setup: function(channel) {
return channel.assertQueue(q, { durable: true });
}
});
console.log('Starting message stream')
while (true) {
await channelWrapper.sendToQueue(q, { value: Math.random() })
await sleep(100)
}
}
main()
cluster_producer.js
Klaster
Konsument
let amqp = require('amqp-connection-manager');
let q = 'tasks_app';
let main = async () => {
var connection = amqp.connect([
'amqp://localhost:5672',
'amqp://localhost:5673',
'amqp://localhost:5674',
]);
var channelWrapper = connection.createChannel({
json: true,
setup: function(channel) {
return channel.assertQueue(q, { durable: true });
}
});
channelWrapper.addSetup(function(channel) {
return Promise.all([
channel.consume(q, (msg) => {
console.log(msg.content.toString())
}, {noAck: true , exclusive: false })
])
});
}
main()
cluster_consumer.js
Klaster
Mirrored Queues
Klaster
Mirrored Queues
Replikacja danych ma kilka trybów ha-mode:
- all - kopia na każdym węźle,
- exactly - stałą liczbę kopii,
- nodes - na konkretnych węzłach
Dodawanie kolejnych replik może odbywa się w dwóch trybach synchronizacji ha-sync-mode:
- automatic - automatyczna synchronizacja,
- manual - ręczna, która nie blokuje kolejki na czas synchronizacji
W przypadku awarii master node, następuje wyłonienie nowego master node z slave node.
Klaster
Mirrored Queues
Klaster
Mirrored Queues
Klaster
Quorum Queues
Klaster
Quorum Queues
Zalety
- kolejki Quorum Queues kładą nacisk na bezpieczeństwo danych,
- uproszczenie replikacji,
- nadają się jako długożyjące kolejki pełniące krytyczne funkcje,
- gwarantują bezpieczeństwo wiadomości w przypadku awarii węzłów ( kworum N/2+1 )
- minimum 3 węzły,
- klaster toleruje utratę 1 węzła przy klastrze trzywęzłowym, 2 przy klastrze 5 węzłowym,
Klaster
Quorum Queues
Ograniczenia
- nie wspierają parametru exclusive ( kolejki usuwane po rozłączeniu ),
- nie wspierają parametru TTL ( usunięcie kolejki po określonym czasie, od rozłączenia ostatniego konsumenta ),
- kolejki zawsze są trwałe ( durable )
- brak zastosowania lazy mode, gdyż wiadomości zawsze są zapisywane na dysk oraz trzymane w pamięci
Klaster
Quorum Queues
Dodajemy kolejkę
Klaster
Quorum Queues
Po dodaniu kolejki na liście powinna pojawi się nasza kolejka typu Quorum oraz informacja o jej synchronizacji
Klaster
Quorum Queues
quorum_producer.js
connection.createConfirmChannel(function(err2, channel) {
if (err2){
throw err2;
}
console.info('Channel created');
var queue = 'quorum_q1';
var msg = JSON.stringify({
'text': 'Message 1'
});
console.log(" [x] Sent %s", msg);
channel.sendToQueue(queue, Buffer.from(msg), {}, errorCallback(msg));
channel.waitForConfirms(function(err3) {
if (err3) {
return console.log('Not confirm all message');
}
console.log('All messages confirm');
});
});
Connected
Channel created
[x] Sent {"text":"Message 1"}
{"text":"Message 1"} - confirm
All messages confirm
wynik działania
Klaster
Quorum Queues
Klaster
Quorum Queues
Klaster
Quorum Queues
docker stop mle_rabbit2_1
docker ps
node quorum_producer.js
Connected
Channel created
[x] Sent {"text":"Message 1"}
{"text":"Message 1"} - confirm
All messages confirm
Klaster
Quorum Queues
docker stop mle_rabbit3_1
node quorum_producer.js
Connected
Channel created
[x] Sent {"text":"Message 1"}
Message: {"text":"Message 1"} - NOT confirm
Not confirm all message
Dziękuję :)
Materiały dodatkowe
- https://www.cloudamqp.com/blog/part4-rabbitmq-13-common-errors.html
- https://sleeplessbeastie.eu/2020/03/18/how-export-or-import-rabbitmq-configuration/
- https://tomasz.jarosik.online/2018/09/rabbitmq-performance-test-in-a-home-lab/
- https://git.zabbix.com/projects/ZBX/repos/zabbix/browse/templates/app/rabbitmq_http
- https://www.rabbitmq.com/prometheus.html
- https://www.rabbitmq.com/monitoring.html#rabbitmq-metrics
RabbitMQ Basic
By Marcin Lewandowski
RabbitMQ Basic
- 764