Questa pagina fornisce indicazioni e best practice per l'esecuzione di WebSocket o altri servizi di streaming su Cloud Run e per la scrittura di client per questi servizi.
Le applicazioni WebSocket sono supportate su Cloud Run senza alcuna configurazione aggiuntiva. Tuttavia, gli stream WebSocket sono richieste HTTP ancora soggette al timeout della richiesta configurato per il servizio Cloud Run, quindi devi assicurarti che questa impostazione funzioni correttamente per l'utilizzo di WebSocket, ad esempio l'implementazione dei ricollegamenti nei tuoi client.
Anche se utilizzi l'affinità di sessione su Cloud Run, che fornisce un'affinità del tipo "best effort", le richieste WebSocket potrebbero comunque finire in istanze diverse a causa del bilanciamento del carico integrato. Per risolvere il problema, devi sincronizzare i dati tra le istanze.
Tieni presente che WebSocket su Cloud Run sono supportati anche se utilizzi Cloud Load Balancing.
Eseguire il deployment di un servizio WebSocket di esempio
Utilizza Cloud Shell per eseguire rapidamente il deployment di un servizio di lavagna di esempio che utilizza WebSocket con Cloud Run: Esegui il deployment di un esempio
In alternativa, se vuoi eseguire il deployment manuale del servizio della lavagna di esempio:
Clona il repository Socket.IO localmente utilizzando lo strumento a riga di comando git:
git clone https://github.com/socketio/socket.io.git
Vai alla directory di esempio:
cd socket.io/examples/whiteboard/
Esegui il deployment di un nuovo servizio Cloud Run compilandolo dal codice sorgente utilizzando Google Cloud CLI:
gcloud run deploy whiteboard --allow-unauthenticated --source=.
Dopo il deployment del servizio, apri due schede del browser separate e vai all'URL del servizio. Tutto ciò che disegni in una scheda deve essere propagato all'altra scheda (e viceversa) poiché i client sono connessi alla stessa istanza tramite WebSocket.
Tutorial completo sull'esempio di chat WebSocket
Se vuoi una procedura dettagliata completa del codice, sono disponibili altri esempi di codice nell'argomento Tutorial sulla creazione di un servizio di chat WebSocket per Cloud Run.
Best practice
La parte più difficile della creazione di servizi WebSocket su Cloud Run è la sincronizzazione dei dati tra più istanze Cloud Run. Questo è difficile a causa della natura delle istanze di scalabilità automatica e senza stato e dei limiti per la concorrenza e i tempi di attesa delle richieste.
Gestione dei timeout delle richieste e delle ricollegamenti del client
Le richieste WebSocket vengono trattate come richieste HTTP di lunga durata in Cloud Run. Sono soggetti a timeout delle richieste (attualmente fino a 60 minuti e il valore predefinito è 5 minuti) anche se il server delle applicazioni non applica alcun timeout.
Di conseguenza, se il client mantiene la connessione aperta più a lungo del tempo di attesa obbligatorio configurato per il servizio Cloud Run, verrà disconnesso al termine del tempo di attesa della richiesta.
Pertanto, i client WebSocket che si connettono a Cloud Run devono gestire la riconnessione al server se la richiesta scade o se il server si disconnette. Puoi farlo nei client basati su browser utilizzando librerie come reconnecting-websocket o gestindo gli eventi "disconnetti" se utilizzi la libreria SocketIO.
Fatturazione sostenuta durante l'utilizzo di WebSocket
Un'istanza Cloud Run con qualsiasi connessione WebSocket aperta è considerata attiva, pertanto la CPU viene allocata e fatturata.
Massimizzazione della concorrenza
I servizi WebSocket sono in genere progettati per gestire molte connessioni contemporaneamente. Poiché Cloud Run supporta le connessioni simultanee (fino a 1000 per contenitore), Google consiglia di aumentare l'impostazione di concorrenza massima per il contenitore a un valore superiore a quello predefinito se il servizio è in grado di gestire il carico con determinate risorse.
Informazioni sulle sessioni fisse (affinità sessione)
Poiché le connessioni WebSocket sono stateful, il client rimarrà connesso allo stesso contenitore su Cloud Run per tutta la durata della connessione. Ciò offre naturalmente una persistenza della sessione nel contesto di una singola connessione WebSocket.
Per più connessioni WebSocket successive, puoi configurare il servizio Cloud Run in modo da utilizzare l'affinità di sessione, ma questo fornisce un'affinità best effort, pertanto le richieste WebSocket potrebbero comunque finire in istanze diverse. I client che si connettono al tuo servizio Cloud Run potrebbero essere gestiti da istanze diverse che non si coordinano o condividono dati.
Per ovviare a questo problema, devi utilizzare un'area di archiviazione dati esterna per sincronizzare lo stato tra le istanze Cloud Run, come spiegato nella sezione successiva.
Sincronizzazione dei dati tra le istanze
Devi sincronizzare i dati per assicurarti che i client che si connettono a un servizio Cloud Run ricevano gli stessi dati dalla connessione WebSocket.
Ad esempio, supponiamo che tu stia creando un servizio di chatroom utilizzando WebSocket e impostato l'impostazione Contemporaneità massima su 1000
. Se più di 1000
utenti si connettono a questo servizio contemporaneamente, verranno gestiti da istanze diverse e, di conseguenza, non potranno vedere gli stessi
messaggi nella chatroom.
Per sincronizzare i dati tra le istanze Cloud Run, ad esempio per ricevere i messaggi pubblicati in una chatroom da tutte le istanze, è necessario un sistema di archiviazione dei dati esterno, come un database o una coda di messaggi.
Se utilizzi un database esterno come Cloud SQL, puoi inviare messaggi al database ed eseguire periodicamente poll dal database. Tuttavia, tieni presente che le istanze Cloud Run non hanno CPU quando il contenitore non gestisce richieste. Se il tuo servizio gestisce principalmente richieste WebSockets, la CPU verrà allocata al contenitore purché sia collegato almeno un client.
Le code di messaggi funzionano meglio per sincronizzare i dati tra i contenitori Cloud Run in tempo reale, perché le code di messaggi esterne non possono indirizzare ogni istanza per "inviare" i dati. I servizi devono "estrarre" i nuovi messaggi dalla coda dei messaggi stabilendo una connessione alla coda.
Google consiglia di utilizzare sistemi di coda di messaggi esterni come Redis Pub/Sub (Memorystore) o aggiornamenti in tempo reale di Firestore che possono inviare aggiornamenti a tutte le istanze tramite connessioni avviate dall'istanza del contenitore.
Utilizzo di Redis Pub/Sub
Puoi utilizzare il meccanismo Pub/Sub di Redis creando un'istanza Redis da Memorystore. Se utilizzi la libreria Socket.IO per WebSocket, puoi utilizzare l'adattatore redis.
In questa architettura basata su Redis, ogni istanza Cloud Run
stabilisce una connessione a lungo termine con il canale Redis che contiene i
messaggi ricevuti (utilizzando il
comando SUBSCRIBE
). Una volta che le istanze del contenitore ricevono un nuovo messaggio sul canale, possono inviarlo ai propri clienti tramite WebSocket in tempo reale.
Analogamente, quando un client emette un messaggio utilizzando WebSocket, l'istanza che lo riceve lo pubblica nel canale Redis (utilizzando il comando PUBLISH
) e le altre istanze che sono iscritte a questo canale lo riceveranno.
Se vuoi una procedura dettagliata completa del codice, sono disponibili altri esempi di codice nell'argomento Tutorial sulla creazione di un servizio di chat WebSocket per Cloud Run.