RabbitMQ
O RabbitMQ é um broker de mensagens MQTT, AMQP, STOMP e WebSTOMP (STOMP via WebSockets) e cliente JMS (Java Message Service) feito na linguagem de programação Erlang e mantido pela empresa Pivotal (a mesma que fez o Spring, famoso framework web para Java)
Como o RabbitMQ funciona? O vídeo abaixo explica muito bem.
Instalando RabbitMQ no Debian/Ubuntu Linux
Há várias maneiras de instalar o RabbitMQ no Linux. Os tutoriais oficiais não são tão simples. Aqui vou apresentar quatro delas.
Recomendo muito instalar o RabbitMQ de duas maneiras: via apt ou via docker, porque são as opções mais fáceis. As outras opções são bem mais complicadas e demandam tempo.
Instalação fácil via apt-get
(versão desatualizada)
Você pode usar o comando apt-get para instalar o RabbitMQ. O problema é que geralmente são versões antigas.
apt install rabbitmq-server
O problema em se instalar dessa forma é que a versão instalada muito provavelmente é antiga e pode conter alguns bugs. Se você estiver OK com isso, sem problemas.
Instalação manual via dpkg (versão que você quiser)
Nesse modo você precisa instalar manualmente o Erlang e depois o RabbitMQ. Tome cuidado com isso, pois a versão escolhida do Erlang e do RabbitMQ precisam ser compatíveis. Veja aqui a lista de compatibilidades.
Instalação via apt-get pelo repositório do RabbitMQ (última versão)
Tentei seguir esse tutorial na documentação oficial mas não consegui. Foi bem sofrido.
Há um script pronto que faz a instalação automática aqui. Não cheguei a testar.
Instalação via Docker (versão que você quiser)
Instale a última versão do docker. Pra isso você precisa adicionar o repositório oficial do Docker. Esse tutorial da Digital Ocean é excelente.
Pronto, o Docker está instalado e o status do serviço do docker deve aparecer na tela.
Agora vamos instalar o RabbitMQ!
Os conteiners docker oficiais do time do RabbitMQ estão nesse link.
docker run -d --hostname rabbitmq --log-driver=journald --name rabbitmq --restart unless-stopped --network host rabbitmq:management
Neste comando fazemos:
- Criamos um contêiner docker com hosname rabbitmq e nome do container rabbitmq
- Instalamos no contêiner da última versão do RabbitMQ disponível no docker hub com o plugin management ativo (plugin para gerenciar o RabbitMQ via interface web)
- Permitimos que todas as portas de dentro do conteiner sejam acessíveis pelo computador hospedeiro
- O RabbitMQ será reiniciado se o programa cair ou se o computador for reiniciado. Caso o RabbitMQ seja parado manualmente, ele só será reiniciado automaticamente se ele for iniciado manualmente em seguida
Pronto! Acesse o gerenciador do RabbitMQ em localhost:15672
Como acessar o RabbitMQ terminal pelo docker?
docker exec -it rabbitmq bash
Vendo logs do RabbitMQ pelo systemd no computador hospedeiro
# -f para mostrar mensagens em fluxosudo journalctl -f CONTAINER_NAME=rabbitmq # -b para apenas mensagens desde o último boot sudo journalctl -b CONTAINER_NAME=rabbitmq # -o json para mostrar log em formato json sudo journalctl -o json CONTAINER_NAME=rabbitmq
Requisitos de Hardware e Consumo
Quanto consome o RabbitMQ via docker?
Ubuntu 18 x64 em uma VirtualBox com 1.45 gb de memóra RAM.
Ubuntu 18 x64 sem nada instalado
- Consumo memória RAM - 83.4M/1.45G
- 0,7% CPU
Pós instalação Docker
- Consumo memória RAM - 138MB/1.45GB
- Consumo HD 243MB
- Download de 50.7 MB
Pós instalação RabbitMQ no Docker
- Consumo memória RAM - 257MB/1.45GB
- Consumo HD ?
Quais portas o RabbitMQ usa?
- 5672, 5671: Portas mais comuns (AMQP), usadas para editar, acessar, publicar e se inscrever em filas AMQP 0-9-1 e 1.0 com e sem criptografia TLS
- 1883, 8883: Portas MQTT, usadas para acessar via MQTT com e sem criptografia TLS, se o MQTT plugin estiver atualizado
- 15672: HTTP API clients, management UI and rabbitmqadmin (only if the management plugin is enabled)
- 61613, 61614: STOMP clients without and with TLS (only if the STOMP plugin is enabled)
- 15674, 15673?: STOMP-over-WebSockets clients (ativo apenas se o plugin Web STOMP plugin estiver habilitado)
- 15675, 15673?: MQTT-over-WebSockets sem ou com TLS (ativo apenas se o plugin Web MQTT plugin estiver habilitado)
- 4369: epmd, a peer discovery service used by RabbitMQ nodes and CLI tools
- 25672: used for inter-node and CLI tools communication (Erlang distribution server port) and is allocated from a dynamic range (limited to a single port by default, computed as AMQP port + 20000). Unless external connections on these ports are really necessary (e.g. the cluster uses federation or CLI tools are used on machines outside the subnet), these ports should not be publicly exposed. See networking guide for details.
- 35672-35682: used by CLI tools (Erlang distribution client ports) for communication with nodes and is allocated from a dynamic range (computed as server distribution port + 10000 through server distribution port + 10010). See networking guide for details.
- 15692: Prometheus metrics (only if the Prometheus plugin is enabled)
Referência:
https://www.rabbitmq.com/networking.html
Habilitando plugins no RabbitMQ
O RabbitMQ conta com alguns plugins que aumentam suas funcionalidades. Para ver os plugins disponíveis e instalá-los:
# Listando todos os plugins disponíveis, ativos e inativosrabbitmq-plugins list
# Habilitando um pluginrabbitmq-plugins enable plugin-name
# Desabilitando um pluginrabbitmq-plugins disable plugin-name
Integrando MQTT com o RabbitMQ
Você pode enviar mensagens MQTT diretamente para o RabbitMQ.
Para isso, habilite o plugin rabbitmq_mqtt
rabbitmq-plugins enable rabbitmq_mqtt
Todas as mensagens recebidas via MQTT são recebidas pela exchange amq.topic. Você pode mudar essa exchange no arquivo de configuração.
Particularidades do MQTT dentro do RabbitMQ (QoS e persistência)
O RabbitMQ não funciona com QoS2, ou seja, não é possível garantir que uma mensagem chege exatamente uma vez no broker. Quando o RabbitMQ recebe uma mensagem com QoS2 ela a trata automaticamente como QoS1.
Sobre persistência de mensagens, em uma fila dotipo Durable, mensagens com QoS1 e QoS2 são automaticamente salvas no HD, ou seja, em caso de falha no RabbitMQ e restart do servidor RabbitMQ ou do sistema operacional em si, as mensagens não serão perdidas. Em contrapartida, com QoS0 as mensagens existem apenas na memória RAM, em caso de falha e restart, as mensagens são perdidas.
Como salvar mensagens do tipo topic (amq.topic) em uma queue?
- Crie uma queue
- Faça um binding na queue criada com a exchange amq.topic
- Decida e insira a binding key
Os tópicos do MQTT se traduzem para os tópicos do RabbitMQ da seguinte forma:
MQTT | RabbitMQ |
casa/sala-de-estar/lampada | casa.sala-de-estar.lampada |
casa | casa |
casa/# | casa.# |
# | # |
E como as mensagens são salvas na fila dependendo do tópico?
Tópico | Resultado |
# | Captura todas as mensagens recebidas. |
casa.# | Captura todas as mensagens para casa, incluindo as aninhadas (casa.quarto, casa.banheiro, casa.quarto.lampada...). |
casa | Captura todas as mensagens para casa, somente! |
*.sala | Captura todas as mensagens para a sala (no segundo nível). |
Como fazer vários servidores RabbitMQ trabalharem juntos?
Há 3 formas de criar um sistema distribuído com servidores Rabbit:
- Cluster
- Federation
- Shovel
Shovel
O Shovel é a maneira mais simples de fazer vários servidores trabalharem juntos com o RabbitMQ.
- Ao fazer um shovel e não definir uma routing key de saída, o shovel utilizará automaticamente a routing key original da mensagem.
- Ao criar um shovel é possível ver um consumer na queue a ser propagada para outro local.
- O shovel poderá duplicar mensagens. Isso é uma limitação da implementação do AMQP pelo RabbitMQ. Apesar disso o RabbitMQ consegue garantir que nenhuma mensagem será perdida.
Criando uma imagem Docker com certos plugins pré instalados
Crie uma pasta nova e dentro dela um arquivo chamado Dockerfile com o seguinte:
FROM rabbitmq:3.7-managementRUN rabbitmq-plugins enable rabbitmq_shovel &&\ rabbitmq-plugins enable rabbitmq_shovel_management &&\ rabbitmq-plugins enable rabbitmq_mqtt
Este arquivo irá instalar o RabbitMQ 3.7 com os plugins:
- Management (interface gráfica)
- Shovel
- Shovel Management (interface gráfica para o shove)
- RabbitMQ MQTT
Estando dentro da pasta execute:
docker build -t nome-da-sua-imagem-customizada .# o . indica para o docker verificar a pasta atual pelo Dockerfile
Para instalar essa imagem customizada do RabbitMQ
docker run -d --hostname rabbitmq --name rabbitmq --restart unless-stopped -p 15672:15672 -p 5672:5672 -p 5671:5671 -p 1883:1883 nome-da-sua-imagem-customizada
Publicando mensagens com AMQP
Ao publicar uma mensagem no RabbitMQ via AMQP, você pode atribuir alguns parâmetros no cabeçalho da mensagem. Estes parâmetros são:
- Nome da Exchange (string)
- Routing Key (string)
- Mandatory (verdadeiro ou falso)
- Immediate (verdadeiro ou falso)
- Delivery Mode (1 = não-persistente, 2=persistente)
- App ID (string)
- Cluster ID (string)
- Content Encoding (string)
- Content Type (string)
- Correlation ID (string)
- Expiration (string)
- Headers? (uma lista com chave e valor)
- Message ID (string)
- Priority (int)
- Reply To (string)
- Timestamp (data)
- Type (string)
- User ID (string)
Documentação sobre headers do AMQP no RabbitMQ
https://www.rabbitmq.com/amqp-0-9-1-reference.html
Sobre a flag Mandatory
https://jack-vanlightly.com/blog/2017/3/10/rabbitmq-the-different-failures-on-basicpublish#:~:text=The%20mandatory%20flag%20tells%20RabbitMq,when%20an%20ack%20is%20received.
Sobre a flag Mandatory e Immediate
https://stackoverflow.com/questions/6386117/rabbitmq-use-of-immediate-and-mandatory-bits
Tutoriais:
https://docs.vmware.com/en/vCloud-Availability-for-vCloud-Director/1.0.1/com.vmware.vcavcd.install.doc/GUID-AC63692F-0288-4F49-8D4D-9F837D1E4FE5.html
https://success.outsystems.com/Support/Enterprise_Customers/Maintenance_and_Operations/Cache_Invalidation_in_OutSystems_11/Enable_TLS_communication_in_RabbitMQ
https://www.rabbitmq.com/ssl.html#enabling-tls
Referências
Arquivo de configuração do RabbitMQ
https://www.rabbitmq.com/configure.html#configuration-file
Documentação sobre TLS no RabbitMQ
https://www.rabbitmq.com/ssl.html
Troubleshooting TLS no RabbitMQ
https://www.rabbitmq.com/troubleshooting-ssl.html
Configurando Dynamic Shovel
https://www.rabbitmq.com/shovel-dynamic.html
Configurando Shovel
https://www.rabbitmq.com/shovel.html
URI query Parameters
https://www.rabbitmq.com/uri-query-parameters.html
Referências
Instalação do RabbitMQ
Instalando RabbitMQ no Debian/Ubuntu
https://www.rabbitmq.com/install-debian.html#package-dependencies
Instalando RabbitMQ via Docker
https://hub.docker.com/_/rabbitmq/
Instalando RabbitMQ
https://www.vultr.com/docs/how-to-install-rabbitmq-on-ubuntu-16-04-47
Criando clusters
Documentação oficial sobre comunicação entre brokers distribuídos
https://www.rabbitmq.com/distributed.html
Documentação oficial sobre o Federation Plugin
https://www.rabbitmq.com/federation.html
Documentação oficial sobre o Shovel Plugin
https://www.rabbitmq.com/shovel.html
Qual a diferença entre Shovel e Federation?
https://stackoverflow.com/questions/19357272/when-to-use-rabbitmq-shovels-and-when-federation-plugin
Documentação oficial sobre criação de clusters
https://www.rabbitmq.com/clustering.html
RabbitMQ e garantia de entrega
Sobre garantia de entrega do RabbitMQ e semântica
https://www.rabbitmq.com/semantics.html
Sobre confirmações de mensagens (publishers e consumers)
https://www.rabbitmq.com/confirms.html
Publisher Confirms (Java)
https://www.rabbitmq.com/tutorials/tutorial-seven-java.html
Tutorial RabbitMQ Java
https://www.rabbitmq.com/api-guide.html
Documentação do RabbitMQ
Documentação da Pivotal
https://rabbitmq.docs.pivotal.io/37/index.html
Tipos de Exchanges e seus comportamentos
Artigo da Lisa Smith sobre tipos de exchanges
https://www.compose.com/articles/configuring-rabbitmq-exchanges-queues-and-bindings-part-1/
Exemplo de arquivo de configuração do RabbitMQ rabbitmq.conf
# Disabling guest user from non localhost (loopback) interfacesloopback_users.guest = false ###### AMQP Configurations ###### listeners.tcp.default = 5672 listeners.ssl.default = 5671 ssl_options.cacertfile = /etc/rabbitmq/my.ca_bundle ssl_options.certfile = /etc/rabbitmq/my.crt ssl_options.keyfile = /etc/rabbitmq/my.key # ssl_options.verify = verify_peer ssl_options.verify = verify_none # ssl_options.fail_if_no_peer_cert = true ssl_options.fail_if_no_peer_cert = false # Disabling TLS versions older than 1.1 ssl_options.versions.1 = tlsv1.2 ssl_options.versions.2 = tlsv1.1 ###### MQTT Configurations ###### mqtt.listeners.tcp.default = 1883 ## Default MQTT with TLS port is 8883 mqtt.listeners.ssl.default = 8883 # anonymous connections, if allowed, will use the default # credentials specified here mqtt.allow_anonymous = false # mqtt.default_user = guest # mqtt.default_pass = guest mqtt.vhost = / mqtt.exchange = amq.topic # 24 hours by default mqtt.subscription_ttl = 86400000 # To disable # mqtt.subscription_ttl = undefined mqtt.prefetch = 10 # Dealing with MQTT Retained Message ## use DETS (disk-based) store for retained messages # mqtt.retained_message_store = rabbit_mqtt_retained_msg_store_dets ## only used by DETS store #mqtt.retained_message_store_dets_sync_interval = 2000 ## use ETS (ram-based) store for retained messages # mqtt.retained_message_store = rabbit_mqtt_retained_msg_store_ets # Application specific MQTT # mqtt.listeners.tcp.1 = 127.0.0.1:1883 # mqtt.listeners.tcp.2 = ::1:1883 # mqtt.tcp_listen_options.backlog = 4096 # mqtt.tcp_listen_options.recbuf = 131072 # mqtt.tcp_listen_options.sndbuf = 131072 # mqtt.tcp_listen_options.keepalive = true # mqtt.tcp_listen_options.nodelay = true # mqtt.tcp_listen_options.exit_on_close = true # mqtt.tcp_listen_options.send_timeout = 120 ###### Management Configurations ###### management.tcp.port = 15672 management.ssl.port = 15671 management.ssl.cacertfile = /etc/rabbitmq/my.ca_bundle management.ssl.certfile = /etc/rabbitmq/my.crt management.ssl.keyfile = /etc/rabbitmq/my.key ###### Web MQTT Configurations ###### web_mqtt.tcp.port = 15675 web_mqtt.ssl.port = 15673 web_mqtt.ssl.backlog = 1024 web_mqtt.ssl.cacertfile = /etc/rabbitmq/my.ca_bundle web_mqtt.ssl.certfile = /etc/rabbitmq/my.crt web_mqtt.ssl.keyfile = /etc/rabbitmq/my.key ###### Web Stomp Configurations ###### web_stomp.tcp.port = 15674 web_stomp.ssl.port = 15676 web_stomp.ssl.backlog = 1024 web_stomp.ssl.cacertfile = /etc/rabbitmq/my.ca_bundle web_stomp.ssl.certfile = /etc/rabbitmq/my.crt web_stomp.ssl.keyfile = /etc/rabbitmq/my.key # WebSocket traffic compression is enabled by default web_stomp.ws_opts.compress = true # WebSocket connection inactivity timeout # web_stomp.ws_opts.idle_timeout # web_stomp.ws_opts.max_frame_size = 50000 # connection inactivity timeout # web_stomp.cowboy_opts.idle_timeout = 60000 # max number of pending requests allowed on a connection # web_stomp.cowboy_opts.max_keepalive = 200 # max number of headers in a request # web_stomp.cowboy_opts.max_headers = 100 # max number of empty lines before request body # web_stomp.cowboy_opts.max_empty_lines = 5 # max request line length allowed in requests # web_stomp.cowboy_opts.max_request_line_length
Mudando a porta do MQTT no RabbitMQ
Crie/edite o arquivo /etc/rabbitmq/rabbitmq.config (configuração antiga)
[{rabbitmq_mqtt, [{tcp_listeners, [12345]}]} ].
Arquivo /etc/rabbitmq/rabbitmq.conf padrão:
loopback_users.guest = falselisteners.tcp.default = 5672 management.tcp.port = 15672