Quali sono le sfide tecniche nella costruzione di una piattaforma di messaggistica in tempo reale?

Costruire una piattaforma di messaggistica in tempo reale su un singolo server è relativamente semplice (vedere progetti come Socket.IO che ottengono questo molto bene). Tuttavia, la creazione di un servizio scalabile a bassa latenza con mesh globale che fornisce messaggi, livello di servizio e garanzie di prestazioni è incredibilmente difficile.

Alla messaggistica in tempo reale Ably, abbiamo trascorso oltre tre anni nella ricerca e sviluppo per costruire una piattaforma globale scalabile e solida, quindi ho delineato alcune delle maggiori sfide che abbiamo affrontato. Spero che altri lo trovino utile.

Integrità dei dati nelle mutevoli condizioni di rete
I server devono esistere vicino ai client, pertanto i server devono essere distribuiti a livello globale per ridurre la latenza di abbonati ed editori. Tuttavia, ciò significa che i dati devono essere replicati tra tutte le regioni che hanno abbonati o editori in tempo reale, ma devono essere resistenti alle mutevoli condizioni della rete. Se un server diventa temporaneamente non disponibile o per un lungo periodo di tempo, secondari e terziari devono subentrare immediatamente per evitare la perdita di dati. Elaborare algoritmi che assicurano che tutti i server si chiacchierino l’un l’altro e concordino un consenso su come assegnare le responsabilità a ciascun server è una sfida.

Continuità attraverso le distribuzioni
I client verranno collegati utilizzando un socket o una connessione simile a un socket per un periodo di tempo prolungato che si estenderà alle distribuzioni sui server. Uno deve essere in grado di distribuire frequentemente nuovo codice senza timore di perdita di dati. Per riuscirci devi risolvere alcuni problemi:

  • Ogni server distribuito deve prendere il posto del vecchio server che sostituisce o idealmente assumere porzioni dell’anello su cui esiste
  • I vecchi server devono chiudere e trasferire con garbo tutto lo stato su nuovi server assumendo ruoli e dati del server corrente
  • A seguito di un arresto regolare del server, tutti i client connessi devono riconnettersi e riprendere lo stato della connessione. Ciò significa che un server che si spegne deve trasferire lo stato in tempo reale su un altro server, quel server deve archiviare tutti i messaggi pubblicati su tutti i canali a cui è stato sottoscritto il client ora disconnesso e quando il client si riconnette, deve recuperare e riprodurre tutti i messaggi al cliente che sono stati pubblicati nel frattempo.
  • La sicurezza deve essere indirizzata per garantire che le connessioni non possano essere dirottate durante le distribuzioni o in qualsiasi altro momento.

Scala illimitata
Semplicemente lanciare più hardware al tuo servizio in tempo reale non risolverà i tuoi problemi di ridimensionamento. Ad esempio, se si disponevano di 100 milioni di abbonati su un canale e viene pubblicato un singolo messaggio, ne verranno pubblicati 100 milioni. Se la tua strategia è quella di avere un singolo server che gestisce un canale responsabile della trasmissione di quel messaggio a tutti i client, la pubblicazione di un singolo messaggio comporterà 100m di bit di lavoro da fare. Indipendentemente dal tuo hardware, questo canale metterà in ginocchio quel canale / server / app. Invece, devi pensare a come il lavoro può essere distribuito in tempo reale attraverso il cluster e smazzato il più possibile mentre lo fai in tempo reale. Pertanto, un modo tipico di affrontare questo problema è aggiungere lavoro a una coda di messaggi e lasciare che tutti gli abbonati raccolgano tale lavoro. Nel contesto dei sistemi in tempo reale, questo spesso non funzionerà abbastanza semplicemente perché un messaggio deve essere recapitato in tempo reale indipendentemente dal numero di messaggi pubblicati, vale a dire 100 milioni di messaggi devono essere consegnati nello stesso lasso di tempo di 1 messaggio. Per farlo, devi pensare molto attentamente al tuo architetto.

Conservazione e resilienza a lungo termine
Se i dati vengono archiviati in un’unica posizione o data center, sono soggetti a perdita di dati o almeno all’interruzione del servizio mentre il database è offline a causa di un errore di rete o hardware. Inoltre, i dati devono essere tenuti vicini a tutti i server di messaggistica in tempo reale a livello globale per garantire che le latenze siano mantenute molto basse. Per fare ciò è necessario assicurarsi di mantenere repliche di dati vicine a tutti i data center per garantire l’accesso al database a bassa latenza, ma anche l’integrità dei dati attraverso guasti hardware o software. La nostra strategia è stata quella di conservare i dati in tre continenti separati con due repliche in ciascuno. Il motivo per cui abbiamo due repliche in ciascuna regione è garantire che la chiusura improvvisa o la manutenzione ordinaria di qualsiasi server non provochino la disattivazione di dati in quella regione che potrebbero influire sulle latenze.

Instradamento intelligente, architettura mesh e nessun singolo punto di congestione
Se un client in Europa si connette al servizio in tempo reale, deve essere instradato al server più vicino disponibile tramite DNS. Ciò garantisce basse latenze al server a cui si connette il client. Tuttavia, se un cliente pubblica un messaggio in Europa e un altro abbonato sta ascoltando messaggi in Europa, allora il messaggio deve essere instradato utilizzando il percorso più breve e non deve mai essere instradato attraverso un singolo punto di congestione. Ciò è importante sia perché mantiene le latenze il più basse possibile, sia garantisce anche che non vi siano punti di congestione o guasti nel sistema.

Browser e supporto di trasporto alternativo
I WebSocket sono un trasporto ideale per una piattaforma di messaggistica in tempo reale, tuttavia non tutti gli ambienti di rete li supportano e non tutti i dispositivi li supportano. Pertanto, è necessario supportare i trasporti di fallback come lo streaming e il polling XHR e per dispositivi ancora più vecchi, a volte il polling JSONP. La difficoltà, tuttavia, non è nel supportare più trasporti, ma nel supportare i cambi di trasporto fornendo al contempo continuità, ad esempio se ti connetti con XHR e successivamente puoi passare a WebSocket, la connessione deve rimanere aperta durante l’aggiornamento e il servizio deve continuare senza alcuna perdita di dati a seguito dell’aggiornamento .

Stato della connessione e continuità
I client, in particolare i dispositivi mobili, verranno continuamente disconnessi a causa delle mutevoli condizioni di rete come entrare in un seminterrato, attraversare un tunnel o passare da 3G a Wifi quando si entra in ufficio. Mentre un client potrebbe semplicemente riconnettersi quando si perde una connessione, ciò comporterebbe una perdita di dati per la durata della disconnessione del client. Pertanto, è indispensabile che il servizio in tempo reale a cui è stato connesso continui a mantenere lo stato di connessione e a iscriversi ai messaggi su tutti i canali a cui era connesso il client mentre il client è disconnesso. Una volta che il client è in grado di riconnettersi, deve dimostrare che era il client originale che utilizzava una chiave segreta, quindi il server deve riprodurre nuovamente tutti i messaggi persi mentre era disconnesso. Senza questa funzione, una piattaforma in tempo reale sarà una fonte di dati inaffidabile.

Sicurezza e autenticazione
Inutile dire che la sicurezza e l’autenticazione sono sempre una priorità assoluta. Dovrai pensare ai modi in cui ai client possono essere emessi token che forniscono loro autorizzazioni granulari nel sistema secondo il principio del privilegio minimo. Tuttavia, è quindi necessario riflettere attentamente su come i clienti possono identificarsi in modo affidabile, ad esempio impedire a un client di mascherarsi come un altro e anche pensare alla revoca del token. La crittografia in transito è indispensabile, tuttavia in alcuni casi è probabilmente necessaria la crittografia end-to-end quando i clienti non possono fidarsi del servizio in tempo reale stesso con payload sensibili. Pertanto, le librerie client dovranno supportare la crittografia con chiavi private mai condivise con il servizio in tempo reale.

Librerie client coerenti e documentazione per le lingue popolari
È probabile che dovrai supportare più piattaforme che abbonano la tua piattaforma in tempo reale. Pertanto, non solo dovrai creare librerie client in tutte le lingue e piattaforme che intendi supportare, ma vorrai mantenere coerenti il ​​comportamento, la funzionalità e la copertura dei test. Abbiamo riscontrato che questo è incredibilmente impegnativo, specialmente quando le specifiche della nostra libreria client hanno oltre 600 requisiti. Le sole librerie client sono incredibilmente difficili da ottenere, insieme alla documentazione delle librerie client.

Gestione e ridimensionamento dell’infrastruttura
L’esecuzione di alcuni server può essere facilmente gestita manualmente, ma se si sta creando una piattaforma di messaggistica in tempo reale, è necessario considerare le implicazioni dell’infrastruttura all’inizio. Pertanto, è necessario considerare:

  • In che modo il tuo servizio aumenterà automaticamente per soddisfare la domanda? Quali metriche / trigger avvierà il ridimensionamento
  • In che modo distribuirai il codice a livello globale assicurando che i rollback possano avvenire senza problemi se le distribuzioni falliscono. Devi assicurarti di avere tutti i server che eseguono lo stesso codice contemporaneamente
  • Riesci a identificare i colli di bottiglia nel sistema? Disponi di strumenti sufficienti a livello globale per vedere quali server, app, client o clienti stanno consumando risorse. Puoi fermarlo?
  • Limitazione e limitazione della velocità sono necessarie per garantire la continuità del servizio ed evitare l’abuso del servizio. Che cos’è l’abuso e che cosa è semplicemente un uso elevato, quale euristica usi per determinarlo in tempo reale?
  • I sistemi autorigeneranti devono rilevare anomalie, registrare i problemi e risolverli automaticamente.

Potrei letteralmente continuare per sempre sui dettagli e le sfide nella costruzione di una piattaforma di messaggistica in tempo reale. In effetti, dopo aver risposto a questa domanda, inizierò a scrivere delle sfide che abbiamo affrontato e continuerò ad affrontare nel nostro blog. Il segreto è che se lo mantieni molto piccolo ed esegui il servizio su un server, probabilmente lo farai facilmente. Se tuttavia hai bisogno di un servizio globale che si ridimensiona, allora è un compito formidabile per ottenere il giusto. Abbiamo avuto 25 persone che lavorano su questo problema per 3 anni e solo recentemente hanno lanciato.

Se qualcuno ha domande specifiche sulle sfide che affrontiamo, sarei felice di elaborare qui o altrove. Sentiti libero di contattarmi.

Esistono vari modi per ottenere aggiornamenti in tempo reale e ognuno ha le proprie sfide:

1- I websocket possono essere limitati a poche cose:
max-connessioni a seconda delle implementazioni del server.
Costo e implementazione dei websocket.

Il problema è che WebSocket è più complesso di HTTP, porta molte cose sul tavolo e aggiunge un altro livello, ma con ciò derivano più dipendenze.

1 / i / Server Sent Events non è una tecnologia in competizione con WS, ma può anche spingere i dati nel browser.

Nel caso WS, può sia inviare e ricevere dati da / dal browser. Ecco perché WS è noto per le applicazioni di chat.

Mentre per le connessioni Server Sent Events, è in grado di eseguire solo il push dei dati nel browser. Ma può ancora essere manipolato per fare lo stesso comportamento.

Cito SSE, perché la sua implementazione può essere più semplice di WebSocket, mentre ha anche i suoi limiti.

Citerò Eric Bidelman di:
Aggiornamenti del flusso con eventi inviati dal server – HTML5 Rocks

Eventi inviati dal server vs. WebSocket

Perché dovresti scegliere Server-Sent Events over WebSocket? Buona domanda.

Uno dei motivi per cui gli SSE sono stati tenuti all’ombra è perché le API successive come WebSocket forniscono un protocollo più ricco per eseguire comunicazioni bidirezionali e full duplex. Avere un canale a due vie è più attraente per cose come giochi, app di messaggistica e per i casi in cui hai bisogno di aggiornamenti quasi in tempo reale in entrambe le direzioni. Tuttavia, in alcuni scenari i dati non devono essere inviati dal client. Hai semplicemente bisogno di aggiornamenti da alcune azioni del server. Alcuni esempi potrebbero essere gli aggiornamenti dello stato degli amici, i ticker delle azioni, i feed di notizie o altri meccanismi automatici di push dei dati (ad esempio l’aggiornamento di un database SQL Web sul lato client o un archivio oggetti IndexedDB). Se devi inviare dati a un server, XMLHttpRequest è sempre un amico.

Gli SSE vengono inviati tramite HTTP tradizionale. Ciò significa che non richiedono un protocollo speciale o un’implementazione del server per funzionare. D’altra parte, i WebSocket richiedono connessioni full duplex e nuovi server Web Socket per gestire il protocollo. Inoltre, gli Eventi Server-Sent hanno una varietà di funzionalità che WebSocket manca in base alla progettazione, come la riconnessione automatica, gli ID evento e la possibilità di inviare eventi arbitrari.

Puoi scegliere SSE su Websocket per:

  • Trasportato su HTTP semplice anziché su un protocollo personalizzato
  • Può essere poli-riempito con javascript per “backport” SSE su browser che non lo supportano ancora.
  • Supporto integrato per ricollegamento e ID evento
  • Protocollo più semplice

Mentre se vai con Websocket su SSE:

  • Tempo reale, comunicazione bidirezionale.
  • Supporto nativo in più browser

E anche questo:

  • % 81 di utenti globali supportano nativamente WebSocket
  • Il 71% degli utenti globali supporta nativamente gli eventi inviati dal server

“È necessario soppesare i due costi (mantenere aperta una connessione anziché stabilire una nuova connessione) per decidere tra i due protocolli.”

2- Quindi hai il polling lungo:
La tolleranza alle prestazioni e ai guasti è il sacrificio e la sfida in questo caso.

Il polling lungo non è di per sé una vera spinta; il polling lungo è una variante della tradizionale tecnica di polling, ma consente di emulare un meccanismo push in circostanze in cui non è possibile effettuare una push reale, ad esempio siti con criteri di sicurezza che richiedono il rifiuto delle richieste HTTP / S in arrivo.

3- DB in memoria:
Soluzioni come Redis possono riprodurre lo stesso comportamento, ma ancora una volta l’implementazione e il costo della disponibilità possono aumentare rapidamente.

    • Ridimensionamento delle app in tempo reale su Cloud Foundry utilizzando Node.js e Redis
    • Creazione di un’applicazione di chat in tempo reale con Socket.io

Puoi dare un’occhiata a PubNub e forse Stephen Blum può dirci di più sulle loro sfide nel loro caso con chat / sistemi in tempo reale.


tl; dr :

  1. Costo
  2. Prestazione
  3. Tolleranza ai guasti
  4. Complessità di soluzioni
  5. Supporto legacy

fonti:

  • Tecnologia push
  • svantaggi dei websocket
  • Aggiornamenti del flusso con eventi inviati dal server – HTML5 Rocks
  • WebSocket vs. eventi server inviati / EventSource

C’è un’API chiamata PySocket
https://github.com/dristic/pysocket
Per questo puoi usare Tornado e Twisted.