Prometheus e Grafana são a dupla mais comum para monitorar um broker MQTT. O Prometheus coleta métricas via HTTP e avalia regras de alerta. O Grafana desenha os dashboards. Os brokers expõem métricas de duas formas: alguns têm um endpoint Prometheus nativo (EMQX, VerneMQ, HiveMQ por meio de uma extensão), enquanto outros, como o Mosquitto, só publicam tópicos $SYS e precisam de um exporter para traduzi-los.
Este guia conecta as três fontes de dados de que você provavelmente vai precisar: um exporter para o Mosquitto, o endpoint nativo do EMQX e uma sonda do lado do cliente que funciona com qualquer broker, inclusive os gerenciados. Depois, adiciona dashboards e alertas.
De onde vêm as métricas
| Broker | Como o Prometheus obtém as métricas |
|---|---|
| Mosquitto | mosquitto-exporter assina $SYS/# e serve /metrics (porta 9234 por padrão) |
| EMQX 5 | Endpoint embutido /api/v5/prometheus/stats na porta do dashboard/API (18083), ou envio para um Pushgateway |
| HiveMQ | HiveMQ Prometheus Monitoring Extension, serve /metrics (porta 9399 por padrão) |
| VerneMQ | /metrics embutido no listener HTTP (porta 8888 por padrão) |
| Broker gerenciado | Métricas do provedor, se houver, mais a sua própria sonda do lado do cliente |
Métricas do broker mostram o que o broker está fazendo: conexões, throughput, filas e descartes. Uma sonda do lado do cliente mostra o que os seus dispositivos experimentam: eles conseguem conectar, e quanto tempo leva uma mensagem? Você precisa das duas. Se só puder ter uma, escolha a sonda, porque é ela que pega falhas de DNS, TLS, load balancer e autenticação.
Se $SYS é novidade para você, leia primeiro monitorar um broker com tópicos $SYS. O exporter abaixo é uma camada fina sobre isso.
Um stack local com Docker Compose
Este stack roda Mosquitto, o exporter, Prometheus e Grafana juntos. É um bom laboratório para montar dashboards antes de apontá-los para produção.
services:
mosquitto:
image: eclipse-mosquitto:2
ports: ["1883:1883"]
volumes:
- ./mosquitto.conf:/mosquitto/config/mosquitto.conf:ro
mosquitto-exporter:
image: sapcc/mosquitto-exporter
command: ["--endpoint", "tcp://mosquitto:1883"]
ports: ["9234:9234"]
depends_on: [mosquitto]
prometheus:
image: prom/prometheus
ports: ["9090:9090"]
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml:ro
- ./alerts.yml:/etc/prometheus/alerts.yml:ro
grafana:
image: grafana/grafana
ports: ["3000:3000"]
volumes:
- ./grafana-datasource.yml:/etc/grafana/provisioning/datasources/prometheus.yml:rolistener 1883
allow_anonymous true
sys_interval 10apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
url: http://prometheus:9090
isDefault: trueallow_anonymous true só é aceitável no seu notebook. Em um broker real, crie um usuário de monitoramento que possa ler $SYS/# e nada mais, e passe-o ao exporter com --user e --pass. O gerador de mosquitto.conf pode montar os blocos de listener e autenticação para você. Para um laboratório mais completo, com mais serviços, veja o stack MQTT com Docker Compose.
O exporter transforma cada tópico $SYS numérico em uma métrica cujo nome segue o caminho do tópico; por exemplo, $SYS/broker/clients/connected vira broker_clients_connected. Abra http://localhost:9234/metrics para ver os nomes exatos que a sua versão gera antes de escrever consultas.
Um exporter de sondagem para qualquer broker
Este exporter em Python (paho-mqtt 2.x e prometheus_client) conecta via TLS a cada 15 segundos, assina um tópico único, publica uma mensagem e espera que ela volte. Ele exporta se deu certo e quanto tempo cada etapa levou:
import os, ssl, threading, time, uuid
import paho.mqtt.client as mqtt
from prometheus_client import Gauge, Histogram, start_http_server
HOST, PORT, INTERVAL = "broker.connectmq.com", 8883, 15
success = Gauge("mqtt_probe_success", "1 if the last connect/publish/receive cycle worked")
connect_s = Gauge("mqtt_probe_connect_seconds", "TCP + TLS + CONNACK time of the last probe")
roundtrip = Histogram("mqtt_probe_roundtrip_seconds", "Subscribe, publish and receive time",
buckets=(0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5))
def probe() -> bool:
topic = f"testmqtt/probe/{uuid.uuid4().hex[:8]}"
connected, received = threading.Event(), threading.Event()
c = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
client_id=f"testmqtt-probe-{uuid.uuid4().hex[:6]}")
c.username_pw_set(os.getenv("MQTT_USER"), os.getenv("MQTT_PASS"))
c.tls_set(cert_reqs=ssl.CERT_REQUIRED)
c.on_connect = lambda cl, ud, fl, rc, pr: connected.set() if not rc.is_failure else None
c.on_subscribe = lambda cl, ud, mid, rcs, pr: cl.publish(topic, "ping", qos=1)
c.on_message = lambda cl, ud, msg: received.set()
t0 = time.perf_counter()
try:
c.connect(HOST, PORT, keepalive=10)
c.loop_start()
if not connected.wait(5):
return False
connect_s.set(time.perf_counter() - t0)
t1 = time.perf_counter()
c.subscribe(topic, qos=1)
if not received.wait(5):
return False
roundtrip.observe(time.perf_counter() - t1)
return True
except OSError:
return False
finally:
c.disconnect()
c.loop_stop()
if __name__ == "__main__":
start_http_server(9105) # métricas em http://localhost:9105/metrics
while True:
success.set(1 if probe() else 0)
time.sleep(INTERVAL)Instale com pip install paho-mqtt prometheus-client. Abrir uma conexão nova a cada ciclo é proposital: isso exercita DNS, TLS e autenticação todas as vezes, como um dispositivo que reinicia. Use um client ID único em cada execução. O gerador de client ID explica por que IDs duplicados derrubam um ao outro.
Configuração de scrape
global:
scrape_interval: 15s
rule_files: ["/etc/prometheus/alerts.yml"]
scrape_configs:
- job_name: mosquitto
static_configs:
- targets: ["mosquitto-exporter:9234"]
- job_name: mqtt-probe
static_configs:
- targets: ["host.docker.internal:9105"] # onde a sonda roda
- job_name: emqx
metrics_path: /api/v5/prometheus/stats
static_configs:
- targets: ["emqx:18083"]Remova os jobs que você não usa. Nas versões recentes do EMQX, o endpoint de estatísticas pode ser configurado para exigir autenticação. Nesse caso, adicione basic_auth com uma API key e o secret. Para testar o EMQX localmente, veja EMQX no Docker. host.docker.internal funciona no Docker Desktop. No Linux, rode a sonda como outro serviço do Compose.
Dashboards que respondem perguntas reais
Um dashboard MQTT útil tem poucos painéis, e cada um responde a uma pergunta que alguém vai fazer durante um incidente:
| Painel | PromQL (exemplo) |
|---|---|
| Há clientes conectados? | broker_clients_connected ou sum(emqx_connections_count) |
| Mensagens de entrada / saída por segundo | rate(broker_messages_received[5m]), rate(emqx_messages_sent[5m]) |
| Estamos descartando mensagens? | rate(broker_publish_messages_dropped[5m]) ou rate(emqx_messages_dropped[5m]) |
| Um cliente consegue conectar agora? | mqtt_probe_success |
| Quão lenta está a entrega? | histogram_quantile(0.99, sum by (le) (rate(mqtt_probe_roundtrip_seconds_bucket[10m]))) |
| Tempo de conexão | mqtt_probe_connect_seconds |
Use rate() nos contadores e nunca plote o valor bruto do contador. Coloque os painéis da sonda no topo, porque eles mostram o que os usuários veem. No grafana.com há dashboards da comunidade para o exporter do Mosquitto e para o EMQX. São um bom ponto de partida, mas confira se os nomes de métricas batem com a versão do seu exporter.
Regras de alerta
groups:
- name: mqtt
rules:
- alert: MqttProbeFailing
expr: max_over_time(mqtt_probe_success[3m]) == 0
labels: { severity: page }
annotations:
summary: "No successful MQTT round trip for 3 minutes"
- alert: MqttProbeSlow
expr: histogram_quantile(0.99, sum by (le) (rate(mqtt_probe_roundtrip_seconds_bucket[10m]))) > 0.5
for: 10m
labels: { severity: ticket }
- alert: MqttClientsDropped
expr: broker_clients_connected < 0.7 * (broker_clients_connected offset 10m)
for: 2m
labels: { severity: page }
- alert: MqttExporterDown
expr: up{job="mosquitto"} == 0
for: 2m
labels: { severity: ticket }MqttClientsDropped detecta o padrão clássico de incidente: uma grande parte dos dispositivos desconecta de uma vez, depois de um certificado expirado, uma mudança de rede ou um reinício do broker. Encaminhe os alertas page pelo Alertmanager para o canal de plantão e os ticket para um lugar mais tranquilo. Para verificações externas e a matemática de SLO, veja monitoramento de uptime MQTT.
Teste o próprio monitoramento
Antes de confiar nos alertas, faça cada um disparar de propósito:
- Falha da sonda: troque
MQTT_PASSpor um valor errado e reinicie a sonda.mqtt_probe_successdeve cair para 0 eMqttProbeFailingdeve disparar em cerca de três minutos. - Queda de clientes: conecte um lote de clientes de teste (um simulador de dispositivos ou várias abas do cliente online), espere dez minutos e feche-os. O painel de clientes conectados deve cair de acordo.
- Exporter fora do ar:
docker compose stop mosquitto-exporterdeve dispararMqttExporterDown. - Latência: adicione atraso com um network shaper ou compare os números da sonda com um teste de latência dedicado.
Um alerta que nunca disparou em um teste pode não disparar também durante uma queda real.
Prometheus e Grafana trazem histórico, dashboards e alertas que o $SYS sozinho não oferece. Combine métricas do broker com uma sonda do lado do cliente, mantenha o dashboard enxuto e teste cada alerta uma vez antes de depender dele.
Perguntas frequentes
O Mosquitto tem um endpoint Prometheus embutido?
Não. O Mosquitto publica suas estatísticas em tópicos $SYS. Um exporter como o mosquitto-exporter assina $SYS/# e expõe os valores em um endpoint HTTP /metrics que o Prometheus pode coletar.
Posso monitorar um broker MQTT gerenciado com Prometheus?
Sim, pelo lado do cliente. Mesmo quando você não pode instalar um exporter ao lado do broker, uma pequena sonda que conecta, publica e recebe uma mensagem pode exportar métricas de sucesso e latência. Muitas vezes esse é o sinal mais útil.
Sobre o que devo alertar primeiro?
Comece com três alertas: a sonda falhando por alguns minutos, uma queda brusca de clientes conectados e mensagens descartadas acima de zero. Adicione alertas de latência quando souber qual é o seu p99 normal.


