Fundamentos de MQTT

El modelo de publicación/suscripción de MQTT: desacoplar dispositivos y aplicaciones

El modelo de publicación/suscripción de MQTT permite que dispositivos y aplicaciones intercambien datos sin conocerse entre sí. Aprende los tres tipos de desacoplamiento y pruébalos en vivo con dos clientes en broker.connectmq.com.

Diagrama del modelo de publicación/suscripción de MQTT con sensores que publican en un broker que distribuye los mensajes a paneles y servicios
Pruébalo en tu propio broker MQTTConsigue un broker MQTT privado y gestionado con el plan Free y empieza con ejemplos de código listos para usar.
Pruébalo gratis Ejemplos de código Sin tarjeta

El modelo de publicación/suscripción de MQTT es la razón por la que un sensor de temperatura, un panel y un servicio de facturación pueden compartir datos sin conocer nunca la dirección de los demás. En este artículo aprenderás en qué se diferencia pub/sub de petición/respuesta, qué significan en la práctica los tres tipos de desacoplamiento, y comprobarás cada uno de ellos tú mismo con dos ventanas de terminal conectadas a un broker gratuito.

Petición/respuesta frente a publicación/suscripción

La mayoría de los desarrolladores aprenden redes a través de HTTP. Un cliente abre una conexión con un servidor conocido, hace una pregunta y espera la respuesta. Ese patrón es sencillo, pero acopla estrechamente a las dos partes: el cliente debe conocer la dirección del servidor, el servidor debe estar disponible en ese preciso momento y el cliente se bloquea (o sondea) hasta que recibe algo.

Publicación/suscripción rompe ese acoplamiento introduciendo un intermediario. En MQTT, ese intermediario es el broker. Los clientes nunca hablan entre sí; solo hablan con el broker:

  • Un publicador envía un mensaje con un topic como plant1/line2/press/temperature.
  • Un suscriptor indica al broker qué topics le interesan, opcionalmente con comodines como plant1/+/press/#.
  • El broker compara cada mensaje entrante con todas las suscripciones activas y reenvía una copia a cada coincidencia.

Si el papel del servidor intermedio te resulta nuevo, nuestra guía sobre qué hace un broker MQTT cubre con más detalle el enrutamiento, las sesiones y el estado retenido.

Aspecto Petición/respuesta (HTTP) Publicación/suscripción MQTT
Quién conoce a quién El cliente conoce la dirección del servidor Los clientes solo conocen el broker
Dirección El cliente solicita El broker envía al llegar el mensaje
Fan-out a muchos lectores Una petición por lector Una publicación, muchas entregas
Conexión A menudo de corta duración Una única conexión TCP de larga duración
Receptores desconectados La petición falla Las sesiones persistentes pueden encolar

Los tres tipos de desacoplamiento en el modelo de publicación/suscripción de MQTT

La literatura sobre pub/sub suele describir tres dimensiones de desacoplamiento. Vale la pena separarlas, porque cada una resuelve un problema distinto del IoT.

Desacoplamiento espacial

Los publicadores y los suscriptores no conocen la dirección IP ni el nombre de host de los demás, ni siquiera cuántos hay. Un sensor publica en site/tank3/level; que lo reciban cero, una o cincuenta aplicaciones es invisible para el sensor. Esto es lo que te permite añadir un nuevo servicio de analítica el año que viene sin tocar el firmware de miles de dispositivos ya instalados en campo.

Desacoplamiento temporal

El publicador y el suscriptor no necesitan estar conectados a la vez. MQTT ofrece dos mecanismos para ello:

  • Retained messages. El broker guarda el último mensaje retenido de cada topic y se lo entrega de inmediato a cualquier nuevo suscriptor. Un panel que arranca a las 09:00 sigue viendo el estado de la válvula que se publicó a las 06:00.
  • Sesiones persistentes. Un suscriptor que se conecta con el flag clean start a false (y, en MQTT 5, con un intervalo de caducidad de sesión) conserva sus suscripciones mientras está desconectado, y el broker le pone en cola los mensajes QoS 1 y QoS 2.

El desacoplamiento temporal no es ilimitado. Las colas están acotadas por la caducidad de sesión y las cuotas del broker, así que trátalo como un buffer para caídas cortas, no como almacenamiento a largo plazo.

Desacoplamiento de sincronización

Ninguna de las partes bloquea a la otra. Un publicador entrega su mensaje a la biblioteca cliente y sigue con lo suyo; la biblioteca gestiona las confirmaciones en segundo plano. Los suscriptores reciben los mensajes mediante callbacks en lugar de esperar en un bucle. En un microcontrolador, esto significa que el bucle principal sigue leyendo sensores mientras la E/S de red ocurre de forma asíncrona.

Topics: el contrato entre publicadores y suscriptores

Como no hay un vínculo directo entre las partes, la cadena del topic es el único contrato que comparten. Por eso, un buen diseño de topics importa más en MQTT que el diseño de URLs en REST:

  1. Ve de lo general a lo específico: company/site/area/line/device/measurement.
  2. Mantén los niveles estables y con significado para que los comodines sigan siendo útiles.
  3. Nunca pongas secretos ni datos de identificación personal en los nombres de los topics.
  4. No empieces los topics con $; ese prefijo está reservado para topics del broker como $SYS.
  5. Separa los comandos de la telemetría, por ejemplo .../cmd/... frente a .../telemetry/....

El comodín + coincide exactamente con un nivel y # coincide con cualquier número de niveles finales. Un historiador podría suscribirse a acme/#, mientras que un supervisor de línea solo necesita acme/izmir/assembly/line4/+/status.

Pruébalo: dos clientes en broker.connectmq.com

Nada hace que el modelo encaje más rápido que verlo en acción. Instala los clientes de línea de comandos de Mosquitto (mosquitto_pub y mosquitto_sub) y abre dos terminales. Elige un sufijo aleatorio para que tus topics no colisionen con los de nadie más en el servidor MQTT público gratuito. Recuerda que el área pública puede leerla cualquiera, así que no publiques nada sensible: es para pruebas y prototipos, no para datos de producción.

Paso 1: inicia un suscriptor

# Terminal A: suscribirse con un comodín
mosquitto_sub -h broker.connectmq.com -p 1883 -i sub-demo-7f3a \
  -t "connectmq/demo/7f3a/#" -v

Paso 2: publica desde otro cliente

# Terminal B: publicar dos lecturas
mosquitto_pub -h broker.connectmq.com -p 1883 -i pub-demo-7f3a \
  -t "connectmq/demo/7f3a/room1/temperature" -m "21.4"
mosquitto_pub -h broker.connectmq.com -p 1883 -i pub-demo-7f3a \
  -t "connectmq/demo/7f3a/room2/temperature" -m "19.8"

La terminal A imprime ambos mensajes con sus topics. El publicador nunca supo dónde estaba el suscriptor: eso es el desacoplamiento espacial.

Paso 3: demuestra el desacoplamiento temporal con un mensaje retenido

Detén el suscriptor con Ctrl+C. Ahora publica un valor retenido mientras nadie escucha:

mosquitto_pub -h broker.connectmq.com -p 1883 -i pub-demo-7f3a \
  -t "connectmq/demo/7f3a/door/state" -m "open" -r

Vuelve a iniciar el suscriptor. Recibe de inmediato connectmq/demo/7f3a/door/state open aunque el mensaje se envió mientras estaba desconectado. Para limpiar, publica un payload retenido vacío con -r -n.

Paso 4: fan-out

Abre una tercera terminal con otro suscriptor (usa un client ID distinto, como sub2-demo-7f3a). Publica una vez y ambos suscriptores reciben el mensaje. Una publicación, muchas entregas, y el código del publicador no ha cambiado.

Un suscriptor programático en Python

El mismo modelo en código muestra el desacoplamiento de sincronización: el callback se dispara cada vez que llegan datos mientras tu programa sigue libre para hacer otras tareas.

import time
import paho.mqtt.client as mqtt

BROKER = "broker.connectmq.com"
PREFIX = "connectmq/demo/7f3a"

def on_connect(client, userdata, flags, reason_code, properties):
    print("Connected:", reason_code)
    client.subscribe(f"{PREFIX}/#", qos=1)

def on_message(client, userdata, msg):
    print(f"{msg.topic} -> {msg.payload.decode()} (retained={msg.retain})")

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="py-sub-7f3a")
client.on_connect = on_connect
client.on_message = on_message
client.connect(BROKER, 1883, keepalive=60)
client.loop_start()

try:
    while True:
        # Tu aplicación sigue trabajando; los mensajes llegan en segundo plano.
        time.sleep(5)
        client.publish(f"{PREFIX}/heartbeat", str(int(time.time())), qos=1)
except KeyboardInterrupt:
    client.loop_stop()
    client.disconnect()

Por qué pub/sub encaja tan bien con el IoT

  • Enlaces poco fiables. Los dispositivos en redes celulares o Wi-Fi se desconectan con regularidad. Las sesiones persistentes y QoS 1/2 les permiten ponerse al día sin lógica de reintento a medida. La guía de niveles de QoS de MQTT explica en detalle las garantías de entrega.
  • Muchos consumidores por dato. La misma lectura de vibración puede alimentar un panel, un script de alertas y un historiador. Cada uno se suscribe de forma independiente.
  • Conexiones solo salientes. Los dispositivos abren una conexión con el broker; nada necesita conectarse hacia el dispositivo. Eso es mucho más amigable con el NAT y los firewalls que ejecutar un servidor HTTP en cada sensor.
  • Paquetes pequeños. La cabecera fija puede ocupar dos bytes, lo que mantiene bajos el tiempo de radio y el consumo del plan de datos.

Errores habituales y cómo evitarlos

Que no haya suscriptores no es un error. Si publicas en un topic sin suscriptores, el broker lo acepta y lo descarta (salvo que sea retenido). A veces los desarrolladores dan por hecho que un mensaje perdido es un problema de red cuando en realidad es una errata en el topic. Suscríbete a # bajo tu prefijo mientras depuras.

Client IDs duplicados. Dos clientes con el mismo ID se expulsan mutuamente en bucle. Cada conexión necesita un ID único.

Comodines demasiado amplios en producción. Un servicio suscrito a # lo recibe todo, incluido tráfico que no puede gestionar. Acota las suscripciones a los niveles que necesitas.

Esperar respuestas. Pub/sub no tiene respuesta integrada. Si necesitas semántica de petición/respuesta, MQTT 5 añade un response topic y datos de correlación, tratados en nuestra introducción a las funciones de MQTT 5.

Orden entre topics. MQTT conserva el orden por topic para un QoS dado desde un mismo publicador, pero no entre topics distintos. Incluye una marca de tiempo o un número de secuencia en los payloads cuando el orden importe.

De la demo a la producción

El servidor público es perfecto para experimentar, pero es compartido y cualquiera puede leerlo. Para dispositivos reales quieres autenticación, TLS en el puerto 8883 y tu propio espacio de nombres aislado. Un broker MQTT gestionado como ConnectMQ te da exactamente eso: crea un broker en el portal, copia el usuario, la contraseña y el client ID generados y apunta el mismo código al puerto 8883 con TLS. ConnectMQ admite MQTT 3.1.1 y 5.0, así que los retained messages, la caducidad de sesión y las suscripciones compartidas funcionan tal como describe este artículo. Para un recorrido más amplio por el protocolo, empieza con nuestro tutorial completo de MQTT, o lee cómo funciona MQTT a nivel de paquetes.

Empieza con ConnectMQ

¿Listo para llevar tu prototipo pub/sub a un broker privado? Regístrate en app.connectmq.com y crea un broker Serverless gratuito en un par de minutos, sin tarjeta de crédito. El cliente MQTT del navegador y el explorador de topics en vivo de ConnectMQ te permiten observar cómo fluyen las publicaciones y las suscripciones sin instalar nada.

Preguntas frecuentes

¿Es la publicación/suscripción de MQTT lo mismo que una cola de mensajes?

No exactamente. En MQTT, cada suscriptor que coincide recibe su propia copia de cada mensaje, mientras que una cola clásica entrega cada mensaje a un solo consumidor. Las suscripciones compartidas de MQTT 5 añaden un balanceo de carga similar al de una cola cuando lo necesitas.

¿Puede un cliente publicar y suscribirse a la vez?

Sí. Una sola conexión MQTT puede publicar en unos topics y suscribirse a otros; así es como la mayoría de los dispositivos reciben comandos mientras envían telemetría.

¿Qué pasa con los mensajes cuando nadie está suscrito?

El broker los descarta, salvo que el mensaje sea retenido, en cuyo caso se guarda el último valor retenido de cada topic para los futuros suscriptores.

¿Saben los publicadores cuántos suscriptores recibieron un mensaje?

No. En MQTT las confirmaciones son solo entre el cliente y el broker, que es precisamente lo que mantiene desacoplados a publicadores y suscriptores.

Artículos relacionados

¿Quién inventó MQTT? La historia, de los oleoductos al IoT

MQTT lo inventaron en 1999 Andy Stanford-Clark, de IBM, y Arlen Nipper, de Arcom, para monitorizar oleoductos vía satélite. Sigue su camino hacia el open source, OASIS, ISO y los brokers MQTT gestionados en la nube de hoy.

8 min de lectura

Por qué tu cliente MQTT se desconecta constantemente (y cómo solucionarlo)

Los bucles de reconexión son uno de los problemas más habituales de MQTT. Conoce las cinco causas típicas, desde los client ID duplicados hasta los timeouts de keep alive y los paquetes demasiado grandes, y sigue un flujo de diagnóstico que localiza la tuya.

9 min de lectura

Todos los artículos →

Tu broker MQTT privado, a unos pocos clics

Crea una cuenta, obtén las credenciales de tu broker y conecta tu primer dispositivo, sin servidores que instalar, parchear ni escalar.