RabbitMQ uvodni tutorijal (koncepti, scenariji upotrebe, instalacija, korišćenje)
RabbitMQ uvodni tutorijal (koncepti, scenariji upotrebe, instalacija, korišćenje)
Ono čime čovek najviše treba da se ponosi u životu nije toliko koliko bogatstva ima (mada zvuči pomalo licemerno, hehe), koliko njegova sposobnost učenja. Brzina kojom se tehnologija obnavja i menja je izuzetno visoka, pa kao programeri treba da imamo srce koje grli promene i da joj aktivno idemo u susret.
Pre nego što sam ušao u RabbitMQ, već sam ušao u Redis, Elasticsearch i MongoDB, što me čini prilično geeks duhom — i to je osećaj koji jako prija.

Pre nego što nastavite sa čitanjem, moram da naglasim jednu stvar: RabbitMQ nisam istraživao neki pretjerano duboko, učim ga jednostavno zato što mi treba. Ali, kao odgovoran tehnički bloger, srce sam u to uložio — čim pročitate ovaj uvodni tutorijal, siguran sam da ćete biti zadovoljni i da ćete neizdrživo poželeti da lajkujete i podelite ga.
Naravno, ako u tekstu naiđete na greške, nemojte biti blagi — slobodno možete doći u grupi da me izbodete, ali samo pod jednim uslovom: nemojte me udarati po licu, plašim se da mi se naruši izgled.
01. Šta je RabbitMQ
Pre svega, znam da je zec (rabbit) — zec (ajde, malo se pohvalio znanjem engleskog), i ta slatka slika mi je već iskočila u glavi. A šta je onda MQ? To je skraćenica od Message Queue, što znači da je RabbitMQ open source sistem reda poruka.
Glavne osobine RabbitMQ-a su robusnost, lakoća upotrebe, visoke performanse, visoka konkurentnost, lako proširive klastere i snažna podrška open source zajednice. Ukratko — prilično moćna stvar.
Pre devet godina, kada sam radio trgovinu terminskim ugovorima (futures), takođe mi je trebalo slanje poruka (push). Tada nisam ni znao da potražim gotov middleware, pa sam koristio sopstveni red implementiran od nule — na kraju je iskrslo mnogo bagova, od kojih neki ni danas nisu rešeni. Zaista su to sećanja na koja ne prijaju da se misli.
Slika ispod je model poruka RabbitMQ-a (preuzeta sa interneta; ako se kosi sa autorskim pravima, neka se ukloni) — hajde da ga „osetite".

P je Producer, odnosno proizvođač — strana koja šalje poruke i može ih slati ka X.
X je Exchange (zašto nije E, i meni je radoznalo), odnosno razmena — prihvata poruke koje šalje proizvođač i, na osnovu rutiranja, prosleđuje ih u zadate redove.
Q je Queue, odnosno red — tu se čuvaju poruke koje pošalje Exchange.
C je Consumer, odnosno potrošač — primalac poruka, koji iz reda uzima poruke.
Kada sam ovako objasnio, utisak o RabbitMQ-u postaje prilično konkretan, zar ne? Hajde da krenemo sa učenjem!
02. Instalacija Erlang-a
Zar ne, zašto ne instalacija RabbitMQ-a? Hajde prvo da vidimo zvanično objašnjenje.

Ne razumem baš najbolje engleski, ali nema veze, dodaćemo par reči „ljudskog" objašnjenja. RabbitMQ server je napisan u jeziku Erlang, a njegov instalacioni paket ne uključuje Erlang okruženje, pa je zato najpre potrebno instalirati Erlang. Ne brigte, instalacija Erlang-a nema nikakvu težinu.
Adresa za preuzimanje Erlang-a je:
https://erlang.org/download/otp_versions_tree.html
Najsvežija verzija je 23.0.1, izabrao sam 64-bitnu verziju, veličine oko 104 MB. Kada se preuzme, samo dvokliknite pokrenite instalaciju — potpuno je „hladan" („dalje, dalje, dalje") proces.

Važno je napomenuti da mi se tokom instalacije računar jednom restartovao — izgleda da je trebalo instalirati neku biblioteku, a pre restarta sam zaboravio da sačuvam sliku (izvinjavam se). Nakon restarta, ponovo dvokliknite na fajl otp_win64_23.0.1.exe i time završavate instalaciju Erlang-a.
03. Instalacija RabbitMQ-a
Kada se Erlang uspešno instalira, možete instalirati i RabbitMQ. Adresa za preuzimanje je:
https://www.rabbitmq.com/install-windows.html
Pronađite poziciju na slici ispod i preuzmite fajl iz crvenog okvira.

Instalacioni paket veličine je samo 16,5 MB, što je zaista lako. Pošto ga preuzmete, dvokliknite na exe fajl i instalirajte ga na „dalje, dalje, dalle" način.

Kada se instalacija završi, RabbitMQ se može pokrenuti kao Windows servis, a njime možete upravljati iz „Start" menija.

Kliknite na „RabbitMQ Command Prompt (sbin dir)" da uđete u komandnu liniju, a unosom rabbitmqctl.bat status možete potvrditi status pokretanja RabbitMQ-a.

Mogu se videti neke informacije o statusu RabbitMQ-a:
- ID procesa, odnosno PID, je 2816
- Operativni sistem je Windows
- Trenutna verzija je 3.8.4
- Konfiguracija Erlang-a
Komandna linija ne deluje baš preterano elegantno, pa možemo uneti sledeću komandu kako bismo omogućili dodatak za klijentski menadžment UI:
rabbitmq-plugins enable rabbitmq_managementKada vidite sledeću poruku, možete potvrditi da je dodatak uspešno omogućen.

U adresnu traku pregledača unesite http://localhost:15672/ i ući ćete u interfejs menadžmenta, kao na slici ispod:

04. Korišćenje RabbitMQ-a u Javi
Neki drugovi možda pitaju: „Erge, ja sam Java programer, kako da koristim RabbitMQ u Javi?" Odlično pitanje — evo odmah, evo odmah.
Prvi korak: u projekat dodajte zavisnost RabbitMQ klijenta:
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>5.9.0</version>
</dependency>Drugi korak: hajde da simuliramo najsimpleniji scenario — jedan proizvođač šalje poruku u red, a jedan potrošač iz reda čita poruku i ispisuje je.

Zvanično postoji vrlo dobro objašnjenje RabbitMQ-a, koje ću ovde slobodno „posuditi". U vreme kada sam išao u srednju školu, najpopularniji način komunikacije među đacima nije bio QQ, WeChat, čak ni SMS, već pisma. Jer tada nije bilo pametnih telefona, a i škola je za vreme nastave strogo zabranjivala upotrebu telefona, pa su pisma bila najbolji način za izražavanje osećanja. Kako li samo nedostaju.
Zamislimo da sam devojci Xiaoxiang napisao ljubavno pismo, čiji je sadržaj sledeći:
Za Xiaoxiang Zdravo, Xiaoxiang. Otkad si otišla, svaki dan mi je teskobno, baš kao Don Kihot koji svakog dana misli na Dulsineju iz Toboza. Sada sam već stvorio naviku da te nalazim na svaka dva-tri dana i kažem ti nekoliko reči koje ne bih rekao nikome drugom. ... Wang Er, 20. maj
Da bih to ljubavno pismo poslao Xiaoxiang, moram otići na poštu, kupiti marke i ubaciti ga u poštanski sanduče. A da bi devojka primila to pismo, poštar mora biti savesan i paziti da ga ne izgubi.
RabbitMQ je baš kao pošta — samo što ne obrađuje pisma, već poruke. Već je objašnjeno: P je proizvođač, C je potrošač.
Napravimo klasu proizvođača Wanger:
public class Wanger {
private final static String QUEUE_NAME = "love";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
String message = "Xiaoxiang, sviđaš mi se.";
channel.basicPublish("", QUEUE_NAME, null, message.getBytes(StandardCharsets.UTF_8));
System.out.println(" [Wang Er] poslao '" + message + "'");
}
}
}QUEUE_NAME je ime reda — to znači da će poruka koju pošalje proizvođač biti smeštena u red „love".
Kreiranje veze sa serverom radi se na sledeći način:
ConnectionFactory factory = new ConnectionFactory();
try (Connection connection = factory.newConnection();
Channel channel = connection.createChannel()) {ConnectionFactory je veoma pogodna factory klasa koja se koristi za kreiranje podrazumevanog pristupa RabbitMQ-u (ime hosta je „localhost"). Zatim se kreira kanal (Channel) preko kojeg se šalju poruke.
Klase Connection i Channel obje implementiraju interfejs Closeable, pa se može iskoristiti try-with-resource instrukcija. Ako nekom drugu try-with-resource nije blizak, može pogledati moj raniji članak o tome.
Pri slanju poruke obavezno se postavlja ime reda, i to preko metode
queueDeclare().Metoda
basicPublish()služi za objavljivanje poruke:
- prvi parametar je razmena (exchange); u trenutnom scenariju nije potrebna, pa se postavlja na prazan string;
- drugi parametar je ključ rutiranja (routingKey); za sada se popunjava imenom reda;
- treći parametar su ostala svojstva poruke (BasicProperties); za sada se ne konfiguriše;
- četvrti parametar je telo poruke, ovde u obliku UTF-8 niza bajtova, što efikasno sprečava mojibake („kineske“ izvitoperene znakove).
Sad kad imamo klasu proizvođača, hajde da napravimo i klasu potrošača XiaoXiang:
public class XiaoXiang {
private final static String QUEUE_NAME = "love";
public static void main(String[] args) throws IOException, TimeoutException {
ConnectionFactory factory = new ConnectionFactory();
Connection connection = factory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare(QUEUE_NAME, false, false, false, null);
System.out.println("Čekam na prijem poruke");
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), "UTF-8");
System.out.println(" [Xiaoxiang] primljena poruka '" + message + "'");
};
channel.basicConsume(QUEUE_NAME, true, deliverCallback, consumerTag -> { });
}
}Kod za kreiranje kanala je skoro isti kao kod proizvođača, samo što ovde nije iskorišćena
try-with-resourceinstrukcija za automatsko zatvaranje veze i kanala — želimo da potrošač zadrži vezu sve dok je nasilno ne zatvorimo.Pri prijemu poruka obavezno se postavlja ime reda, i to preko metode
queueDeclare().Pošto će nam RabbitMQ poruke dostavljati asinhrono, potrebno je da obezbedimo povratni poziv (callback) koji će ih baferovati dok se ne pripremimo da ih primimo.
DeliverCallback deliverCallback = (consumerTag, delivery) -> {
String message = new String(delivery.getBody(), "UTF-8");
System.out.println(" [Xiaoxiang] primljena poruka '" + message + "'");
};Metoda basicConsume() služi za prijem poruka:
prvi parametar je ime reda (queue), koje mora odgovarati imenu kod proizvođača („love").
drugi parametar je autoAck — ako je
true, to znači da server poruke isporučuje odjednom. Kako da se shvati ovaj koncept? Drugovi možete, pre nego što pokrenete klasu potrošačaXiaoXiang, prvo više puta pokrenuti klasu proizvođačaWangeri poslati više poruka u red; kada se potrošač pokrene, videćete da se više poruka primi odjednom — baš kao što je prikazano ispod.
Čekam na prijem poruke
[Xiaoxiang] primljena poruka 'Xiaoxiang, sviđaš mi se.'
[Xiaoxiang] primljena poruka 'Xiaoxiang, sviđaš mi se.'
[Xiaoxiang] primljena poruka 'Xiaoxiang, sviđaš mi se.'treći parametar je DeliverCallback, dakle funkcija povratnog poziva za poruku.
četvrti parametar je CancelCallback — nisam baš još shvatio čemu tačno služi.
Tokom procesa slanja poruke, možete preko menadžment panela RabbitMQ-a videti i grafikon kretanja poruka, kao na slici ispod.

