Sviluppare applicazioni a disponibilità elevata con il broker MQTT
La creazione di un'applicazione a disponibilità elevata con il broker MQTT prevede un'attenta considerazione dei tipi di sessione, della QoS (qualità del servizio), degli ACK (acknowledgment) dei messaggi, dell'elaborazione parallela dei messaggi, della conservazione dei messaggi e delle sottoscrizioni condivise. Il broker MQTT include un broker di messaggi distribuito e in memoria e un archivio che fornisce la conservazione dei messaggi e la gestione predefinita dello stato con semantica MQTT.
Le sezioni seguenti illustrano le impostazioni e le funzionalità che contribuiscono a un'applicazione affidabile, senza perdita di messaggi e distribuita.
Qualità del servizio (QoS)
Sia i server di pubblicazione che i sottoscrittori dovrebbero usare QoS-1 almeno una volta per garantire la consegna dei messaggi. Il broker MQTT archivia e ritrasmette i messaggi finché non riceve un riconoscimento (ACK) dal destinatario, assicurandosi che non vengano persi messaggi durante la trasmissione.
Tipo di sessione e flag Clean-Session
Per garantire che non si verifichi la perdita di nessun messaggio, è necessario impostare il flag clean-start su false durante la connessione al broker MQTT. Questa impostazione informa il broker di mantenere lo stato della sessione per il client, mantenendo le sottoscrizioni e i messaggi di cui non si è ricevuto l’ACK tra le connessioni. Se il client si disconnette e successivamente si riconnette, riprende da dove aveva interrotto, ricevendo eventuali messaggi QoS-1 di cui non si è ricevuto l’ACK tramite riprova di consegna del messaggio. Se configurato, il broker MQTT fa scadere la sessione del client se questo non si riconnette entro l'Intervallo di scadenza della sessione. L’impostazione predefinita è un giorno.
Receive-Max in applicazioni multithreading
Le applicazioni multithread devono usare il valore receive-max (65.535 max) per elaborare i messaggi in parallelo e applicare il controllo del flusso. Questa impostazione ottimizza l'elaborazione dei messaggi consentendo a più thread di lavorare contemporaneamente sui messaggi e senza che il broker sovraccarichi l'applicazione con una frequenza di messaggi elevata al di sopra della capacità dell'applicazione. Ogni thread può elaborare un messaggio in modo indipendente e inviare il suo ACK dopo il completamento. Una procedura tipica consiste nel configurare il parametro receive-max in modo proporzionale al numero di thread usati dall'applicazione.
ACK dei messaggi
Quando un'applicazione sottoscrittore invia un ACK per un messaggio QoS-1, acquisisce la proprietà del messaggio. Dopo aver ricevuto l’ACK per un messaggio QoS-1, il broker MQTT interrompe la verifica del messaggio di quell'applicazione e argomento. Il trasferimento corretto della proprietà garantisce la conservazione dei messaggi in caso di problemi di elaborazione o arresti anomali dell'applicazione. Se un'applicazione vuole proteggersi dagli arresti anomali, non deve assumere la proprietà prima di completare correttamente l'elaborazione del messaggio. Le applicazioni che sottoscrivono il broker MQTT devono ritardare l’ACK dei messaggi fino al completamento dell'elaborazione fino al valorereceive-max con un massimo di 65.535. Ciò può includere l'inoltro del messaggio o di una sua derivativa al broker MQTT per un ulteriore invio.
Conservazione dei messaggi e comportamento del broker
Il broker mantiene i messaggi fino a quando non riceve un ACK da un sottoscrittore, garantendo che non si verifichi la perdita di nessun messaggio. Questo comportamento garantisce che anche se un'applicazione sottoscrittore si arresta in modo anomalo o perde temporaneamente la connettività, i messaggi non andranno persi e potranno essere elaborati dopo la riconnessione dell'applicazione. I messaggi broker MQTT potrebbero scadere se configurati dal Message-expiry-interval e un sottoscrittore non ha usato il messaggio.
Messaggi non distribuiti
I messaggi non distribuiti mantengono lo stato temporaneo dell'applicazione, ad esempio lo stato o il valore più recente di un argomento specifico. Quando un nuovo client sottoscrive un argomento, riceve l'ultimo messaggio non distribuito, garantendo di disporre delle informazioni più aggiornate.
Keep-Alive
Per garantire la disponibilità elevata in caso di errori o rimozioni di connessione, impostare intervalli keep-alive appropriati per la comunicazione client-server. Durante i periodi di inattività, i client inviano PINGREQs, in attesa di PINGRESPs. In caso di assenza di risposta, implementare la logica di riconnessione automatica nel client per ristabilire le connessioni. La maggior parte dei client come Paho hanno la logica di riprova integrata. Poiché il broker MQTT tollera gli errori, una riconnessione ha esito positivo se sono presenti almeno due istanze di broker integre ovvero una del front-end e una del back-end.
Coerenza finale con la sottoscrizione QoS-1
Le sottoscrizioni MQTT con QoS-1 garantiscono la coerenza finale tra istanze dell'applicazione identiche, sottoscrivendo un argomento condiviso. Quando vengono pubblicati i messaggi, le istanze ricevono e replicano i dati con consegna at-least-once. Le istanze devono gestire duplicati e tollerare incoerenze temporanee fino a quando i dati non vengono sincronizzati.
Sottoscrizioni condivise
Le sottoscrizioni condivise abilitano il bilanciamento del carico tra più istanze di un'applicazione a disponibilità elevata. Anziché ricevere una copia di ogni messaggio ciascuno, i messaggi vengono distribuiti uniformemente tra i sottoscrittori. Il broker MQTT supporta attualmente solo un algoritmo round robin per la distribuzione dei messaggi che consentono a un'applicazione di aumentare il numero di istanze. Un caso d'uso tipico consiste nel distribuire più pod usando Kubernetes ReplicaSet i quali sottoscrivono tutti il broker MQTT usando lo stesso filtro di argomenti nella sottoscrizione condivisa.
Archivio stati
L'archivio stati è un hashmap in memoria replicato per la gestione dello stato di elaborazione dell'applicazione. A differenza di etcd, ad esempio, l'archivio di stato assegna priorità alla velocità effettiva ad alta velocità, alla scalabilità orizzontale e alla bassa latenza tramite strutture di dati in memoria, partizionamento e replica a catena. Consente alle applicazioni di usare la natura distribuita e la tolleranza di errore negli archivi di stato durante l'accesso rapido a uno stato coerente tra istanze. Per usare l'archivio chiave-valore predefinito fornito dal broker distribuito:
Implementare operazioni temporanee di archiviazione e recupero usando l’API dell'archivio chiave-valore del broker, il che garantisce una corretta gestione degli errori e coerenza dei dati. Lo stato temporaneo è un archivio dati di breve durata usato nell'elaborazione con stato per l'accesso rapido a risultati intermedi o metadati durante i calcoli in tempo reale. Nel contesto dell'applicazione a disponibilità elevata, uno stato temporaneo consente di recuperare gli stati dell'applicazione tra un arresto anomalo e l’altro. Può essere scritto su disco, ma rimane temporaneo, al contrario dell'archiviazione offline sicura progettata per l'archiviazione a lungo termine dei dati a cui si accede raramente.
Usare l'archivio stati per condividere lo stato, la memorizzazione nella cache, la configurazione o altri dati essenziali tra più istanze dell'applicazione, consentendo loro di mantenere una visualizzazione coerente dei dati.
Usare l'integrazione predefinita di Dapr del broker MQTT
Per casi d'uso più semplici, un'applicazione potrebbe usare Dapr (Distributed Application Runtime). Dapr è un runtime open source, portabile e basato su eventi il quale semplifica la creazione di microservizi e applicazioni distribuite. Offre un set di blocchi predefiniti, come chiamate da servizio a servizio, gestione dello stato e messaggistica di pubblicazione/sottoscrizione.
Dapr viene offerto come parte del broker MQTT, astraendo i dettagli della gestione delle sessioni MQTT, QoS e ACK dei messaggi e degli archivi chiave-valore integrati, rendendola una scelta pratica per lo sviluppo di un'applicazione a disponibilità elevata per casi d'uso semplici:
Progettare l'applicazione usando i blocchi predefiniti di Dapr, come la gestione dello stato per il controllo dell'archivio chiave-valore e la messaggistica di pubblicazione/sottoscrizione per l'interazione con il broker MQTT. Se il caso d'uso richiede blocchi predefiniti e astrazioni non supportati da Dapr, è consigliabile usare le funzionalità del broker MQTT indicate in precedenza.
Implementare l'applicazione usando il linguaggio di programmazione e il framework preferiti, sfruttando gli SDK o le API Dapr per una perfetta integrazione con il broker e l'archivio chiavi-valore.
Elenco di controllo per sviluppare un'applicazione a disponibilità elevata
- Scegliere una libreria client MQTT appropriata per il linguaggio di programmazione. Il client deve supportare la versione 5 di MQTT. Usare una libreria basata su C o Rust se l'applicazione è suscettibile alla latenza.
- Configurare la libreria client per connettersi al broker MQTT con flag di sessione pulita impostato su
false
e il livello QoS desiderato (QoS-1). - Decidere un valore appropriato per la scadenza della sessione, del messaggio e gli intervalli keep-alive.
- Implementare la logica di elaborazione dei messaggi per l'applicazione sottoscrittore, incluso l'invio di un ACK quando il messaggio è stato recapitato o elaborato correttamente.
- Nelle applicazioni multithread, configurare il parametro receive-max per abilitare l'elaborazione parallela dei messaggi.
- Utilizzare messaggi non distribuiti per mantenere lo stato temporaneo dell'applicazione.
- Usare l'archivio stati distribuito per gestire lo stato temporaneo dell'applicazione.
- Valutare l’uso di Dapr per sviluppare l'applicazione se il caso d'uso è semplice e non richiede un controllo dettagliato sulla connessione MQTT o sulla gestione dei messaggi.
- Implementare sottoscrizioni condivise per distribuire i messaggi in modo uniforme tra più istanze dell'applicazione, consentendo un ridimensionamento efficiente.