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.xmlaponte omainClasse oimageNamepara 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.