Development

Registri di comunicazione

Questo sistema archivia tutti i registri da coppie di richiesta/risposta che sono state emesse durante l’elaborazione di qualsiasi messaggio SMS A2P. Di Milan Mimica

December 11 2015

Ambito

La piattaforma di messaggistica di Infobip gestisce circa 250 milioni di transazioni al giorno, ovvero 250 milioni messaggi SMS ricevuti dal cliente, fatturati, instradati, adattati se necessario, inviati a un operatore di telecomunicazioni, elaborati con un rapporto sulla consegna e rinviati al cliente. Si tratta di almeno 6 coppie di richieste e risposte attraverso rete utilizzando diverse API su (a volte) 4 protocolli completamente differenti solo per elaborare un singolo messaggio. Questo se tutto va bene e non sono necessari tentativi. E questo solo per la comunicazione esterna, non stiamo considerando la comunicazione inter-servizio. Inoltre, alcuni messaggi sono correlati, e osservare i messaggi individuali non offre un quadro completo.

La sfida rappresentata dal monitoraggio di tutte quelle operazioni di rete è enorme. Il reparto che si occupa del supporto deve risolvere prontamente sia le richieste del cliente che dell’operatore. Hanno bisogno di uno strumento per sondare tutte le coppie di richiesta/risposta che sono state emesse durante l’elaborazione di qualsiasi messaggio, perché vedere esattamente cos’è stato inviato dal cliente e il modo esatto in cui è stato inoltrato all’operatore, è il punto di partenza per qualsiasi operazione di debugging o problem solving.

Registrazione distributa

Il termine “distribuita” suona bene. È una parola in voga. In qualche modo vogliamo che tutto sia distribuito. Ma vediamo com’è fatto davvero un sistema di registrazione distribuita.

Ciò che abbiamo qui è un servizio separato per ogni protocollo di messaggistica sul lato cliente e sul lato operatore. Ogni servizio gestisce i propri registri, solitamente archiviandoli nella memoria, scrivendoli sul disco in modalità tipo buffer. Poiché i servizi sono sviluppati da team diversi, è necessario un certo sforzo per unicare l’aspetto delle interfacce web per la gestione dei registri. Per rendere un po’ più facile la vita del rappresentante del supporto, i servizi espongono i registri attraverso le proprie API e un’interfaccia di amministrazione centralizzata viene introdotta dove è possibile osservare tutti i registri di tutti i servizi. Rendere tutti i servizi registri push verso un sistema di archiviazione della registrazione come Graylog rappresenta un buon passo verso l’unificazione, e la centralizzazione. Graylog è valido. Scala bene, fa quello che deve fare. Sta sopra a un cluster elasticsearch. Archivia un messaggio di registro con metadati di valore chiave indicizzati. L’interfaccia web è un po’ difficoltosa inizialmente, ma ci si abitua. Dispone anche di pratiche funzioni di analisi.

Il problema è che questi registri non si relazionano. Le 6 coppie di richiesta/risposta sono totalmente non correlati. Serve un’analisi complessa, l’estrazione manuale degli identificatori di correlazione dalla piattaforma di elaborazione interna solo per connettere diversi registri di comunicazione di un singolo messaggio. Per non parlare di trovare registri di comunicazione per messaggi correlati. Questo perché il lato client è disaccoppiato dal lato operatore. Non condividono un singolo identificatore di correlazione.

Inoltre, avendo confini ben definiti tra gli ambiti del servizio, i servizi lato operatore non sanno nulla sul lato cliente e viceversa. Ciò significa che i servizi lato operatore non sanno da quale cliente proviene il messaggio che stanno elaborando. Viene definita separazione delle aree problematiche, e generalmente è una buona cosa. Non funziona bene per la registrazione perché i servizi lato operatore non possono arricchire i registri con alcuni metadati clientId che aiuterebbero a correlare i registri. Inoltre, questi servizi non sanno nulla sulle relazioni del messaggio, perché non ne hanno bisogno. Solo la piattaforma di elaborazione interna lo fa, ma non comunicazione esterna, perciò non produce alcun registro. Significa che i nostri registri non possono avere alcun metadato di relazione associato.

Un modo per risolverlo sarebbe far produrre i registri ai servizi e recuperarli sulla comunicazione interna verso la piattaforma di elaborazione interna. La piattaforma può quindi arricchire i registri con tutti i metadati e spingerli su un’archiviazione di registrazione. Questo funzionerebbe ma sarebbe sbagliato. Sono necessarie preziose risorse di elaborazione e “distrae” la piattaforma dalle proprie mansioni.

Introduzione dell’UUID

Bè, non è nulla di rivoluzionario. Abbiamo immaginato che ogni messaggio avesse bisogno di un ID univoco – UUID (identificatore univoco universale) associato dall’inizio, quando entra nel sistema, e dobbiamo passare questo ID con il messaggio al servizio seguente nella catena di elaborazione. Allora ogni registro di produzione del servizio può applicare questo ID ai metadati del registro. È così semplice! Ora possiamo far relazionare alcuni record di registri a un singolo messaggio. Se solo...

Accoppiamento dei rapporti sulla consegna

Non ci vuole molto per capire che si avrebbe un problema. Basta osservare i registri per vedere che mancano i rapporti sulla consegna. Ancora una volta, il problema è causato dalla separazione delle aree problematiche e, ancora una volta, non vogliamo sabotarla perché concordiamo che sia una buona cosa. I servizi che gestiscono un protocollo specifico possono inviare un messaggio che hanno ricevuto dalla piattaforma e gestire un rapporto sulla consegna. L’abbinamento di un rapporto sulla consegna con un messaggio è un’operazione più complessa di quanto si potrebbe pensare. Si tratta chiaramente di un problema della piattaforma. Vogliamo ancora che il servizio che ha ricevuto il rapporto sulla consegna produca un record di registro per esso, questo è un suo compito. Tuttavia, al momento della ricezione della consegna non si sa ancora a quale messaggio verrà abbinato (se verrà poi davvero abbinato!) quindi il servizio non sa quale UUID applicare al registro.

Mettere in relazione messaggi correlati

Come affermato in precedenza, alcuni messaggi sono correlati. Solitamente, sono messaggi SMS lunghi che vengono trasferiti, ma elaborati e alla fine visualizzati sul telefono cellulare come singolo messaggio. A volte è coinvolta un’operazione di divisione e fusione, perciò abbiamo relazioni di tipo uno a molti, molti a uno, e molti a molti. Sarebbe bello avere anche registri per questi messaggi correlati perché a volte dobbiamo osservare tutti questi messaggi come se fossero uno. Il problema è che solo la piattaforma di elaborazione interna è consapevole della relazione tra questi messaggi, ed è qui che si verifica l’operazione di divisione e fusione. I servizi che gestiscono la comunicazione esterna non sanno nulla di queste relazioni. Gestiscono i messaggi individualmente e ogni messaggio ha il suo proprio UUID.

Un’altra fonte di relazioni è l’elaborazione in massa. Il cliente può semplicemente inviare diversi messaggi in una richiesta HTTP. Il servizio che gestisce l’HTTP alizzerà la richiesta e inoltrerà diversi messaggi nella piattaforma, ma registrerà solo una richiesta e una risposta. Genererà un UUID per registrare la richiesta HTTP e un nuovo UUID per ogni messaggio generato da questa richiesta.

Grafici in soccorso

È chiaro che abbiamo bisogno di archiviare le relazioni tra gli UUID da qualche parte. Dobbiamo essere in grado di recuperare tutti i messaggi correlati quando si recuperano i dati i registri di un singolo messaggio. Proviamo a visualizzare una relazione più complessa, ma non insolita. Abbiamo un invio dal cliente (UUID-100) che contiene due lunghi messaggi (UUID-200 and UUID-210) che successivamente vengono suddivisi in più messaggi e inviati all’operatore (UUID-201, UUID-202, UUID-211, UUID-212). Poi si verifica un’unica consegna in massa, che contiene i rapporti sulla consegna per tutte le parti del messaggio inviate (UUID-300).

Non sorprende che si tratti di un grafico. Sicuramente si potrebbe investire un po’ di tempo e archiviarlo in un database relazionale, o trasformarlo in un json per un database di documenti, ma oggi abbiamo database di grafici. Usiamo lo strumento giusto per questo lavoro! Ovunque si verifica una nuova relazione e si verifica un’operazione di divisione e fusione, immettiamo un piccolo grafico in un database di grafici. Scegliamo Neo4j perché ha un ottimo marketing, sono gentili durante i congressi, regalano libri e magliette. Nemmeno il software è male. Bisogna pagare per il clustering e l’HA, ma per i registri va bene anche la versione gratuita. L’istanza Neo4j singola su una macchina 16 CPU si occupa di 100 milioni di nodi con 150 milioni di relazioni che occupano appena 15GB di memoria. Il problema con Neo4j qui è che l’eliminazione dei nodi non libera memoria o utilizzo del disco, perciò è necessario ripulire i dati di tanto in tanto.

Quando dobbiamo recuperare i registri per un messaggio, prendiamo l’UUID di questo messaggio, recuperiamo tutti gli UUID correlati da Neo4j, poi recuperiamo i registri da Graylog attraverso questi UUID. È importante recuperare solo gli UUID rilevanti, non l’intero grafico. Ad esempio, se vogliamo i registri di comunicazione per il messaggio UUID-200, dobbiamo recuperare solo i record dei registri UUID-100, UUID-200, UUID-201, UUID-202 e UUID-300. Il ramo UUID-21x è irrilevante. Il trucco è utilizzare diversi tipi di relazione quando si collegano I blocchi e quando si collegano le parti del messaggio. Poi viene utilizzata una semplice query con Neo4j cypher per recuperare gli UUID correlati.

Il risultato è che ogni servizio spinge i propri registri della comunicazione che gestisce, Inoltre, la parte del sistema che ha creato una nuova relazione è responsabile della pubblicazione di tale informazione. Le aree problematiche sono ben separate, i registri e le relazioni sono archiviate su sistemi dedicati dove possono essere eventualmente recuperati (di Milan Mimica, Software Engineer / Team Leader),