Fundamentos

MQTT Keep Alive explicado: PINGREQ, timeouts e ajustes

Como funciona o keep alive do MQTT: a regra do timeout de 1,5x, PINGREQ e PINGRESP, Server Keep Alive do MQTT 5, NAT e redes móveis e como escolher o intervalo.

Atualizado · 7 min de leitura

Conexões TCP podem morrer em silêncio. Um roteador reinicia, um celular troca de antena, uma entrada da tabela NAT expira — e nenhum dos lados recebe um encerramento limpo. O mecanismo de keep alive do MQTT existe para que tanto o cliente quanto o broker percebam uma conexão morta em um tempo previsível, e para que o broker possa publicar a mensagem Last Will do cliente quando isso acontecer. Este artigo explica exatamente como o keep alive funciona no MQTT 3.1.1 e 5, e como escolher um valor adequado à sua rede.

O que é o intervalo de keep alive

O keep alive é um valor de 16 bits, em segundos, que o cliente envia no seu pacote CONNECT. É uma promessa: "Nunca vou ficar em silêncio por mais tempo que isso." O valor máximo é 65535 segundos (pouco mais de 18 horas), e 0 desativa o mecanismo por completo.

O ponto principal é que o timer vale para qualquer pacote de controle, não apenas pings. Um cliente que publica uma leitura de sensor a cada 10 segundos com keep alive de 60 segundos nunca precisa enviar um ping, porque os pacotes PUBLISH já provam que ele está vivo. Pings só são enviados quando o cliente não tem mais nada a dizer.

PINGREQ e PINGRESP

Quando o período de keep alive está prestes a se esgotar sem que o cliente tenha enviado nada, ele envia um PINGREQ. O broker deve responder com um PINGRESP. Os dois pacotes são minúsculos: apenas um cabeçalho fixo de 2 bytes, sem cabeçalho variável e sem payload.

PacoteDireçãoBytes na redeFinalidade
PINGREQCliente → broker0xC0 0x00Prova que o cliente está vivo; pergunta se o broker está vivo
PINGRESPBroker → cliente0xD0 0x00Prova que o broker e o caminho de volta até o cliente funcionam

Dois bytes de MQTT não contam a história toda — TCP/IP, registros TLS e, nos navegadores, o enquadramento WebSocket adicionam overhead a cada ping. Se você está dimensionando um plano de dados celular, a calculadora de tamanho de pacote MQTT ajuda a estimar a parte MQTT de cada pacote para que você some o overhead do transporte.

A regra de 1,5×: quando uma conexão é declarada morta

Os dois lados usam o keep alive de formas diferentes:

  • Lado do broker — se o broker não receber nenhum pacote de controle do cliente dentro de uma vez e meia o período de keep alive, ele deve fechar a conexão de rede como se a rede tivesse falhado. Com keep alive de 60 segundos, isso significa 90 segundos de silêncio.
  • Lado do cliente — se o cliente envia um PINGREQ e não recebe um PINGRESP em um tempo razoável, ele mesmo deve fechar a conexão. As bibliotecas costumam tratar a falta de resposta ao ping até o próximo ciclo de keep alive como falha e começam a reconectar.

Como o broker trata um timeout de keep alive como desconexão anormal, o Last Will do cliente é publicado. É isso que faz funcionar o clássico padrão de "dispositivo offline": defina um will retido offline em devices/42/status, e o broker anuncia a falha em seu nome no máximo 1,5 período de keep alive depois que o dispositivo desaparece.

Server Keep Alive no MQTT 5

No MQTT 3.1.1, o cliente decide o keep alive e o broker precisa aceitá-lo (ou recusar a conexão). O MQTT 5 adiciona a propriedade Server Keep Alive ao CONNACK. Se o broker a incluir, o cliente deve usar o valor do broker em vez do que pediu. Os brokers usam isso para impedir que clientes peçam um keep alive de 0 ou de muitas horas, o que deixaria conexões mortas se acumularem.

O MQTT 5 também torna a falha explícita: antes de fechar, um broker pode enviar um DISCONNECT com o reason code 0x8D (Keep Alive timeout). Você pode consultar esse e todos os outros códigos na referência de reason codes MQTT. Veja MQTT 5 vs 3.1.1 para as outras diferenças do protocolo.

Muitas vezes os brokers também impõem limites do lado do servidor. O Mosquitto, por exemplo, tem a opção max_keepalive: clientes MQTT 5 recebem o valor limitado via Server Keep Alive, enquanto clientes MQTT 3.1.1 que pedem mais podem ser rejeitados.

Configurando o keep alive nos clientes mais comuns

A maioria das bibliotecas usa 60 segundos por padrão. Veja como alterar:

mosquitto_sub
# -k sets the keep alive in seconds
mosquitto_sub -h broker.hivemq.com -t 'testmqtt/ka-demo/#' -k 30 -v
MQTT.js
import mqtt from 'mqtt';

const client = mqtt.connect('wss://broker.hivemq.com:8884/mqtt', {
  keepalive: 30,        // seconds; 0 disables
  reconnectPeriod: 2000 // ms between reconnect attempts
});
Paho MQTT (Python)
import paho.mqtt.client as mqtt

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
client.connect("broker.hivemq.com", 1883, keepalive=30)
client.loop_forever()

Quer o código completo para a sua linguagem? O gerador de código MQTT produz código de conexão com o keep alive já configurado. Para observar o comportamento ao vivo, conecte o cliente MQTT online com um keep alive curto e deixe-o ocioso.

Teste no cliente MQTT online

NAT, firewalls e redes móveis

O keep alive tem uma segunda função que a especificação não menciona: manter os equipamentos intermediários satisfeitos. Gateways NAT, o CGNAT das redes móveis, load balancers e firewalls stateful descartam fluxos TCP ociosos após um timeout. Quando o mapeamento some, o cliente ainda acredita estar conectado, mas nada do que ele envia chega ao broker e nada do que o broker envia chega ao cliente.

  • Fique abaixo do menor idle timeout do caminho. Load balancers em nuvem e operadoras móveis costumam usar idle timeouts de poucos minutos, às vezes menos. Um keep alive com folga abaixo disso mantém o mapeamento ativo.
  • Não dependa do TCP keepalive. Os padrões de TCP keepalive do sistema operacional geralmente são medidos em horas, lentos demais para proteger uma sessão MQTT.
  • Equilibre com a bateria. Cada ping acorda o rádio. Em dispositivos celulares a bateria, intervalos mais longos combinados com uma sessão persistente (para que as mensagens perdidas fiquem na fila) costumam ser o melhor equilíbrio.
  • WebSockets não são exceção. Clientes de navegador atrás de proxies enfrentam os mesmos idle timeouts; o keep alive do MQTT funciona da mesma forma em MQTT sobre WebSockets.

Como escolher um valor de keep alive

CenárioKeep alive sugeridoPor quê
Dashboards e serviços de backend em redes estáveis30–60 sPadrão das bibliotecas, pouco overhead, detecção em cerca de um minuto
Dispositivos em que o "offline" precisa aparecer rápido10–20 sA mensagem will dispara em cerca de 15–30 s
Redes celulares / com muito NATAbaixo do menor idle timeout do caminhoEvita conexões semiabertas silenciosas
Dispositivos a bateria, com envios pouco frequentesVários minutos, ou conectar–publicar–desconectarMenos despertares do rádio; conte com sessões persistentes

Solucionando desconexões por keep alive

Se os clientes se desconectam a cada 1,5× keep alive, a causa mais comum é um loop do cliente que não está rodando — por exemplo, o loop de rede do Paho bloqueado por um trabalho demorado dentro de um callback, de modo que nenhum PINGREQ é enviado. Já reconexões frequentes em um intervalo fixo de alguns minutos apontam para um idle timeout em um proxy ou NAT. Para outras causas, veja o guia de erros de conexão MQTT.

Perguntas frequentes

Qual é um bom intervalo de keep alive no MQTT?

Para a maioria dos dispositivos em redes estáveis, 30 a 60 segundos é um padrão sensato. Use valores menores (15 a 30 segundos) quando precisar detectar clientes mortos rapidamente ou ficar abaixo de um timeout de NAT agressivo, e valores maiores em dispositivos a bateria, em que cada despertar do rádio custa energia.

O que acontece quando o keep alive do MQTT expira?

Se o broker não recebe nenhum pacote de controle do cliente dentro de uma vez e meia o intervalo de keep alive, ele fecha a conexão de rede e a trata como uma desconexão anormal. Isso significa que a mensagem Last Will, se houver, é publicada. No MQTT 5, o broker pode antes enviar um DISCONNECT com o reason code 0x8D (Keep Alive timeout).

Definir o keep alive como 0 o desativa?

Sim. Um keep alive de 0 desliga o mecanismo, e o broker nunca desconecta o cliente por inatividade. Raramente é uma boa ideia, porque conexões TCP semiabertas podem então ficar abertas por muito tempo sem que ninguém perceba.