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 richiedere ulteriori configurazioni. Tuttavia, gli stream WebSocket sono richieste HTTP, che sono comunque soggette al timeout della richiesta configurato per il tuo servizio Cloud Run, quindi devi procedere come segue:
- Aumenta il periodo di timeout della richiesta alla durata massima per cui vuoi mantenere aperto lo stream WebSockets, ad esempio 60 minuti.
- Assicurati che i tuoi client siano in grado di riconnettersi.
- Valuta l'utilizzo dell'affinità di sessione per consentire ai client di riconnettersi il più possibile alla stessa istanza.
- Non attivare HTTP/2 end-to-end.
Sebbene l'affinità di sessione su Cloud Run fornisca un'affinità best effort, le nuove richieste WebSocket potrebbero comunque connettersi a istanze diverse, a causa del bilanciamento del carico integrato. Per risolvere questo problema, devi sincronizzare i dati tra le istanze.
Tieni presente che i WebSocket su Cloud Run sono supportati anche se utilizzi Cloud Load Balancing.
Deployment di un servizio WebSocket di esempio
Utilizza Cloud Shell per eseguire rapidamente il deployment di un servizio di lavagna di esempio che utilizza WebSockets con Cloud Run: Esegui il deployment di un esempio
In alternativa, se vuoi eseguire il deployment del servizio di lavagna di esempio manualmente:
Clona il repository Socket.IO localmente utilizzando lo strumento a riga di comando git:
git clone https://github.com/socketio/socket.io.gitVai alla directory di esempio:
cd socket.io/examples/whiteboard/Esegui il deployment di un nuovo servizio Cloud Run creando il servizio 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 dovrebbe essere propagato all'altra scheda (e viceversa), poiché i client sono connessi alla stessa istanza tramite WebSocket.
Tutorial completo sull'esempio di chat WebSockets
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 scalabilità automatica e della natura stateless delle istanze, nonché dei limiti di concorrenza e timeout delle richieste.
Gestione dei timeout delle richieste e delle riconnessioni dei client
Le richieste WebSocket vengono trattate come richieste HTTP a lunga esecuzione in Cloud Run. Sono soggette a timeout delle richieste (attualmente fino a 60 minuti e per impostazione predefinita 5 minuti) anche se il server dell'applicazione non applica timeout.
Di conseguenza, se il client mantiene la connessione aperta più a lungo del timeout richiesto configurato per il servizio Cloud Run, il client verrà disconnesso quando la richiesta scade.
Pertanto, i client WebSockets che si connettono a Cloud Run devono gestire la riconnessione al server se la richiesta scade o il server si disconnette. Puoi farlo nei client basati su browser utilizzando librerie come reconnecting-websocket o gestendo gli eventi "disconnect" se utilizzi la libreria SocketIO.
Fatturazione per l'utilizzo di WebSocket
Un'istanza Cloud Run con qualsiasi connessione WebSocket aperta è considerata attiva, pertanto la CPU viene allocata e il servizio viene fatturato in base alla fatturazione basata sulle istanze.
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 container), Google consiglia di aumentare l'impostazione di contemporaneità massima per il container a un valore superiore a quello predefinito se il servizio è in grado di gestire il carico con le risorse fornite.
Informazioni sulle sessioni fisse (affinità sessione)
Poiché le connessioni WebSocket sono stateful, il client rimarrà connesso allo stesso container su Cloud Run per tutta la durata della connessione. In questo modo, viene offerta naturalmente una persistenza della sessione nel contesto di una singola connessione WebSocket.
Per connessioni WebSocket multiple e successive, puoi configurare il servizio Cloud Run in modo che utilizzi l'affinità di sessione, ma questo fornisce un'affinità best effort, quindi 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 coordinano o condividono i dati.
Per mitigare questo problema, devi utilizzare un datastore esterno 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 WebSockets.
Ad esempio, supponiamo che tu stia creando un servizio di chat room utilizzando WebSocket e che imposti l'impostazione di concorrenza massima su 1,000. Se più di 1,000 utenti si connettono a questo servizio contemporaneamente, verranno gestiti da istanze diverse e, di conseguenza, non potranno vedere gli stessi messaggi nella stanza virtuale.
Per sincronizzare i dati tra le istanze Cloud Run, ad esempio per ricevere i messaggi pubblicati in una stanza di chat da tutte le istanze, devi utilizzare 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 il polling dal database. Tuttavia, tieni presente che le istanze Cloud Run non hanno CPU quando il container non gestisce richieste. Se il tuo servizio gestisce principalmente richieste WebSockets, al container verrà allocata la CPU finché è presente almeno un client connesso.
Le code di messaggi funzionano meglio per sincronizzare i dati tra i container Cloud Run in tempo reale, perché le code di messaggi esterne non possono indirizzare ogni istanza per eseguire il "push" dei dati. I tuoi servizi devono "eseguire il pull" dei nuovi messaggi dalla coda dei messaggi stabilendo una connessione alla coda dei messaggi.
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 container.
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 i WebSocket, puoi utilizzare il relativo adattatore Redis.
In questa architettura basata su Redis, ogni istanza Cloud Run stabilisce una connessione di lunga durata al canale Redis che contiene i messaggi ricevuti (utilizzando il comando SUBSCRIBE). Una volta che le istanze del container ricevono un nuovo messaggio sul canale, possono inviarlo ai propri client tramite WebSocket in tempo reale.
In modo analogo, quando un client invia un messaggio utilizzando WebSocket, l'istanza che riceve il messaggio lo pubblica sul canale Redis (utilizzando il comando PUBLISH) e le altre istanze iscritte a questo canale riceveranno il messaggio.
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.