Fundamentos de MQTT

Formatos de Payload MQTT: JSON vs Protobuf vs CBOR

O MQTT não se importa com o que há dentro de um payload, então a escolha é sua. Compare JSON, Protobuf e CBOR em tamanho, schemas, depuração e ferramentas, com contagens de bytes para a mesma leitura de sensor.

A mesma leitura de sensor codificada em JSON, Protobuf e CBOR, comparando os tamanhos de cada formato de payload MQTT
Rode isso no seu próprio broker MQTTTenha um broker MQTT privado e gerenciado no plano Free e comece com exemplos de código prontos.
Teste grátis Exemplos de código Sem cartão de crédito

Escolher um formato de payload MQTT é uma das primeiras decisões de design em qualquer projeto de IoT, do sensor de vibração de uma mineradora à bomba de uma estação de saneamento, e uma das mais difíceis de mudar depois. O MQTT trata o payload como bytes opacos, então JSON, Protobuf, CBOR ou um layout binário próprio funcionam igualmente bem na rede. Esta comparação mostra como as três codificações mais comuns diferem em tamanho, gestão de schemas e ferramentas, usando contagens de bytes para a mesma mensagem de sensor, para que você escolha a opção certa para os seus dispositivos.

O MQTT é agnóstico ao payload

Um pacote PUBLISH do MQTT contém um topic, algumas flags, propriedades opcionais do MQTT 5 e um payload de até 256 MB pelo limite do protocolo (na prática, os brokers impõem limites bem menores). O broker MQTT nunca olha dentro do payload. Isso dá liberdade, mas também significa que nada impede duas equipes de publicarem formatos incompatíveis no mesmo topic.

O MQTT 5 adiciona duas propriedades que ajudam:

  • Payload Format Indicator: 0 significa bytes não especificados, 1 significa texto UTF-8.
  • Content Type: uma string livre, normalmente um tipo MIME como application/json ou application/x-protobuf.

Defini-las custa alguns bytes e permite que ferramentas genéricas, loggers e consumidores tratem suas mensagens corretamente.

A mensagem de exemplo

Para uma comparação justa, codificamos a mesma leitura de bomba em cada formato:

{"deviceId":"pump-07","ts":1760600000,"temp":21.5,"pressure":2.31,"rpm":1480,"running":true}

Seis campos: um ID em string, um timestamp Unix, duas medições decimais, um inteiro e um booleano. É um formato realista para telemetria industrial e predial.

Comparação de tamanho

As contagens de bytes abaixo foram calculadas a partir das regras de codificação de cada formato para esta mensagem exata:

Codificação Bytes Observações
JSON formatado (indentação de 2 espaços) 117 Amigável para humanos, desperdício na rede
JSON compacto 92 O padrão mais comum
JSON compacto com chaves curtas 65 {"d":"pump-07","t":1760600000,"tp":21.5,"p":2.31,"r":1480,"on":1}
CBOR, floats de 64 bits 74 Mesmas chaves do JSON, valores binários
CBOR, floats de 32 bits 64 Troca de precisão em pressure
Protobuf, floats como float 30 Números de campo em vez de nomes

Algumas observações:

  • A maior parte do tamanho do JSON vem dos nomes das chaves e do texto dos números. Encurtar as chaves já leva você longe antes mesmo de trocar de formato.
  • O CBOR mantém a estrutura de mapa autodescritiva, então os nomes das chaves continuam viajando em cada mensagem. A economia vem dos números e booleanos binários.
  • O Protobuf é pequeno porque os nomes dos campos ficam em um arquivo de schema, não na mensagem. O receptor precisa ter esse schema.

Lembre-se do cabeçalho MQTT e do topic além do payload. Um topic como site/plant1/line1/pump-07/telemetry tem 35 bytes, mais do que todo o payload Protobuf. Se a largura de banda realmente importa, olhe também para o comprimento do topic e para os topic aliases do MQTT 5, não só para a codificação. Para uma visão mais ampla de para onde vão os bytes, veja o consumo de banda do MQTT.

JSON: o padrão por boas razões

O JSON vence em tudo, exceto no tamanho:

  • Legível em qualquer client MQTT, arquivo de log ou terminal.
  • Toda linguagem e plataforma tem um parser, incluindo o ArduinoJson em microcontroladores.
  • Node-RED, Telegraf, Home Assistant e a maioria dos dashboards o aceitam sem configuração.
  • Adicionar um campo raramente quebra consumidores mais antigos.

Suas fraquezas: nenhuma imposição de schema, tipos numéricos ambíguos (1 é um booleano, um inteiro ou um float?) e custo de parsing em microcontroladores muito pequenos. Para a maioria dos projetos com dispositivos ligados na tomada e Wi-Fi ou Ethernet, essas concessões são aceitáveis.

Protobuf: o menor, com schema

O Protocol Buffers codifica cada campo como um número de campo mais um valor compacto. O schema da nossa mensagem:

syntax = "proto3";

message PumpReading {
  string device_id = 1;
  uint64 ts = 2;
  float temp = 3;
  float pressure = 4;
  uint32 rpm = 5;
  bool running = 6;
}

Pontos fortes: os menores payloads, tipagem forte, código gerado em muitas linguagens e regras bem definidas para evoluir schemas (adicione campos com números novos, nunca reutilize os antigos). O Sparkplug B, amplamente usado no MQTT industrial, é construído sobre Protobuf exatamente por esses motivos; veja MQTT Sparkplug B e o Unified Namespace.

Pontos fracos: ilegível sem o schema, então a depuração exige ferramentas de decodificação; os arquivos de schema precisam ser distribuídos e versionados entre todos os produtores e consumidores; e integrações genéricas não conseguem usar os dados sem uma etapa de decodificação.

CBOR: JSON binário

O CBOR (RFC 8949) mantém o modelo de dados do JSON, com mapas, arrays, strings e números, mas o codifica em binário. Ele não precisa de schema, então qualquer decodificador CBOR consegue transformar uma mensagem de volta em uma estrutura parecida com JSON.

Pontos fortes: menor que o JSON, autodescritivo, byte strings binárias nativas (sem base64) e popular em protocolos restritos como o CoAP. Pontos fracos: a economia é moderada, a menos que você também encurte as chaves, o suporte de ferramentas é mais escasso que o do JSON e a codificação de floats varia entre bibliotecas, o que pode surpreender quando você compara bytes.

Checklist de decisão

  1. Pessoas vão ler essas mensagens com frequência? Prefira JSON.
  2. Os dispositivos estão em rede celular tarifada, backhaul LoRa ou satélite? Considere Protobuf, ou JSON compacto com chaves curtas como primeiro passo.
  3. Muitas equipes e linguagens consumindo os mesmos dados? Os schemas do Protobuf se pagam; caso contrário, JSON com um schema documentado.
  4. Precisa de blobs binários dentro de dados estruturados? O CBOR lida com eles nativamente.
  5. Integração com ferramentas prontas? JSON, ou planeje uma etapa de decodificação que republique em JSON.
  6. Interoperabilidade industrial? Avalie o Sparkplug B antes de inventar seu próprio schema Protobuf.

Seja qual for a escolha, versione o formato. Um campo schema no payload, uma versão no topic ou uma user property do MQTT 5 funcionam; o importante é que os consumidores consigam distinguir os formatos.

Publicando com Content Type em Python

Este exemplo com paho-mqtt 2.x publica a leitura em JSON compacto com o payload format indicator e o content type do MQTT 5 definidos, no servidor MQTT público (gratuito), que serve para testes e protótipos, não para dados de produção:

import json
import uuid
import paho.mqtt.client as mqtt
from paho.mqtt.properties import Properties
from paho.mqtt.packettypes import PacketTypes

reading = {"deviceId": "pump-07", "ts": 1760600000, "temp": 21.5,
           "pressure": 2.31, "rpm": 1480, "running": True}
payload = json.dumps(reading, separators=(",", ":")).encode()
print("payload bytes:", len(payload))  # 92

props = Properties(PacketTypes.PUBLISH)
props.PayloadFormatIndicator = 1
props.ContentType = "application/json"

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2,
                     client_id=f"fmt-{uuid.uuid4().hex[:8]}",
                     protocol=mqtt.MQTTv5)
client.connect("broker.connectmq.com", 1883, keepalive=30)
client.loop_start()
client.publish("connectmq/demo/f6n1/pump-07/telemetry", payload,
               qos=1, properties=props).wait_for_publish()
client.loop_stop()
client.disconnect()

Repare em separators=(",", ":"): o json.dumps padrão do Python adiciona um espaço depois de cada vírgula e de cada dois-pontos, o que deixaria o payload maior que o valor compacto da tabela.

Armadilhas de payload

  • Misturar formatos em um mesmo topic. Os consumidores quebram de formas confusas. Um topic, um formato.
  • Surpresas com ponto flutuante. Floats de 32 bits não representam 2.31 exatamente. Decida a precisão deliberadamente ou envie inteiros escalonados.
  • Timestamps em horário local. Use horário Unix em UTC ou ISO 8601 com offset.
  • Ultrapassar limites de tamanho. Agrupar muitas leituras em uma única mensagem pode atingir o tamanho máximo de mensagem do broker; veja o limite de tamanho de mensagem MQTT.

Formatos de payload no ConnectMQ

O ConnectMQ transporta qualquer formato de payload, já que os payloads MQTT são bytes opacos. Além disso, o ConnectMQ consegue decodificar payloads Sparkplug B (Protobuf ou JSON) e republicá-los em topics ISA-95 legíveis. Os limites de mensagem são de 256 KB no plano Serverless gratuito e de 1 MB no plano Serverless pago, mais do que suficiente para qualquer uma das codificações de leitura única acima. Se você prefere não operar a infraestrutura, um broker MQTT gerenciado permite que você se concentre no contrato do payload. O tutorial de MQTT cobre o restante do protocolo.

Comece a usar o ConnectMQ

Crie um broker gratuito em app.connectmq.com no plano Serverless, sem cartão de crédito. Publique a mesma leitura em JSON e no formato binário de sua preferência e compare os dois lado a lado no client integrado ao navegador do portal ConnectMQ.

Perguntas frequentes

Qual é o melhor formato de payload MQTT?

Não existe um único melhor. O JSON é o padrão mais seguro para interoperabilidade e depuração; o Protobuf é o melhor quando a largura de banda é apertada e os schemas são bem gerenciados.

O broker valida o formato do payload?

Não. Brokers MQTT tratam payloads como bytes opacos. A validação acontece nos seus consumidores.

Devo comprimir payloads JSON?

Para leituras pequenas e individuais, a compressão costuma economizar pouco e custar CPU. Ela ajuda mais em mensagens grandes com lotes de dados.

Como informo aos consumidores qual formato uma mensagem usa?

No MQTT 5, defina a propriedade Content Type. No MQTT 3.1.1, use uma convenção de topic ou um campo de versão dentro do payload.

Artigos relacionados

Por que Seu Cliente MQTT Fica Desconectando (e Como Corrigir)

Loops de reconexão estão entre os problemas mais comuns do MQTT. Conheça as cinco causas habituais, de client IDs duplicados a timeouts de keep alive e pacotes grandes demais, e siga um fluxo de diagnóstico que identifica a sua.

9 min de leitura

Quem Inventou o MQTT? A História dos Oleodutos à IoT

O MQTT foi inventado em 1999 por Andy Stanford-Clark, da IBM, e Arlen Nipper, da Arcom, para monitorar oleodutos via satélite. Acompanhe sua trajetória até o open source, a OASIS, a ISO e os brokers MQTT gerenciados na nuvem de hoje.

8 min de leitura

Todos os artigos →

Seu broker MQTT privado está a poucos cliques de distância

Crie uma conta, receba as credenciais do seu broker e conecte seu primeiro dispositivo — sem servidores para instalar, atualizar ou escalar.