Fundamentos

Topics y comodines en MQTT: guía de diseño y buenas prácticas

Topics y comodines MQTT explicados: niveles de topic, los comodines + y #, topics $SYS, suscripciones compartidas y buenas prácticas para diseñar tu jerarquía.

Actualizado · 7 min de lectura

En MQTT, el topic es lo único que conecta a publicadores y suscriptores. No hay colas ni exchanges que configurar: el broker simplemente compara el topic de cada mensaje con todos los filtros de suscripción. Eso convierte el diseño de topics en la columna vertebral de tu sistema: determina a qué pueden suscribirse los clientes, cómo se expresan los permisos y lo fácil que será añadir nuevos consumidores más adelante.

Conceptos básicos de los topics

Un nombre de topic es una cadena UTF-8 formada por niveles separados por una barra:

text
building-a/floor-3/room-12/temperature
vehicles/truck-0042/gps
acme/devices/sensor-17/status
  • Los topics distinguen mayúsculas y minúsculas. Home/Kitchen y home/kitchen son topics distintos.
  • No hace falta registrarlos. Un topic existe en el momento en que alguien publica en él.
  • Cada carácter cuenta. Una barra inicial crea un primer nivel vacío, así que /home/kitchen no es lo mismo que home/kitchen. Los espacios son válidos, pero causan confusión sin fin.
  • Tamaño. Los nombres de topic deben tener al menos un carácter y como máximo 65.535 bytes, y no pueden contener el carácter nulo.

Comodines: + y #

Los suscriptores usan filtros de topic, que pueden contener dos comodines. Los publicadores siempre usan nombres de topic concretos: los comodines en un PUBLISH son una violación del protocolo.

Comodín de un nivel: +

+ coincide exactamente con un nivel. Debe ocupar un nivel completo (sensor+ no es válido), pero puede aparecer en cualquier posición y más de una vez.

FiltroCoincide conNo coincide con
home/+/temperaturehome/kitchen/temperaturehome/kitchen/oven/temperature
+/+/statusacme/sensor-17/statusacme/status
home/+home/kitchenhome, home/kitchen/light

Comodín multinivel: #

# coincide con cualquier número de niveles —incluido cero— y debe ser el último carácter del filtro, en su propio nivel. home/# coincide con home/kitchen, home/kitchen/light/state y también con el propio nivel padre home. Filtros como home/#/light o home# no son válidos.

Un # solo te suscribe a todos los topics del broker (excepto los topics $). Es útil para depurar tu propio broker privado, pero en un broker público te inunda con el tráfico de otras personas.

$SYS y otros topics $

Los topics que empiezan por $ están reservados para el broker. El más habitual es $SYS/, donde muchos brokers (Mosquitto, EMQX y otros) publican estadísticas como los clientes conectados, las tasas de mensajes y el uptime. Los topics exactos dependen del broker: la especificación solo reserva el prefijo.

Los comodines en el primer nivel no coinciden con topics $: # y +/monitor nunca entregarán mensajes $SYS/.... Suscríbete de forma explícita:

bash
mosquitto_sub -h test.mosquitto.org -t '$SYS/broker/clients/connected' -v

MQTT 5 añade otro prefijo reservado: las suscripciones compartidas usan $share/<group>/<filter>. Todos los suscriptores del mismo grupo comparten el flujo y cada mensaje va a un único miembro: una forma sencilla de balancear la carga entre consumidores. Consulta MQTT 5 vs 3.1.1 para conocer otras novedades de MQTT 5, como los topic aliases.

Diseñar una jerarquía de topics

Una buena jerarquía va de lo general a lo específico, de modo que los comodines al final seleccionen grupos con sentido. Un patrón habitual es:

text
<org-or-app>/<site>/<device-type>/<device-id>/<measurement-or-channel>

acme/berlin/thermostat/th-0193/temperature
acme/berlin/thermostat/th-0193/setpoint/set
acme/berlin/thermostat/th-0193/status

Con esta estructura:

  • acme/berlin/# da a un dashboard de sede todo lo que ocurre en Berlín.
  • acme/+/thermostat/+/temperature da a un servicio de analítica todas las lecturas de los termostatos.
  • acme/berlin/thermostat/th-0193/# da el flujo completo de un solo dispositivo.

Buenas prácticas

  1. No empieces con una barra. Añade un nivel vacío que no sirve para nada.
  2. Usa minúsculas, ASCII y guiones. Evita espacios y mezclas de mayúsculas y minúsculas: provocan discrepancias sutiles.
  3. Incluye el ID del dispositivo o del cliente en el topic. Facilita el control de acceso por cliente (muchos brokers pueden sustituir el client ID o el nombre de usuario en patrones de ACL).
  4. Separa datos, comandos y estado. Por ejemplo, .../temperature para la telemetría, .../setpoint/set para los comandos y .../status para el estado retenido (retained) o la presencia mediante Last Will.
  5. Mantén los topics cortos pero descriptivos. El topic viaja con cada mensaje (salvo que uses topic aliases de MQTT 5), así que los nombres muy largos consumen ancho de banda en enlaces limitados.
  6. No codifiques datos en el topic. Los valores van en el payload; un topic por valor genera un número ilimitado de topics y montones de mensajes retenidos.
  7. Versiona tu esquema si puede cambiar. Un prefijo como v1/ permite que dispositivos antiguos y nuevos convivan durante una migración.
  8. Evita suscripciones amplias en producción. Suscribirse a # en un servicio de backend convierte cada mensaje del broker en su problema.

Errores habituales con los topics

  • Esperar que a/+ coincida con a. No lo hace: + exige que exista un nivel. Usa a/# si también quieres el nivel padre.
  • Barras finales. home/kitchen/ tiene un último nivel vacío y es un topic distinto de home/kitchen.
  • Suscripciones solapadas. Si un cliente se suscribe a home/# y a home/+/temperature, la especificación permite al broker entregar una sola copia o una copia por cada suscripción que coincida, así que algunos brokers te enviarán duplicados. Mantén las suscripciones disjuntas siempre que puedas.
  • Mezclar formatos de ID. Si algunos dispositivos publican como Sensor_17 y otros como sensor-17, cada filtro y cada regla de ACL tiene que contemplar ambos. Normaliza los IDs al aprovisionar los dispositivos.
  • Tratar los topics como una base de datos. Los brokers están optimizados para enrutar, no para consultar. Si necesitas histórico, haz que un consumidor se suscriba y escriba los mensajes en una base de datos.

Topics y control de acceso

Los brokers autorizan las operaciones de publicación y suscripción por topic, así que tu jerarquía hace también de modelo de permisos. Si cada dispositivo solo escribe bajo acme/<site>/<type>/<device-id>/, puedes concederle exactamente ese subárbol y nada más. Si los topics son planos o inconsistentes, escribir reglas estrictas se vuelve imposible y los equipos acaban concediendo # a todo el mundo.

Pruébalo tú mismo

Abre el cliente MQTT online, suscríbete a testmqtt/demo/+/temperature y publica en testmqtt/demo/kitchen/temperature y en testmqtt/demo/kitchen/oven/temperature. Solo llega el primer mensaje, justo lo que predice la regla de +.

Pruébalo en el cliente MQTT online

Preguntas frecuentes

¿Qué diferencia hay entre + y # en MQTT?

El comodín + coincide exactamente con un nivel del topic y puede aparecer en cualquier parte del filtro. El comodín # coincide con cualquier número de niveles, incluido cero, y debe ser el último carácter del filtro.

¿Puedo publicar en un topic que contenga un comodín?

No. Los comodines solo son válidos en los filtros de suscripción. Un PUBLISH con + o # en el nombre del topic es un error de protocolo y el broker cerrará la conexión.

¿Suscribirse a # incluye los topics $SYS?

No. Los filtros que empiezan por un comodín no coinciden con topics que empiezan por $. Para recibir las estadísticas del broker tienes que suscribirte explícitamente, por ejemplo a $SYS/#.