Eclipse Mosquitto e GraalVM: Broker MQTT e Java Nativo para IoT

Este é meu primeiro post sobre o Eclipse Mosquitto, um broker MQTT open source amplamente utilizado em projetos IoT (Internet das Coisas). Vamos ver, passo a passo, como configurá-lo, executá-lo via Docker e Docker Compose, além de compilar nossas aplicações Java para binários nativos usando GraalVM, tudo para mostrar a agilidade e o baixo consumo de recursos que esse ecossistema pode oferecer.
O que é MQTT?
O MQTT é um protocolo de comunicação leve, ideal para dispositivos com recursos limitados de rede, processamento e consumo de energia. Ele usa o modelo publicador/assinante (pub/sub), onde:
-
O publicador (publisher) envia mensagens para um tópico;
-
O assinante (subscriber) se inscreve (subscribe) nesse tópico;
-
O broker (no nosso caso, o Eclipse Mosquitto) é responsável por intermediar essa comunicação, recebendo e entregando as mensagens.
Outras alternativas de brokers MQTT
Se você está pesquisando sobre brokers MQTT, saiba que o Eclipse Mosquitto não é o único nome na jogada. Há várias outras soluções, cada qual com seus diferenciais:
-
HiveMQ: Oferece um broker escalável para grandes infraestruturas IoT, com foco em alto desempenho e suporte a clustering.
-
EMQX: Uma plataforma MQTT que inclui recursos avançados de monitoramento e gerenciamento, além de integrar com outros protocolos.
-
VerneMQ: Conhecido por ser escrito em Erlang/OTP, oferece alta disponibilidade e escalabilidade por padrão.
-
RabbitMQ (com plugin MQTT): Embora o RabbitMQ seja mais conhecido como um broker AMQP, ele pode atuar como broker MQTT por meio de plugins — útil se você já usa RabbitMQ e quer unificar protocolos.
A escolha depende muito das suas necessidades de escalabilidade, linguagens envolvidas, requisitos de segurança, facilidade de configuração, entre outros fatores.
Por que o Mosquitto é uma das melhores alternativas?
O Eclipse Mosquitto brilha em cenários em que simplicidade, leveza e conformidade com o padrão MQTT são fundamentais. Alguns motivos que fazem dele uma escolha popular:
-
Instalação fácil: Disponível em repositórios oficiais de muitas distribuições Linux, em pacotes para Windows/macOS e em imagens Docker.
-
Leveza: Consome poucos recursos de CPU e memória, tornando-o ideal para rodar em dispositivos de borda (edge computing).
-
Open Source e confiável: Com ampla comunidade, manutenções constantes e suporte oficial da Eclipse Foundation.
-
Escalabilidade: Apesar de ser leve, pode lidar com um grande número de conexões simultâneas, desde que a infraestrutura de rede e hardware suporte.
-
Documentação clara: Fácil de aprender e configurar para quem está iniciando no mundo MQTT.
Onde o Mosquitto é utilizado em IoT
O Mosquitto se encaixa muito bem em projetos de:
-
Automação residencial: Dispositivos de casas inteligentes (smart homes) usam MQTT para trocar dados de sensores, lâmpadas, fechaduras, etc.
-
Sistemas de monitoramento: Sensores industriais ou ambientais (temperatura, umidade, vibração) publicam dados em tempo real para dashboards ou sistemas de alerta.
-
Veículos conectados: Alguns projetos de mobilidade, carros e drones utilizam MQTT para telemetria leve e confiável.
-
Smart Cities: Gerenciamento de iluminação pública, tráfego, coleta de lixo, onde há milhares de sensores trocando informações.
-
Dispositivos embarcados: Graças ao baixo overhead do protocolo, é comum em dispositivos com hardware limitado, tornando a comunicação eficiente.
Em resumo, sempre que você precisa de um broker confiável, compatível com o protocolo MQTT, e que possa rodar em ambientes com recursos limitados ou crescer para atender mais dispositivos, o Mosquitto surge como uma ótima escolha.
Subindo o Mosquitto com Docker e Docker Compose
1) Arquivo docker-compose.yml
Para facilitar a vida, podemos subir o Mosquitto com Docker Compose em vez de usar apenas docker run
. Num diretório, crie dois arquivos: docker-compose.yml
e mosquitto.conf
. A estrutura final fica assim:
. ├── docker-compose.yml └── mosquitto.conf
docker-compose.yml (exemplo mínimo):
version: '3' services: mosquitto: image: eclipse-mosquitto container_name: mosquitto ports: - "1883:1883" - "9001:9001" volumes: - "./mosquitto.conf:/mosquitto/config/mosquitto.conf" restart: unless-stopped
2) Arquivo mosquitto.conf
# Escuta na porta 1883 para conexões TCP MQTT listener 1883 allow_anonymous true # Escuta na porta 9001 para conexões WebSocket listener 9001 protocol websockets allow_anonymous true
Em ambiente de produção, recomendamos desabilitar allow_anonymous true
e configurar autenticação (user/password) ou ACLs (listas de controle de acesso).
3) Subindo o broker
No mesmo diretório, rode:
docker-compose up -d
Isso vai levantar o contêiner “mosquitto” em modo daemon, expondo as portas 1883 (TCP) e 9001 (WebSocket).
Atenção ao “local only mode” no Mosquitto 2.x
A partir da versão 2.x, o Mosquitto inicia em modo apenas local (“local only mode”) por padrão, o que impede conexões externas sem um listener configurado. O nosso mosquitto.conf
acima já resolve isso, pois define explicitamente os listeners para 1883 e 9001.
Exemplo de Aplicação Java (Publisher + Subscriber)
Para nosso exemplo, vamos usar a Eclipse Paho, biblioteca oficial para clientes MQTT. E, para ficar ainda mais interessante, vamos mostrar como gerar um binário nativo com GraalVM, melhorando significativamente o tempo de inicialização (startup) e reduzindo o consumo de memória, algo crucial em cenários de IoT.
Dependências e Plugin GraalVM no Maven
A seguir, um exemplo de pom.xml
que gera executáveis nativos tanto para o Publisher quanto para o Subscriber. Observe que usamos as propriedades mainClass
e imageName
para tornar o nome do binário e a classe principal parametrizáveis:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 \ http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.gasparbarancelli</groupId> <artifactId>demo-eclipse-mosquitto</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>23</maven.compiler.source> <maven.compiler.target>23</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <!-- Configurações default para gerar o Publisher --> <imageName>publisher</imageName> <mainClass>com.gasparbarancelli.Publisher</mainClass> </properties> <dependencies> <dependency> <groupId>org.eclipse.paho</groupId> <artifactId>org.eclipse.paho.client.mqttv3</artifactId> <version>1.2.5</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.graalvm.buildtools</groupId> <artifactId>native-maven-plugin</artifactId> <version>0.10.4</version> <executions> <execution> <goals> <goal>build</goal> </goals> </execution> </executions> <configuration> <mainClass>${mainClass}</mainClass> <imageName>${imageName}</imageName> </configuration> </plugin> </plugins> </build> </project>
Código do Publisher
package com.gasparbarancelli; import org.eclipse.paho.client.mqttv3.MqttClient; import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttMessage; import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; public class Publisher { private static final String BROKER_URL = "tcp://localhost:1883"; private static final String TOPIC = "test/topic"; private static final String CLIENT_ID = "PublisherExample"; public static void main(String[] args) { try { MqttClient client = new MqttClient(BROKER_URL, CLIENT_ID, new MemoryPersistence()); client.connect(); // Se houver argumentos na linha de comando, vamos publicar a string deles String mensagem = args.length > 0 ? String.join(" ", args) : "Olá, Mosquitto! Mensagem de teste via MQTT."; MqttMessage mqttMessage = new MqttMessage(mensagem.getBytes()); mqttMessage.setQos(1); client.publish(TOPIC, mqttMessage); System.out.println("Mensagem publicada: " + mensagem); client.disconnect(); client.close(); } catch (MqttException e) { e.printStackTrace(); } } }
Código do Subscriber
package com.gasparbarancelli; import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; import org.eclipse.paho.client.mqttv3.MqttCallback; import org.eclipse.paho.client.mqttv3.MqttClient; import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttMessage; import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence; public class Subscriber implements MqttCallback { private static final String BROKER_URL = "tcp://localhost:1883"; private static final String TOPIC = "test/topic"; private static final String CLIENT_ID = "SubscriberExample"; public static void main(String[] args) { new Subscriber().startSubscriber(); } public void startSubscriber() { try { MqttClient client = new MqttClient(BROKER_URL, CLIENT_ID, new MemoryPersistence()); client.setCallback(this); client.connect(); client.subscribe(TOPIC, 1); System.out.println("Assinado no tópico: " + TOPIC); } catch (MqttException e) { e.printStackTrace(); } } @Override public void connectionLost(Throwable cause) { System.out.println("Conexão perdida! Causa: " + cause.getMessage()); } @Override public void messageArrived(String topic, MqttMessage message) { System.out.println("Mensagem recebida. Tópico: " + topic + ", Mensagem: " + new String(message.getPayload())); } @Override public void deliveryComplete(IMqttDeliveryToken token) { // Chamado quando a publicação é confirmada } }
Gerando os binários nativos
1) Publisher
-
Se você quiser gerar o Publisher como binário, certifique-se de que o
pom.xml
aponte omainClass
e oimageName
para o Publisher. Exemplo:
<properties> <imageName>publisher</imageName> <mainClass>com.gasparbarancelli.Publisher</mainClass> ... </properties>
-
Então, execute:
mvn clean package -Pnative
-
Será gerado um binário chamado publisher (no diretório
target/
). -
Para publicar uma mensagem:
./target/publisher "Olá, Mosquitto! Mensagem de teste via MQTT."
2) Subscriber
Para gerar um binário do Subscriber, você pode sobrescrever as propriedades via linha de comando, sem precisar alterar o pom.xml
:
mvn clean package -Pnative \ -DmainClass=com.gasparbarancelli.Subscriber \ -DimageName=subscriber
Isso gerará o binário subscriber em target/
. Para rodar:
./target/subscriber
Baixo consumo de memória e prints
A grande vantagem aqui é que o binário nativo inicia rapidamente (em milissegundos) e tem um consumo muito menor de recursos se comparado a uma aplicação Java típica rodando em JVM. Veja os prints abaixo capturados em um MacBook Air, mostrando o subscriber
rodando e assinando o tópico test/topic
, além do top
filtrado pelo PID. Note que o uso de memória do app nativo ficou abaixo de 5 MB (4577K):

Acima, o %CPU
está em 0.0% (praticamente ocioso), e a MEM está em 4577K (~4,5 MB).
Abaixo, os logs mostrando as mensagens recebidas e publicadas:


Observe que o subscriber
continua rodando, recebendo mensagens publicadas pelo publisher
, que podem ser passadas como argumentos de linha de comando.
Código de Exemplo no GitHub
O repositório completo com todo o código de exemplo (Publisher, Subscriber e configuração) está disponível em:
Sinta-se à vontade para clonar e experimentar!
Conclusão
O Eclipse Mosquitto é uma solução simples e eficiente para quem quer ingressar no universo do MQTT e IoT sem complicações. Seu baixo consumo de recursos, aliado à facilidade de instalação e configuração (especialmente via Docker), o tornam uma excelente escolha para projetos que precisam de confiabilidade e escalabilidade.
Além disso, demonstramos como é fácil implementar um publisher e subscriber MQTT em Java usando a biblioteca Eclipse Paho, que segue rigorosamente as especificações do protocolo. E, ao compilar nossas aplicações para binários nativos com GraalVM, ganhamos em velocidade de inicialização e reduzimos significativamente o uso de memória, deixando a solução ainda mais atrativa para cenários de dispositivos embarcados e aplicações de alto desempenho.
Assim, para quem deseja combinar leveza, performance e praticidade, o Mosquitto continua sendo uma das escolhas favoritas de desenvolvedores e profissionais de IoT.