Obsah
1. Apache ActiveMQ – další systém implementující message brokera
2. Protokoly podporované systémem Apache ActiveMQ
4. Základní příkazy podporované nástrojem activemq
5. Použití nástroje activemq pro poslání popř. pro přijetí zprávy
6. Komunikační protokol STOMP a knihovna stomp.py
7. Jednoduchý producent zpráv naprogramovaný v Pythonu
8. Konzument zpráv naprogramovaný taktéž v Pythonu
9. Využití komunikační strategie PUSH-PULL s frontami zpráv
10. Sledování stavu Apache ActiveMQ z konzole
11. Webové rozhraní Apache ActiveMQ
12. Přístup k nastavení a stavu Apache ActiveMQ s využitím nástroje JConsole
13. Ukázka komunikace s Apache ActiveMQ s využitím telnetu přes protokol STOMP
14. Připojení a poslání zprávy do fronty
15. Další příkazy podporované protokolem STOMP
16. Od Apache ActiveMQ k Red Hat AMQ
17. Součásti (komponenty) systému Red Hat AMQ
18. Repositář s demonstračními příklady
19. Odkazy na předchozí části seriálu
1. Apache ActiveMQ – další systém implementující message brokera
V dnešním článku si ukážeme základní práci s message brokerem nazvaným Apache ActiveMQ (neboli zkráceně Apache AMQ). Tento systém je naprogramován v Javě (i když obsahuje i jednu nativní knihovnu), podporuje velké množství komunikačních protokolů (včetně AMQP a STOMPu) a nabízí poměrně široké možnosti konfigurace. Pro práci s tímto message brokerem využijeme protokol STOMP a knihovnu stomp.py určenou pro jazyk Python 2 a samozřejmě i Python 3. Tato knihovna podporuje obě nejpoužívanější komunikační strategie: PUB-SUB i PUSH-PULL (s frontami), popř. lze nakonfigurovat směrování zpráv a dokonce i jejich persistenci (uložení do různých typů databází, což je téma, které si popíšeme příště).
2. Protokoly podporované systémem Apache ActiveMQ
Se systémem Apache ActiveMQ je možné komunikovat pomocí několika protokolů. Některé protokoly, typicky ty, které jsou navrženy právě pro message brokery, se používají jak pro posílání zpráv, tak i pro jejich příjem. Další protokoly jsou zaměřeny pouze pro komunikaci jedním směrem, například pro informaci zaregistrovaných klientů o tom, že je k dispozici nějaká zpráva. V následující tabulce jsou jednotlivé protokoly vypsány, přičemž pro klasické message brokery nás budou zajímat především první tři řádky tabulky:
Zkratka | Protokol |
---|---|
AMQP 1.0 | Advanced Message Queuing Protocol verze 1.0 |
STOMP | Streaming Text Oriented Messaging Protocol |
MQTT | MQTT is a machine-to-machine connectivity protocol |
OpenWire | tato zajímavá technologie bude popsána v samostatném článku |
REST | Representational state transfer |
RSS a Atom | RDF Site Summary, informace klientů se zprávou |
WSIF | Web Services Invocation Framework |
WS Notification | |
XMPP | Extensible Messaging and Presence Protocol |
AUTO | viz poznámka pod tabulkou |
V enterprise sféře je pravděpodobně nejpoužívanějším protokolem pro message brokery protokol AMQP (Advanced Message Queuing Protocol), s nímž jsme se již částečně setkali při popisu systému RabbitMQ. Ovšem zatímco RabbitMQ podporuje starší verze 0.9.1, 0.9 a 0.8, je tomu v případě Apache MQ jinak, protože je podporován novější protokol verze 1.0 (ten se od předchozích variant liší svou sémantikou i vlastní binárním formátem). Jedná se o binární protokol, v němž je velká váha kladena nejen na precizní specifikaci formátu dat, ale i na popis sémantiky operací prováděných službami, které AMQP implementují (či možná lépe řečeno akceptují).
Dalším důležitým protokolem, který lze použít pro komunikaci s Apache MQ, je protokol nazvaný STOMP neboli Streaming Text Oriented Messaging Protocol. Jedná se o relativně jednoduchý protokol založený – jak jeho název napovídá – na příkazech posílaných v textovém formátu se syntaxí, která se podobá protokolu HTTP. Předností STOMPu je snadná implementace klientů a v případě potřeby (ladění, simulace útoků atd.) je dokonce možné namísto dedikovaného klienta použít běžný nástroj telnet, což si ostatně ukážeme ve čtrnácté kapitole. Ve výchozím nastavení existuje omezení maximální délky zprávy na 10 MB, ovšem tuto hodnotu je možné v případě potřeby změnit.
Třetím užitečným protokolem, o němž se ve stručnosti zmíníme a který je systémem Apache ActiveMQ podporován, je protokol nazvaný MQTT, který je mj. určený pro dnes populární IoT, tj. obecně pro zařízení s relativně malým výkonem popř. omezenými systémovými zdroji (a většinou i omezenou odolností proti útokům :).
3. Instalace Apache ActiveMQ
Systém Apache ActiveMQ je z větší části naprogramován v Javě (kromě knihovny wrapper a dalších maličkostí) a vyžaduje, aby na systému byla nainstalována JRE (Java Runtime Environment) Javy 8, což by na většině současných systémů nemělo být problematické zajistit (navíc je možné v případě potřeby provést překlad i pro JRE Javy 7). Instalace je ve skutečnosti velmi snadná a spočívá se stažení a rozbalení jednoho tarballu. Poslední stabilní verzí Apache ActiveMQ je verze 5.18 a stáhneme ji buď běžným webovým prohlížečem nebo přímo z příkazové řádky tímto příkazem:
$ wget -O apache-activemq-5.15.8-bin.tar.gz "http://www.apache.org/dyn/closer.cgi?filename=/activemq/5.15.8/apache-activemq-5.15.8-bin.tar.gz&action=download"
Dále musíme získaný tarball, jehož velikost přesahuje 50 MB, rozbalit příkazem:
$ tar xvfz apache-activemq-5.15.8-bin.tar.gz ... ... ...
Nyní si otestujeme, zda je možné spustit základní nástroj activemq, který je umístěný v podadresáři bin:
$ cd apache-activemq-5.15.8/bin/
Zkusíme si zobrazit nápovědu se základními podporovanými příkazy:
$ ./activemq help Usage: Main [--extdir <dir>] [task] [task-options] [task data] Tasks: browse - Display selected messages in a specified destination. bstat - Performs a predefined query that displays useful statistics regarding the specified broker consumer - Receives messages from the broker create - Creates a runnable broker instance in the specified path. decrypt - Decrypts given text dstat - Performs a predefined query that displays useful tabular statistics regarding the specified destination type encrypt - Encrypts given text export - Exports a stopped brokers data files to an archive file list - Lists all available brokers in the specified JMX context producer - Sends messages to the broker purge - Delete selected destination's messages that matches the message selector query - Display selected broker component's attributes and statistics. start - Creates and starts a broker using a configuration file, or a broker URI. stop - Stops a running broker specified by the broker name. Task Options (Options specific to each task): --extdir <dir> - Add the jar files in the directory to the classpath. --version - Display the version information. -h,-?,--help - Display this help information. To display task specific help, use Main [task] -h,-?,--help Task Data: - Information needed by each specific task. JMX system property options: -Dactivemq.jmx.url=<jmx service uri> (default is: 'service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi') -Dactivemq.jmx.user=<user name> -Dactivemq.jmx.password=<password>
4. Základní příkazy podporované nástrojem activemq
Ukažme si ve stručnosti ty nejzákladnější příkazy, které jsou nástrojem activemq podporovány.
Spuštění služby ActiveMQ na pozadí:
$ ./activemq start INFO: Loading '/home/tester/apache-activemq-5.15.8//bin/env' INFO: Using java '/usr/bin/java' INFO: Starting - inspect logfiles specified in logging.properties and log4j.properties to get details INFO: pidfile created : '/home/tester/apache-activemq-5.15.8//data/activemq.pid' (pid '9114')
Spuštění služby ActiveMQ na popředí (všechny zprávy se budou vypisovat na terminál):
$ ./activemq console ... ... ...
Ukončení běžící služby ActiveMQ:
$ ./activemq stop Connecting to pid: 20378 Stopping broker: localhost . TERMINATED
Výpis dostupných brokerů:
$ ./activemq list Connecting to pid: 19789 brokerName = localhost
Dtto, ovšem ve chvíli, kdy je služba pozastavena:
$ ./activemq list INFO: Broker not available at: service:jmx:rmi:///jndi/rmi://localhost:1099/jmxrmi
5. Použití nástroje activemq pro poslání popř. pro přijetí zprávy
Nástroj activemq může být dokonce použit i pro poslání popř. pro přijetí zprávy. Ve skutečnosti se zdaleka nejedná o ten nejrychlejší způsob, jak s ActiveMQ pracovat, ovšem je zdaleka nejjednodušší. V příkladech se použije výchozí fronta nazvaná „queue://TEST“.
Poslání stovky shodných zpráv „Hello world“:
$ ./activemq producer --message "Hello world"
Poslání jediné zprávy „Hello world“:
$ ./activemq producer --message "Hello world" --messageCount 1
Poslání zprávy, jejímž tělem jsou data získaná z určité URL. Následující příklad je jen umělý, ve skutečnosti se spíše bude volat nějaké REST API pro získání dat:
$ ./activemq producer --payloadUrl https://www.root.cz --messageCount 1
A nakonec spustíme konzumenta zpráv, při jehož spuštění je možné určit, zda se má zpracování provést v transakci či nikoli:
$ ./activemq consumer --transacted true ... ... ... INFO | consumer-1 Received Hello INFO | consumer-1 Committing transaction: 99 INFO | consumer-1 Consumed: 1000 messages INFO | consumer-1 Consumer thread finished
6. Komunikační protokol STOMP a knihovna stomp.py
V dnešních demonstračních příkladech použijeme pro komunikaci klientů se systémem Apache ActiveMQ protokol STOMP, o němž jsme se ve stručnosti zmínili v úvodních kapitolách. Příklady budou – podobně jako v předchozích částech tohoto seriálu – naprogramovány v jazyku Python, takže nejdříve nainstalujeme knihovnu nazvanou stomp.py zajišťující rozhraní k jakémukoli message brokerovi, který tento protokol využívá, samozřejmě včetně Apache ActiveMQ. Tato knihovna existuje jak pro Python 2.x, tak i pro Python 3.x a podporuje všechny v současnosti dostupné verze protokolu STOMP: 1.0, 1.0 i 1.2.
Instalace této knihovny je snadná, protože ji nalezneme v PyPi. Pro jednoduchost bude instalace provedena pro právě přihlášeného uživatele:
$ pip3 install --user stomp-py Collecting stomp-py Downloading https://files.pythonhosted.org/packages/80/c8/d13f0058ede2d83e54028cbad98a5886aaf2501017ddf4231ec1deff81b3/stomp.py-4.1.15-py2.py3-none-any.whl Installing collected packages: stomp-py Successfully installed stomp-py
Základní test, zda se instalace podařila, lze provést přímo z interpretru Pythonu:
$ python3 Python 3.6.3 (default, Oct 9 2017, 12:11:29) [GCC 7.2.1 20170915 (Red Hat 7.2.1-2)] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import stomp >>> help("stomp") Help on package stomp: NAME stomp DESCRIPTION stomp.py provides connectivity to a message broker supporting the STOMP protocol. Protocol versions 1.0, 1.1 and 1.2 are supported. See the GITHUB project page for more information. Author: Jason R Briggs License: http://www.apache.org/licenses/LICENSE-2.0 ... ... ...
Kromě vlastní knihovny stomp-py se nainstaluje i jednoduchý klient ovládaný z příkazového řádku. Tento klient se jmenuje jednoduše stomp a můžeme si vyzkoušet jeho základní funkce:
$ stomp --version Stomp.py Version 4.1.21
Zkusíme se připojit k lokálně běžící instanci Apache ActiveMQ (viz předchozí kapitolu):
$ stomp CONNECTED server: ActiveMQ/5.15.8 heart-beat: 0,0 session: ID:localhost.localdomain-38215-1549567803551-3:3 version: 1.1 > >
Výpis základních příkazů:
help Documented commands (type help <topic>): ======================================== EOF begin help rollback sendfile stats ver abort commit nack run sendrec subscribe version ack exit quit send sendreply unsubscribe
Poslání zprávy do fronty nazvané „test“:
send /queue/test hello world MESSAGE content-length: 11 expires: 0 destination: /queue/test
Přihlášení se k odběru zpráv z fronty „test“:
subscribe /queue/test Subscribing to "/queue/test" with acknowledge set to "auto", id set to "1" subscription: 1 priority: 4 message-id: ID:localhost.localdomain-38215-1549567803551-3:3:-1:1:1 timestamp: 1549631641256 hello world
7. Jednoduchý producent zpráv naprogramovaný v Pythonu
Zkusme si nyní naprogramovat jednoduchého producenta zpráv, které budou do message brokera poslány s využitím komunikační strategie PUB-SUB. To znamená, že pokud bude existovat nějaký klient naslouchající těmto zprávám, budou mu poslány. V případě, že bude naslouchat více klientů, budou zprávy rozeslány všem těmto klientům a pokud nebude připojen ani jeden klient, bude zpráva zahozena.
Nejprve musíme zajistit připojení k Apache ActiveMQ běžící na stejném počítači. Pro protokol STOMP by měl být otevřený výchozí port 61613:
conn = stomp.Connection(host_and_ports=[("localhost", 61613)]) conn.start()
Výchozí přihlašovací jméno a heslo je „admin“/„admin“ (i když v dokumentaci je psáno „password“):
conn.connect(login="admin", passcode="admin")
Zprávy se posílají metodou Connection.send, které se předává cíl (zde „topic/event“ popř. „topic/event2“), což je jméno tématu s povinným prefixem. Dále se této metodě předá text zprávy a nepovinným parametrem persistent můžeme určit, zda se má zpráva uložit do nastavené databáze či nikoli (tedy zda přežije restart Apache ActiveMQ):
conn.send(destination1, message, persistent='true')
Úplný zdrojový kód zdroje zpráv bude vypadat následovně:
#!/usr/bin/env python import time import stomp destination1 = "/topic/event" destination2 = "/topic/event2" MESSAGES = 10 conn = stomp.Connection(host_and_ports=[("localhost", 61613)]) conn.start() conn.connect(login="admin", passcode="admin") for i in range(0, MESSAGES): message = "Hello world #{i}!".format(i=i) conn.send(destination1, message, persistent='true') conn.send(destination2, message, persistent='true') conn.disconnect()
8. Konzument zpráv naprogramovaný taktéž v Pythonu
Konzument (příjemce) zpráv je komplikovanější, než jejich producent. Je to pochopitelné, protože zatímco publikování zprávy spočívá v prostém zavolání metody Connection.send() je příjem zpráv (a čekání na ně) spojen s nějakou formou čekací smyčky, ať již aktivní či pasivní. V knihovně stomp.py můžeme zaregistrovat objekt, jehož metody se budou volat buď při příjmu zprávy nebo v případě, že nastane nějaká chyba. Tyto callback metody (příjem zprávy, informace o chybě) budou zavolány a budou jim předány hlavičky zprávy/chyby a vlastní text zprávy:
def on_message(self, headers, message): print("Received message: {m}".format(m=message)) def on_error(self, headers, message): print("Received an error {e}".format(e=message))
Registrace třídy s těmito metodami vypadá takto:
conn = stomp.Connection(host_and_ports=[("localhost", 61613)]) conn.set_listener('', SimpleListener(conn))
Dále je nutné se přihlásit k odběru zpráv s automatickým potvrzením jejich zpracování:
conn.connect(login="admin", passcode="admin") conn.subscribe(id='simple_listener', destination=destination, ack='auto')
def subscribe(self, destination, id, ack='auto', headers=None, **keyword_headers): def subscribe(self, destination, id=None, ack='auto', headers=None, **keyword_headers):
Úplný zdrojový kód konzumenta zpráv naleznete na adrese https://github.com/tisnik/message-queues-examples/blob/master/amq/example01_publisher_listener/subscriber.py:
#!/usr/bin/env python import time import stomp class SimpleListener: def __init__(self, conn): self.conn = conn def on_message(self, headers, message): print("Received message: {m}".format(m=message)) def on_error(self, headers, message): print("Received an error {e}".format(e=message)) destination = "/topic/event" conn = stomp.Connection(host_and_ports=[("localhost", 61613)]) conn.set_listener('', SimpleListener(conn)) conn.start() conn.connect(login="admin", passcode="admin") conn.subscribe(id='simple_listener', destination=destination, ack='auto') print("Waiting for messages...") while True: time.sleep(10)
9. Využití komunikační strategie PUSH-PULL s frontami zpráv
Nepatrnou úpravou předchozích dvou skriptů lze zajistit použití komunikační strategie PUSH-PULL, při níž jsou zprávy poslány do fronty a následně (kdykoli později) odeslány klientovi, který se připojí (ovšem jen jedinému klientovi, což je výchozí konfigurace). Úprava spočívá v nahrazení cíle zpráv, kdy se namísto „/topic/event“ použije „/queue/jméno_fronty“.
Následuje ukázka implementace zdroje zpráv posílaných do fronty:
#!/usr/bin/env python import time import stomp destination1 = "/queue/test" destination2 = "/queue/test2" MESSAGES = 10 conn = stomp.Connection(host_and_ports=[("localhost", 61613)]) conn.start() conn.connect(login="admin", passcode="admin") for i in range(0, MESSAGES): message = "Hello world #{i}!".format(i=i) conn.send(destination1, message, persistent='true') conn.send(destination2, message, persistent='true') conn.disconnect()
Skript, který bude zprávy z fronty číst, bude vypadat takto:
#!/usr/bin/env python import time import stomp class SimpleListener: def __init__(self, conn): self.conn = conn def on_message(self, headers, message): print("Received message: {m}".format(m=message)) def on_error(self, headers, message): print("Received an error {e}".format(e=message)) destination = "/queue/test" conn = stomp.Connection(host_and_ports=[("localhost", 61613)]) conn.set_listener('', SimpleListener(conn)) conn.start() conn.connect(login="admin", passcode="admin") conn.subscribe(id='simple_listener', destination=destination, ack='auto') print("Waiting for messages...") while True: time.sleep(10)
10. Sledování stavu Apache ActiveMQ z konzole
V demonstračních příkladech jsme si ukázali zcela základní způsob použití Apache ActiveMQ s využitím protokolu STOMP. V dalších kapitolách se budeme zabývat způsobem sledování (a samozřejmě i ovlivňování) stavu Apache ActiveMQ, k čemuž máme k dispozici hned několik nástrojů.
Základní nástroj pro sledování již známe – je jím příkaz activemq, který nalezneme v adresáři apache-activemq-5.15.8/bin.
Informace o brokerovi zpráv, jednotlivých otevřených „konektorech“ (porty s protokoly) včetně stavu jednotlivých front, získáme příkazem:
$ ./activemq bstat ACTIVEMQ_HOME: /home/tester/apache-activemq-5.15.8 ACTIVEMQ_BASE: /home/tester/apache-activemq-5.15.8 ACTIVEMQ_CONF: /home/tester/apache-activemq-5.15.8/conf ACTIVEMQ_DATA: /home/tester/apache-activemq-5.15.8/data useJmxServiceUrl Found JMS Url: service:jmx:rmi://127.0.0.1/stub/rO0ABXN9AAAAAQAlamF2YXgubWFuYWdlbWVudC5yZW1vdGUucm1pLlJNSVNlcnZlcnhyABdqYXZhLmxhbmcucmVmbGVjdC5Qcm94eeEn2iDMEEPLAgABTAABaHQAJUxqYXZhL2xhbmcvcmVmbGVjdC9JbnZvY2F0aW9uSGFuZGxlcjt4cHNyAC1qYXZhLnJtaS5zZXJ2ZXIuUmVtb3RlT2JqZWN0SW52b2NhdGlvbkhhbmRsZXIAAAAAAAAAAgIAAHhyABxqYXZhLnJtaS5zZXJ2ZXIuUmVtb3RlT2JqZWN002G0kQxhMx4DAAB4cHc0AAtVbmljYXN0UmVmMgAACTEyNy4wLjAuMQAAiFeZdArPzVDT1a21HUEAAAFoyGEyGYABAHg= Connecting to pid: 9667 BrokerName = localhost TotalEnqueueCount = 1350 TotalDequeueCount = 1090 TotalMessageCount = 21 TotalConsumerCount = 0 Uptime = 3 hours 9 minutes Name = test2 destinationName = test2 destinationType = Queue EnqueueCount = 20 DequeueCount = 0 ConsumerCount = 0 DispatchCount = 0 connectorName = openwire connectorName = stomp Name = test destinationName = test destinationType = Queue EnqueueCount = 21 DequeueCount = 20 ConsumerCount = 0 DispatchCount = 22 Name = event2 destinationName = event2 destinationType = Topic EnqueueCount = 80 DequeueCount = 20 ConsumerCount = 0 DispatchCount = 20 destinationName = ActiveMQ.Advisory.TempQueue_ActiveMQ.Advisory.TempTopic destinationType = Topic connectorName = ws Name = TEST destinationName = TEST destinationType = Queue EnqueueCount = 1010 DequeueCount = 1010 ConsumerCount = 0 DispatchCount = 1010 Name = KahaDBPersistenceAdapter[/home/tester/apache-activemq-5.15.8/data/kahadb,Index:/home/tester/apache-activemq-5.15.8/data/kahadb] connectorName = amqp Name = event destinationName = event destinationType = Topic EnqueueCount = 94 DequeueCount = 40 ConsumerCount = 0 DispatchCount = 40 connectorName = mqtt
Podobně znějící příkaz dstat nám podá přehlednější informace o frontách, jejich velikosti, počtu připojených producentů a konzumentů zpráv, počtu zpráv ve frontách a taktéž informace o paměťových požadavcích jednotlivých front:
$ ./activemq dstat ACTIVEMQ_HOME: /home/tester/apache-activemq-5.15.8 ACTIVEMQ_BASE: /home/tester/apache-activemq-5.15.8 ACTIVEMQ_CONF: /home/tester/apache-activemq-5.15.8/conf ACTIVEMQ_DATA: /home/tester/apache-activemq-5.15.8/data useJmxServiceUrl Found JMS Url: service:jmx:rmi://127.0.0.1/stub/rO0ABXN9AAAAAQAlamF2YXgubWFuYWdlbWVudC5yZW1vdGUucm1pLlJNSVNlcnZlcnhyABdqYXZhLmxhbmcucmVmbGVjdC5Qcm94eeEn2iDMEEPLAgABTAABaHQAJUxqYXZhL2xhbmcvcmVmbGVjdC9JbnZvY2F0aW9uSGFuZGxlcjt4cHNyAC1qYXZhLnJtaS5zZXJ2ZXIuUmVtb3RlT2JqZWN0SW52b2NhdGlvbkhhbmRsZXIAAAAAAAAAAgIAAHhyABxqYXZhLnJtaS5zZXJ2ZXIuUmVtb3RlT2JqZWN002G0kQxhMx4DAAB4cHc0AAtVbmljYXN0UmVmMgAACTEyNy4wLjAuMQAAiFeZdArPzVDT1a21HUEAAAFoyGEyGYABAHg= Connecting to pid: 9667 Name Queue Size Producer # Consumer # Enqueue # Dequeue # Forward # Memory % ActiveMQ.Advisory.Connection 0 0 0 85 0 0 0 ActiveMQ.Advisory.Consumer.Queue.TEST 0 0 0 4 0 0 0 ActiveMQ.Advisory.Consumer.Queue.test 0 0 0 10 0 0 0 ActiveMQ.Advisory.Consumer.Topic.event 0 0 0 10 0 0 0 ActiveMQ.Advisory.Consumer.Topic.event2 0 0 0 6 0 0 0 ActiveMQ.Advisory.MasterBroker 0 0 0 1 0 0 0 ActiveMQ.Advisory.Producer.Queue.TEST 0 0 0 4 0 0 0 ActiveMQ.Advisory.Queue 0 0 0 3 0 0 0 ActiveMQ.Advisory.Topic 0 0 0 2 0 0 0 TEST 0 0 0 1010 1010 0 0 event 0 0 0 94 40 0 0 event2 0 0 0 80 20 0 0 test 1 0 0 21 20 0 0 test2 20 0 0 20 0 0 0
11. Webové rozhraní Apache ActiveMQ
Ve výchozím nastavení je na adrese http://localhost:8161/admin spuštěno webové rozhraní, do něhož se přihlásíte zadáním jména „admin“ a hesla „admin“:
Obrázek 1: Úvodní stránka webového rozhraní.
Obrázek 2: Základní informace o systému po přihlášení.
Obrázek 3: Informace o frontách.
Obrázek 4: Konzumenti odebírající zprávy z vybrané fronty „TEST“.
Obrázek 5: Přesný text zprávy, která je uložena ve frontě.
Obrázek 6: Přes webové rozhraní je možné zprávu i odeslat.
12. Přístup k nastavení a stavu Apache ActiveMQ s využitím nástroje JConsole
Systém Apache ActiveMQ naprostou většinu parametrů poskytuje ke čtení (a některé i k modifikaci) přes technologii Java Management Extensions (JMX). Díky tomu je možné ActiveMQ sledovat a konfigurovat z jakékoli aplikace, která dokáže komunikovat přes JMX. Základní aplikací, která je k dispozici v každé instalaci JDK (nikoli však pouze JRE!) je standardní nástroj nazvaný JConsole, který se spouští příkazem jconsole. Podívejme se nyní alespoň ve stručnosti na to, jak lze JConsoli použít společně s ActiveMQ.
Obrázek 7: Po spuštění příkazu jconsole je nutné vybrat proces activemq.jar a popř. potvrdit, že chceme použít nezabezpečené připojení.
Obrázek 8: Na listu nazvaném MBeans vyberte uzel org.apache.activemq a uvidíte všechny atributy poskytované běžícím systémem.
Obrázek 9: Na tomto screenshotu je ukázáno, že po vybrání fronty nazvané „TEST“ je možné volat některé metody ovlivňující její konfiguraci. Další dvě fronty „test“ a „test2“ byly vytvořeny automaticky našimi demonstračními příklady zmíněnými v předchozích kapitolách.
Obrázek 10: Vpravo nahoře jsou vypsány všechny dostupné fronty, přesněji řečeno datové typy, kterými jsou reprezentovány.
13. Ukázka komunikace s Apache ActiveMQ s využitím telnetu přes protokol STOMP
Díky tomu, že protokol STOMP je navržen takovým způsobem, aby bylo velmi snadné implementovat nové klienty, a současně se jedná o čistě textový protokol, nebude asi velkým překvapením, že je možné s Apache ActiveMQ komunikovat i s využitím klasického protokolu telnet a stejně pojmenovaného klienta.
Nejprve se připojíme přímo na lokální port číslo 61613, na němž Apache ActiveMQ očekává příkazy předávané přes protokol STOMP:
$ telnet localhost 61613 Trying ::1... Connected to localhost. Escape character is '^]'.
Samotné příkazy vypadají podobně jako hlavičky protokolu HTTP:
- Na prvním řádku je uvedeno jméno příkazu
- Následují případné parametry umístěné na dalších řádcích
- Celá hlavička příkazu je ukončena prázdným řádkem, za ní může následovat například text zprávy
- Potvrzení příkazu se děje znakem Ctrl+@ (ASCII NUL), který se zapisuje přes Ctrl+Space (nebo zápisem čtyř nul na numerickém bloku s podržením AltGr)
Pokud není tento protokol dodržen, bude spojení ukončeno, což je pravděpodobně nejrozumnější cesta, jak se vypořádat se špatně naimplementovanými klienty :-)
14. Připojení a poslání zprávy do fronty
Pro navázání připojení použijeme příkaz CONNECT, na dalších řádcích se pak uvede jméno a heslo, prázdný řádek a konečně již zmíněný znak Ctrl+@:
CONNECT login: admin password: admin ^@ CONNECTED server:ActiveMQ/5.15.8 heart-beat:0,0 session:ID:localhost.localdomain-43853-1549550040544-3:40 version:1.0
Dokonce je možné přímo z telnetu poslat i zprávu, a to konkrétně příkazem SEND, jehož parametry jsou cíl zprávy (topic nebo fronta), případné upřesnění příjemců a za prázdným řádkem text zprávy ukončený opět znakem Ctrl+@:
SEND destination:/queue/test receipt: Hello from Telnet! ^@ RECEIPT receipt-id:
Přihlášení k příjmu zpráv z fronty test:
SUBSCRIBE id:0 destination:test ask:client ^@
Přijatá zpráva se zobrazí takto:
MESSAGE content-length:15 expires:0 destination:/queue/test subscription:0 priority:4 message-id:ID:localhost.localdomain-36883-1549643957783-3:15:-1:1:19 persistent:true timestamp:1549653866950 Hello world #9!
Odpojení od Apache ActiveMQ:
DISCONNECT ^@ Connection closed by foreign host.
15. Další příkazy podporované protokolem STOMP
V této tabulce jsou uvedeny všechny příkazy podporované protokolem STOMP verze 1.2:
Server naopak může posílat tyto rámce (frame):
Příkaz | Stručný popis |
---|---|
SEND | poslání zprávy |
SUBSCRIBE | přihlášení k odběru zpráv |
UNSUBSCRIBE | odhlášení od odběru zpráv |
ACK | potvrzení zprávy |
NACK | negativní potvrzení (vysvětlíme si příště) |
BEGIN | začátek transakce (vysvětlíme si příště) |
COMMIT | commit v transakci (provedení všech operací) |
ABORT | rollback transakce |
DISCONNECT | odpojení klienta |
Příkaz | Stručný popis |
---|---|
MESSAGE | zpráva poslaná serverem |
RECEIPT | potvrzení o zpracování nějakého příkazu serverem |
ERROR | informace o chybě potvrzené serverem |
16. Od Apache ActiveMQ k Red Hat AMQ
Kromě Apache ActiveMQ se na samotný závěr jen krátce zmíníme o existenci nástroje nazvaného Red Hat AMQ, který možnosti message brokera dále rozšiřuje. Red Hat AMQ se skládá z několika komponent, přičemž ústředním prvkem je samotný message broker odvozený od AMQ Artemis, ovšem kromě toho nabízí i tzv. Interconnect (viz další kapitolu), možnosti clusteringu, HA, persistenci zpráv, žurnálování, decentralizovaná a redundantní úložiště zpráv atd. Celý systém je možné konfigurovat centrálně, a to buď přes JMX (což jsme si již ukázali výše s nástrojem jconsole) nebo klasicky přes REST API.
Podporovány jsou tyto komunikační strategie:
- PUSH-PULL: producer-broker-konzument(i) s jedinou společnou frontou
- PUSH-PULL: producer-broker-konzument(i) s více frontami pro skupiny konzumentů
- dtto, ovšem pro strategii PUB-SUB
- kombinace předchozích možností (typicky PUSH-PULL s „odbočkou“ typu SUB)
17. Součásti (komponenty) systému Red Hat AMQ
Systém Red Hat AMQ se skládá z těchto základních komponent, které je možné vzájemně skládat a vytvářet tak systémy s různě komplikovanou architekturou:
- AMQ Broker – vlastní message broker, který podporuje větší množství protokolů (viz tabulku níže), persistenci zpráv, samozřejmě podporu front, ale i load balancing, clustering atd. Broker je postavený na projektu ActiveMQ Artemis.
- AMQ Interconnect – konfigurovatelná distribuce zpráv, zajišťuje směrování (routing) mezi koncovými uzly (klient, message broker, další služby). Podporuje i tvorbu redundantních cest při směrování, takže je například možné zaručit funkčnost systému i při výpadku některých síťových prvků.
- AMQ Console – tato konzole sloužící pro administraci brokerů, směrování zpráv a front, je odlišná od webové konzole, s níž jsme se setkali v předchozích kapitolách.
- AMQ Clients – jednotliví (většinou multiplatformní) klienti, kteří jsou taktéž vypsáni v následující tabulce. Rozhraní existují pro Javu (JMS), C++, JavaScript, Python, Ruby, .NET atd.
V následující tabulce jsou vypsány podporované protokoly jednotlivých součástí Red Hat AMQ (druhá část tabulky obsahuje jednotlivé varianty klientů):
Komponenta | Jazyk | Platforma | Protokol(y) |
---|---|---|---|
AMQ Broker | × | JVM | AMQP 1.0, MQTT, OpenWire, STOMP, Artemis Core Protocol, HornetQ Core Protocol |
AMQ Interconnect | × | Linux | AMQP 1.0 |
AMQ C++ | C++ | Linux, Windows | AMQP 1.0 |
AMQ JavaScript | JavaScript | Node.js, browsery | AMQP 1.0 |
AMQ JMS | Java | JVM | AMQP 1.0 |
AMQ .NET | C# | .NET | AMQP 1.0 |
AMQ Python | Python | Linux | AMQP 1.0 |
AMQ Ruby | Ruby | Linux | AMQP 1.0 |
AMQ Core Protocol JMS | Java | JVM | Core Protocol |
AMQ OpenWire JMS | Java | JVM | OpenWire |
18. Repositář s demonstračními příklady
Zdrojové kódy všech dnes popsaných demonstračních příkladů naprogramovaných v Pythonu byly uloženy do Git repositáře, který je dostupný na adrese https://github.com/tisnik/message-queues-examples (stále na GitHubu :-). V případě, že nebudete chtít klonovat celý repositář (ten je ovšem – alespoň prozatím – velmi malý, dnes má doslova několik kilobajtů), můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující tabulce.
Příklad | Skript/kód | Popis | Cesta |
---|---|---|---|
1 | publisher.py | zdroj zpráv posílaných se strategií PUB-SUB | https://github.com/tisnik/message-queues-examples/blob/master/amq/example01_publisher_listener/publisher.py |
1 | subscriber.py | příjemce zpráv posílaných se strategií PUB-SUB | https://github.com/tisnik/message-queues-examples/blob/master/amq/example01_publisher_listener/subscriber.py |
2 | publisher.py | zdroj zpráv posílaných se strategií PUSH-PULL | https://github.com/tisnik/message-queues-examples/blob/master/amq/example02_publisher_listener_queue/publisher.py |
2 | subscriber.py | příjemce zpráv posílaných se strategií PUSH-PULL | https://github.com/tisnik/message-queues-examples/blob/master/amq/example02_publisher_listener_queue/subscriber.py |
19. Odkazy na předchozí části seriálu
V této kapitole jsou uvedeny odkazy na všech devět předchozích částí seriálu, v němž se zabýváme různými způsoby implementace front zpráv a k nim přidružených technologií:
- Použití nástroje RQ (Redis Queue) pro správu úloh zpracovávaných na pozadí
https://www.root.cz/clanky/pouziti-nastroje-rq-redis-queue-pro-spravu-uloh-zpracovavanych-na-pozadi/ - Celery: systém implementující asynchronní fronty úloh pro Python
https://www.root.cz/clanky/celery-system-implementujici-asynchronni-fronty-uloh-pro-python/ - Celery: systém implementující asynchronní fronty úloh pro Python (dokončení)
https://www.root.cz/clanky/celery-system-implementujici-asynchronni-fronty-uloh-pro-python-dokonceni/ - RabbitMQ: jedna z nejúspěšnějších implementací brokera
https://www.root.cz/clanky/rabbitmq-jedna-z-nejuspesnejsich-implementaci-brokera/ - Pokročilejší operace nabízené systémem RabbitMQ
https://www.root.cz/clanky/pokrocilejsi-operace-nabizene-systemem-rabbitmq/ - ØMQ: knihovna pro asynchronní předávání zpráv
https://www.root.cz/clanky/0mq-knihovna-pro-asynchronni-predavani-zprav/ - Další možnosti poskytované knihovnou ØMQ
https://www.root.cz/clanky/dalsi-moznosti-poskytovane-knihovnou-mq/ - Další možnosti nabízené knihovnou ØMQ, implementace protokolů ØMQ v čisté Javě
https://www.root.cz/clanky/dalsi-moznosti-nabizene-knihovnou-mq-implementace-protokolu-mq-v-ciste-jave/
20. Odkazy na Internetu
- Apache ActiveMQ
http://activemq.apache.org/ - Apache ActiveMQ Artemis
https://activemq.apache.org/artemis/ - Apache ActiveMQ Artemis User Manual
https://activemq.apache.org/artemis/docs/latest/index.html - Command Line Tools (Apache ActiveMQ)
https://activemq.apache.org/activemq-command-line-tools-reference.html - stomp.py 4.1.21 na PyPi
https://pypi.org/project/stomp.py/ - Stomp Tutorial
https://access.redhat.com/documentation/en-US/Fuse_Message_Broker/5.5/html/Connectivity_Guide/files/FMBConnectivityStompTelnet.html - Apache Camel
https://camel.apache.org/ - Red Hat Fuse
https://developers.redhat.com/products/fuse/overview/ - Confusion between ActiveMQ and ActiveMQ-Artemis?
https://serverfault.com/questions/873533/confusion-between-activemq-and-activemq-artemis - Staré stránky projektu HornetQ
http://hornetq.jboss.org/ - Snapshot JeroMQ verze 0.4.4
https://oss.sonatype.org/content/repositories/snapshots/org/zeromq/jeromq/0.4.4-SNAPSHOT/ - Difference between ActiveMQ vs Apache ActiveMQ Artemis
http://activemq.2283324.n4.nabble.com/Difference-between-ActiveMQ-vs-Apache-ActiveMQ-Artemis-td4703828.html - Microservices communications. Why you should switch to message queues
https://dev.to/matteojoliveau/microservices-communications-why-you-should-switch-to-message-queues–48ia - Stomp.py 4.1.19 documentation
https://stomppy.readthedocs.io/en/stable/ - Repositář knihovny JeroMQ
https://github.com/zeromq/jeromq/ - ØMQ – Distributed Messaging
http://zeromq.org/ - ØMQ Community
http://zeromq.org/community - Get The Software
http://zeromq.org/intro:get-the-software - PyZMQ Documentation
https://pyzmq.readthedocs.io/en/latest/ - Module: zmq.decorators
https://pyzmq.readthedocs.io/en/latest/api/zmq.decorators.html - ZeroMQ is the answer, by Ian Barber
https://vimeo.com/20605470 - ZeroMQ RFC
https://rfc.zeromq.org/ - ZeroMQ and Clojure, a brief introduction
https://antoniogarrote.wordpress.com/2010/09/08/zeromq-and-clojure-a-brief-introduction/ - zeromq/czmq
https://github.com/zeromq/czmq - golang wrapper for CZMQ
https://github.com/zeromq/goczmq - ZeroMQ version reporting in Python
http://zguide.zeromq.org/py:version - A Go interface to ZeroMQ version 4
https://github.com/pebbe/zmq4 - Broker vs. Brokerless
http://zeromq.org/whitepapers:brokerless - Learning ØMQ with pyzmq
https://learning-0mq-with-pyzmq.readthedocs.io/en/latest/ - Céčková funkce zmq_ctx_new
http://api.zeromq.org/4–2:zmq-ctx-new - Céčková funkce zmq_ctx_destroy
http://api.zeromq.org/4–2:zmq-ctx-destroy - Céčková funkce zmq_bind
http://api.zeromq.org/4–2:zmq-bind - Céčková funkce zmq_unbind
http://api.zeromq.org/4–2:zmq-unbind - Céčková C funkce zmq_connect
http://api.zeromq.org/4–2:zmq-connect - Céčková C funkce zmq_disconnect
http://api.zeromq.org/4–2:zmq-disconnect - Céčková C funkce zmq_send
http://api.zeromq.org/4–2:zmq-send - Céčková C funkce zmq_recv
http://api.zeromq.org/4–2:zmq-recv - Třída Context (Python)
https://pyzmq.readthedocs.io/en/latest/api/zmq.html#context - Třída Socket (Python)
https://pyzmq.readthedocs.io/en/latest/api/zmq.html#socket - Python binding
http://zeromq.org/bindings:python - Why should I have written ZeroMQ in C, not C++ (part I)
http://250bpm.com/blog:4 - Why should I have written ZeroMQ in C, not C++ (part II)
http://250bpm.com/blog:8 - About Nanomsg
https://nanomsg.org/ - Advanced Message Queuing Protocol
https://www.amqp.org/ - Advanced Message Queuing Protocol na Wikipedii
https://en.wikipedia.org/wiki/Advanced_Message_Queuing_Protocol - Dokumentace k příkazu rabbitmqctl
https://www.rabbitmq.com/rabbitmqctl.8.html - RabbitMQ
https://www.rabbitmq.com/ - RabbitMQ Tutorials
https://www.rabbitmq.com/getstarted.html - RabbitMQ: Clients and Developer Tools
https://www.rabbitmq.com/devtools.html - RabbitMQ na Wikipedii
https://en.wikipedia.org/wiki/RabbitMQ - Streaming Text Oriented Messaging Protocol
https://en.wikipedia.org/wiki/Streaming_Text_Oriented_Messaging_Protocol - Message Queuing Telemetry Transport
https://en.wikipedia.org/wiki/MQTT - Erlang
http://www.erlang.org/ - pika 0.12.0 na PyPi
https://pypi.org/project/pika/ - Introduction to Pika
https://pika.readthedocs.io/en/stable/ - Langohr: An idiomatic Clojure client for RabbitMQ that embraces the AMQP 0.9.1 model
http://clojurerabbitmq.info/ - AMQP 0–9–1 Model Explained
http://www.rabbitmq.com/tutorials/amqp-concepts.html - Part 1: RabbitMQ for beginners – What is RabbitMQ?
https://www.cloudamqp.com/blog/2015–05–18-part1-rabbitmq-for-beginners-what-is-rabbitmq.html - Downloading and Installing RabbitMQ
https://www.rabbitmq.com/download.html - celery na PyPi
https://pypi.org/project/celery/ - Databáze Redis (nejenom) pro vývojáře používající Python
https://www.root.cz/clanky/databaze-redis-nejenom-pro-vyvojare-pouzivajici-python/ - Databáze Redis (nejenom) pro vývojáře používající Python (dokončení)
https://www.root.cz/clanky/databaze-redis-nejenom-pro-vyvojare-pouzivajici-python-dokonceni/ - Redis Queue (RQ)
https://www.fullstackpython.com/redis-queue-rq.html - Python Celery & RabbitMQ Tutorial
https://tests4geeks.com/python-celery-rabbitmq-tutorial/ - Flower: Real-time Celery web-monitor
http://docs.celeryproject.org/en/latest/userguide/monitoring.html#flower-real-time-celery-web-monitor - Asynchronous Tasks With Django and Celery
https://realpython.com/asynchronous-tasks-with-django-and-celery/ - First Steps with Celery
http://docs.celeryproject.org/en/latest/getting-started/first-steps-with-celery.html - node-celery
https://github.com/mher/node-celery - Full Stack Python: web development
https://www.fullstackpython.com/web-development.html - Introducing RQ
https://nvie.com/posts/introducing-rq/ - Asynchronous Tasks with Flask and Redis Queue
https://testdriven.io/asynchronous-tasks-with-flask-and-redis-queue - rq-dashboard
https://github.com/eoranged/rq-dashboard - Stránky projektu Redis
https://redis.io/ - Introduction to Redis
https://redis.io/topics/introduction - Try Redis
http://try.redis.io/ - Redis tutorial, April 2010 (starší, ale pěkně udělaný)
https://static.simonwillison.net/static/2010/redis-tutorial/ - Python Redis
https://redislabs.com/lp/python-redis/ - Redis: key-value databáze v paměti i na disku
https://www.zdrojak.cz/clanky/redis-key-value-databaze-v-pameti-i-na-disku/ - Praktický úvod do Redis (1): vaše distribuovaná NoSQL cache
http://www.cloudsvet.cz/?p=253 - Praktický úvod do Redis (2): transakce
http://www.cloudsvet.cz/?p=256 - Praktický úvod do Redis (3): cluster
http://www.cloudsvet.cz/?p=258 - Connection pool
https://en.wikipedia.org/wiki/Connection_pool - Instant Redis Sentinel Setup
https://github.com/ServiceStack/redis-config - How to install REDIS in LInux
https://linuxtechlab.com/how-install-redis-server-linux/ - Redis RDB Dump File Format
https://github.com/sripathikrishnan/redis-rdb-tools/wiki/Redis-RDB-Dump-File-Format - Lempel–Ziv–Welch
https://en.wikipedia.org/wiki/Lempel%E2%80%93Ziv%E2%80%93Welch - Redis Persistence
https://redis.io/topics/persistence - Redis persistence demystified
http://oldblog.antirez.com/post/redis-persistence-demystified.html - Redis reliable queues with Lua scripting
http://oldblog.antirez.com/post/250 - Ost (knihovna)
https://github.com/soveran/ost - NoSQL
https://en.wikipedia.org/wiki/NoSQL - Shard (database architecture)
https://en.wikipedia.org/wiki/Shard_%28database_architecture%29 - What is sharding and why is it important?
https://stackoverflow.com/questions/992988/what-is-sharding-and-why-is-it-important - What Is Sharding?
https://btcmanager.com/what-sharding/ - Redis clients
https://redis.io/clients - Category:Lua-scriptable software
https://en.wikipedia.org/wiki/Category:Lua-scriptable_software - Seriál Programovací jazyk Lua
https://www.root.cz/serialy/programovaci-jazyk-lua/ - Redis memory usage
http://nosql.mypopescu.com/post/1010844204/redis-memory-usage - Ukázka konfigurace Redisu pro lokální testování
https://github.com/tisnik/presentations/blob/master/redis/redis.conf - Resque
https://github.com/resque/resque - Nested transaction
https://en.wikipedia.org/wiki/Nested_transaction - Publish–subscribe pattern
https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern - Messaging pattern
https://en.wikipedia.org/wiki/Messaging_pattern - Using pipelining to speedup Redis queries
https://redis.io/topics/pipelining - Pub/Sub
https://redis.io/topics/pubsub - ZeroMQ distributed messaging
http://zeromq.org/ - ZeroMQ: Modern & Fast Networking Stack
https://www.igvita.com/2010/09/03/zeromq-modern-fast-networking-stack/ - Publish/Subscribe paradigm: Why must message classes not know about their subscribers?
https://stackoverflow.com/questions/2908872/publish-subscribe-paradigm-why-must-message-classes-not-know-about-their-subscr - Python & Redis PUB/SUB
https://medium.com/@johngrant/python-redis-pub-sub-6e26b483b3f7 - Message broker
https://en.wikipedia.org/wiki/Message_broker - RESP Arrays
https://redis.io/topics/protocol#array-reply - Redis Protocol specification
https://redis.io/topics/protocol - Redis Pub/Sub: Intro Guide
https://www.redisgreen.net/blog/pubsub-intro/ - Redis Pub/Sub: Howto Guide
https://www.redisgreen.net/blog/pubsub-howto/ - Comparing Publish-Subscribe Messaging and Message Queuing
https://dzone.com/articles/comparing-publish-subscribe-messaging-and-message - Apache Kafka
https://kafka.apache.org/ - Iron
http://www.iron.io/mq - kue (založeno na Redisu, určeno pro node.js)
https://github.com/Automattic/kue - Cloud Pub/Sub
https://cloud.google.com/pubsub/ - Introduction to Redis Streams
https://redis.io/topics/streams-intro - glob (programming)
https://en.wikipedia.org/wiki/Glob_(programming) - Why and how Pricing Assistant migrated from Celery to RQ – Paris.py
https://www.slideshare.net/sylvinus/why-and-how-pricing-assistant-migrated-from-celery-to-rq-parispy-2 - Enqueueing internals
http://python-rq.org/contrib/ - queue — A synchronized queue class
https://docs.python.org/3/library/queue.html - Queues
http://queues.io/ - Windows Subsystem for Linux Documentation
https://docs.microsoft.com/en-us/windows/wsl/about - RestMQ
http://restmq.com/ - ActiveMQ
http://activemq.apache.org/ - Amazon MQ
https://aws.amazon.com/amazon-mq/ - Amazon Simple Queue Service
https://aws.amazon.com/sqs/ - Celery: Distributed Task Queue
http://www.celeryproject.org/ - Disque, an in-memory, distributed job queue
https://github.com/antirez/disque - rq-dashboard
https://github.com/eoranged/rq-dashboard - Projekt RQ na PyPi
https://pypi.org/project/rq/ - rq-dashboard 0.3.12
https://pypi.org/project/rq-dashboard/ - Job queue
https://en.wikipedia.org/wiki/Job_queue - Why we moved from Celery to RQ
https://frappe.io/blog/technology/why-we-moved-from-celery-to-rq - Running multiple workers using Celery
https://serverfault.com/questions/655387/running-multiple-workers-using-celery - celery — Distributed processing
http://docs.celeryproject.org/en/latest/reference/celery.html - Chains
https://celery.readthedocs.io/en/latest/userguide/canvas.html#chains - Routing
http://docs.celeryproject.org/en/latest/userguide/routing.html#automatic-routing - Celery Distributed Task Queue in Go
https://github.com/gocelery/gocelery/ - Python Decorators
https://wiki.python.org/moin/PythonDecorators - Periodic Tasks
http://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html - celery.schedules
http://docs.celeryproject.org/en/latest/reference/celery.schedules.html#celery.schedules.crontab - Pros and cons to use Celery vs. RQ
https://stackoverflow.com/questions/13440875/pros-and-cons-to-use-celery-vs-rq - Priority queue
https://en.wikipedia.org/wiki/Priority_queue - Jupyter
https://jupyter.org/ - How IPython and Jupyter Notebook work
https://jupyter.readthedocs.io/en/latest/architecture/how_jupyter_ipython_work.html - Context Managers
http://book.pythontips.com/en/latest/context_managers.html