Desenvolver aplicativos altamente disponíveis com o Agente MQTT
A criação de um aplicativo altamente disponível usando o Agente MQTT envolve uma reflexão cuidadosa sobre os tipos de sessão, a qualidade do serviço (QoS), as confirmações de mensagens, o processamento paralelo de mensagens, a retenção de mensagens e assinaturas compartilhadas. O Agente MQTT apresenta um repositório e um agente de mensagens distribuídos dentro da memória que fornece retenção de mensagens e um gerenciamento de estado integrado com semântica MQTT.
As seções a seguir explicam as configurações e os recursos que contribuem para uma perda de mensagem robusta, zero e um aplicativo distribuído.
Qualidade do serviço (QoS)
Tanto os editores quanto os assinantes devem usar QoS-1 para garantir a entrega de mensagens pelo menos uma vez. O agente MQTT armazena e retransmite mensagens até receber uma confirmação (ACK) do destinatário, garantindo que nenhuma mensagem seja perdida durante a transmissão.
Tipo de sessão e sinalizador de Sessão Limpa
Para garantir uma perda zero de mensagens, defina o sinalizador de início limpo como false quando se conectar ao Agente MQTT. Essa configuração informa ao agente para manter o estado da sessão para o cliente, preservando assinaturas e mensagens não reconhecidas entre conexões. Se o cliente se desconectar e se reconectar posteriormente, ele retomará de onde parou, recebendo mensagens QoS-1 não reconhecidas por meio de nova tentativa de entrega de mensagens. Se estiver configurado, o Agente MQTT fará a sessão do cliente expirar se o cliente não se reconectar dentro do Intervalo de Expiração da Sessão. O padrão é um dia.
Receive-Max em aplicativos multithreaded
Os aplicativos multithreaded devem usar receive-max (65.535 max) para processar mensagens em paralelo e aplicar o controle de fluxo. Essa configuração otimiza o processamento de mensagens permitindo que vários threads funcionem em mensagens simultaneamente e sem que o agente sobrecarregue o aplicativo com uma alta taxa de mensagens acima da capacidade do aplicativo. Cada thread pode processar uma mensagem de forma independente e enviar sua confirmação após a conclusão. Uma prática típica é configurar max-receive proporcionalmente ao número de threads que o aplicativo usa.
Confirmando mensagens
Quando um aplicativo assinante envia uma confirmação para uma mensagem QoS-1, ele assume a propriedade da mensagem. Após receber a confirmação de uma mensagem QoS-1, o Agente MQTT para de acompanhar a mensagem desse aplicativo e tópico. A transferência adequada de propriedade garante a preservação da mensagem em caso de problemas de processamento ou falhas de aplicativo. Se um aplicativo quiser protegê-lo contra falhas de aplicativo, o aplicativo não deverá assumir a propriedade antes de concluir com êxito seu processamento nessa mensagem. Os aplicativos com assinatura do Agente MQTT devem adiar a confirmação de mensagens até que o processamento tenha concluído um valor receive-max, com um máximo de 65.535. Isso pode incluir retransmitir a mensagem ou um derivado da mensagem para o Agente MQTT para uma expedição adicional.
Retenção de mensagens e comportamento do agente
O agente retém mensagens até receber uma confirmação de um assinante, garantindo a perda de mensagens zero. Esse comportamento garante que, mesmo que um aplicativo assinante falhe ou perca a conectividade temporariamente, as mensagens não serão perdidas e poderão ser processadas depois que o aplicativo se reconectar. Se estiverem configuradas, as mensagens do Agente MQTT poderão expirar no Message-Expiry-Interval e se um assinante não consumir a mensagem.
Mensagens retidas
As mensagens retidas mantêm o estado temporário do aplicativo, como o status ou o valor mais recente de um tópico específico. Quando um novo cliente assina um tópico, ele recebe a última mensagem retida, garantindo que ela tenha as informações mais atualizadas.
Keep-Alive
Para garantir a alta disponibilidade em caso de erros de conexão ou quedas, defina intervalos keep-alive adequados para a comunicação cliente-servidor. Durante períodos ociosos, os clientes enviam PINGREQs, aguardando PINGRESPs. Se não houver resposta, implemente a lógica de reconexão automática no cliente para restabelecer conexões. A maioria dos clientes, como Paho, tem lógica de repetição interna. Como o Agente MQTT é tolerante a falhas, uma reconexão será bem-sucedida se houver pelo menos duas instâncias de agente íntegras, um front-end e um back-end.
Consistência eventual com a assinatura do QoS-1
As assinaturas MQTT com QoS-1 garantem uma consistência eventual em instâncias de aplicativo idênticas assinando um tópico compartilhado. À medida que as mensagens são publicadas, as instâncias recebem e replicam dados com entrega pelo menos uma vez. As instâncias devem lidar com duplicatas e tolerar inconsistências temporárias até que os dados sejam sincronizados.
Assinaturas compartilhadas
As assinaturas compartilhadas permitem o balanceamento de carga em várias instâncias de um aplicativo altamente disponível. Em vez de cada assinante receber uma cópia de cada mensagem, as mensagens são distribuídas uniformemente entre os assinantes. Atualmente, o Agente MQTT dá suporte apenas a um algoritmo round-robin para distribuir mensagens que permitem que um aplicativo seja expandido. Um caso de uso típico é implantar vários pods usando o ReplicaSet do Kubernetes em que todos assinam o Agente MQTT usando o mesmo filtro de tópico na assinatura compartilhada.
Armazenamento de estado
O repositório de estado é um HashMap replicado na memória para gerenciar o estado de processamento do aplicativo. Ao contrário do etcd, por exemplo, o armazenamento de estado prioriza a taxa de transferência de alta velocidade, o escalonamento horizontal e a baixa latência por meio de estruturas de dados na memória, particionamento e replicação em cadeia. Ele permite que os aplicativos usem a natureza distribuída do estado e a tolerância a falhas ao acessar rapidamente um estado consistente entre instâncias. Para usar o repositório de chave-valor interno fornecido pelo agente distribuído:
Implemente operações de armazenamento e recuperação efêmeras usando a API do repositório chave-valor do agente, garantindo o tratamento de erros e a consistência de dados adequados. O estado efêmero é um armazenamento de dados de curta duração usado no processamento com estado para acesso rápido a resultados intermediários ou metadados durante cálculos em tempo real. No contexto do aplicativo de HA, um estado efêmero ajuda a recuperar os estados do aplicativo entre falhas. Ele pode ser gravado em disco, mas permanece temporário, em oposição ao armazenamento frio projetado para armazenamento de longo prazo de dados acessados com pouca frequência.
Use o repositório de estado para compartilhar estado, cache, configuração ou outros dados essenciais entre várias instâncias do aplicativo, permitindo que elas mantenham uma exibição consistente dos dados.
Usar a integração do Dapr integrada do Agente MQTT
Para casos de uso mais simples, um aplicativo pode utilizar Dapr (Distributed Application Runtime). O Dapr é um runtime de software livre, portátil e controlado por eventos que simplifica a criação de microsserviços e aplicativos distribuídos. Ele oferece um conjunto de blocos de construção, como invocação serviço a serviço, gerenciamento de estado e mensagens de publicação/assinatura.
O Dapr é oferecido como parte do Agente MQTT, abstraindo detalhes do gerenciamento de sessão do MQTT, do QoS e confirmação de mensagens e dos repositórios de chave-valor integrados, o que o torna uma opção prática para desenvolver um aplicativo altamente disponível para casos de uso simples ao fazer o seguinte:
Projete seu aplicativo usando os blocos de construção da Dapr, como o gerenciamento de estado para lidar com o repositório de chave-valor e as mensagens de publicação/assinatura para interagir com o agente MQTT. Se o caso de uso requerer componentes e abstrações que não sejam compatíveis com o Dapr, pense em usar os recursos do Agente MQTT mencionados anteriormente.
Implemente o aplicativo usando sua linguagem e estrutura de programação preferidas, aproveitando SDKs de Dapr ou APIs para integração perfeita com o agente e o repositório de chave-valor.
Lista de verificação para desenvolver um aplicativo altamente disponível
- Escolha uma biblioteca de clientes MQTT apropriada para sua linguagem de programação. O cliente deve dar suporte ao MQTT v5. Use uma biblioteca baseada em C ou Rust se o aplicativo estiver sensível à latência.
- Configure a biblioteca de clientes para se conectar ao agente MQTT com um sinalizador clean-session definido como
false
e o nível de QoS desejado (QoS-1). - Decida um valor adequado para expiração da sessão, expiração da mensagem e intervalos de keep-alive.
- Implemente a lógica de processamento de mensagens para o aplicativo assinante, incluindo o envio de uma confirmação quando a mensagem tiver sido entregue ou processada com êxito.
- Para aplicativos multithreaded, configure o parâmetro max-receive para habilitar o processamento de mensagens paralelas.
- Utilize mensagens retidas para manter o estado do aplicativo temporário.
- Utilize o repositório de estado distribuído para gerenciar o estado do aplicativo efêmero.
- Avalie o Dapr para desenvolver seu aplicativo se o caso de uso for simples e não exigir controle detalhado sobre a conexão MQTT ou o tratamento de mensagens.
- Implemente assinaturas compartilhadas para distribuir mensagens uniformemente entre várias instâncias do aplicativo, permitindo dimensionamento eficiente.