Cette page fournit des conseils et des bonnes pratiques pour l'exécution de WebSockets et autres services de streaming sur Cloud Run, et pour l'écriture de clients pour ces services.
Les applications WebSockets sont compatibles avec Cloud Run sans nécessiter aucune configuration supplémentaire. Cependant, les flux WebSockets constituent des requêtes HTTP, qui sont toujours soumises au délai avant expiration des requêtes configuré pour votre service Cloud Run. Vous devez donc vous assurer que ce paramètre fonctionne correctement pour votre utilisation de WebSockets, par exemple en mettant en œuvre un mécanisme de reconnexion dans vos clients.
Même si vous utilisez l'affinité de session sur Cloud Run, qui optimise l'affinité, les requêtes WebSockets peuvent toujours se retrouver sur différentes instances, en raison de l'équilibrage de charge intégré. Pour résoudre ce problème, vous devez synchroniser les données entre les instances.
Notez que WebSockets sur Cloud Run est également compatible si vous utilisez Cloud Load Balancing.
Déployer un exemple de service WebSockets
Utilisez Cloud Shell pour déployer rapidement un exemple de service de tableau blanc utilisant WebSockets avec Cloud Run : Déployer un exemple.
Si vous souhaitez déployer manuellement cet exemple de service de tableau blanc, procédez comme suit :
Clonez le dépôt Socket.IO localement à l'aide de l'outil de ligne de commande git :
git clone https://github.com/socketio/socket.io.git
Accédez au répertoire de l'exemple :
cd socket.io/examples/whiteboard/
Déployez un nouveau service Cloud Run en compilant le service à partir du code source à l'aide de la CLI Google Cloud :
gcloud run deploy whiteboard --allow-unauthenticated --source=.
Une fois le service déployé, ouvrez deux onglets de navigateur distincts et accédez à l'URL du service. Tout ce que vous dessinez dans l'un des onglets doit se propager dans l'autre onglet (et inversement) car les clients sont connectés à la même instance via WebSockets.
Exemple de tutoriel complet sur une application de chat WebSockets
Si vous souhaitez un tutoriel complet sur le code, des exemples de code supplémentaires sont disponibles dans l'article Créer un service WebSocket Chat pour Cloud Run.
Bonnes pratiques
La partie la plus difficile de la création de services WebSockets sur Cloud Run consiste à synchroniser les données entre plusieurs instances Cloud Run. Cette opération est difficile en raison de l'autoscaling et de la nature sans état des instances, ainsi que des limites concernant la simultanéité et les délais avant expiration des requêtes.
Gérer les délais avant expiration des requêtes et les reconnexions des clients
Dans Cloud Run, les requêtes WebSockets sont traitées comme des requêtes HTTP de longue durée. Elles sont soumises à des délais avant expiration des requêtes (actuellement 60 minutes au maximum, et par défaut 5 minutes), même si votre serveur d'application n'applique pas de délais avant expiration.
Ainsi, si le client maintient la connexion ouverte au-delà du délai avant expiration configuré pour le service Cloud Run, il sera déconnecté à l'expiration du délai de la requête.
Par conséquent, les clients WebSockets se connectant à Cloud Run doivent gérer la reconnexion au serveur en cas d'expiration du délai de la requête ou de déconnexion du serveur. Vous pouvez atteindre ce résultat dans les clients basés sur un navigateur en utilisant des bibliothèques telles que reconnecting-websocket ou en gérant des événements "disconnect" si vous utilisez la bibliothèque SocketIO.
Coûts liés à l'utilisation de WebSockets
Une instance Cloud Run contenant au moins une connexion WebSocket ouverte est considérée comme active. Le processeur est donc alloué et facturé.
Optimiser la simultanéité
Les services WebSockets sont généralement conçus pour gérer simultanément plusieurs connexions. Comme Cloud Run autorise les connexions simultanées (jusqu'à 1 000 par conteneur), Google vous recommande d'augmenter le paramètre de simultanéité maximale de votre conteneur afin d'atteindre une valeur supérieure à la valeur par défaut, si votre service est en mesure de gérer la charge avec les ressources dont il dispose.
À propos des sessions persistantes (affinité de session)
Les connexions WebSockets étant "avec état", le client restera connecté au même conteneur sur Cloud Run pendant toute la durée de la connexion. Cela permet naturellement d'assurer la persistance d'une session dans le contexte d'une seule connexion WebSocket.
Pour les connexions WebSocket multiples et ultérieures, vous pouvez configurer votre service Cloud Run pour qu'il utilise l'affinité de session, mais cette affinité est établie de la façon la plus optimale possible : les requêtes WebSockets sont donc toujours susceptibles de se retrouver sur des instances différentes. Il est possible que les clients se connectant à votre service Cloud Run soient traités par des instances différentes qui ne coordonnent ou ne partagent pas les données.
Pour éviter ce problème, vous devez utiliser un stockage de données externe afin de synchroniser l'état entre les instances Cloud Run, comme expliqué dans la section suivante.
Synchroniser les données entre les instances
Vous devez synchroniser les données pour vous assurer que les clients se connectant à un service Cloud Run reçoivent les mêmes données à partir de la connexion WebSockets.
Par exemple, imaginons que vous créiez un service de salon de discussion à l'aide de WebSockets et que vous définissiez votre paramètre de simultanéité maximale sur 1000
. Si plus de 1000
utilisateurs se connectent à ce service simultanément, ils sont répartis dans différentes instances et ne peuvent donc pas voir les mêmes messages dans le salon de discussion.
Pour synchroniser les données entre vos instances Cloud Run, telles que la réception des messages publiés dans un salon de discussion à partir de toutes les instances, vous devez disposer d'un système de stockage de données externe, tel qu'une base de données ou une file d'attente de messages.
Si vous utilisez une base de données externe, par exemple Cloud SQL, vous pouvez envoyer les messages vers la base de données et interroger celle-ci à intervalles réguliers. Cependant, notez que les instances Cloud Run ne disposent pas de processeur lorsque le conteneur ne traite aucune requête. Si votre service gère principalement les requêtes WebSockets, le conteneur se verra allouer une ressource processeur tant qu'il présente au moins un client connecté.
Les files d'attente de messages sont plus efficaces pour synchroniser les données entre les conteneurs Cloud Run en temps réel, car les files d'attente de messages externes ne peuvent pas s'adresser à chaque instance pour demander un "push" (transfert) des données. Vos services doivent extraire ("pull") les nouveaux messages de la file d'attente en établissant une connexion à celle-ci.
Google recommande d'utiliser des systèmes de file d'attente de messages externes tels queRedis Pub/Sub (Memorystore) ou Mises à jour en temps réel Firestore capables de fournir des mises à jour de toutes les instances via des connexions lancées par l'instance de conteneur.
Utiliser Redis Pub/Sub
Vous pouvez utiliser le mécanisme Redis Pub/Sub en créant une instance Redis à partir de Memorystore. Si vous utilisez la bibliothèque Socket.IO pour WebSockets, vous pouvez utiliser son adaptateur Redis.
Dans cette architecture basée sur Redis, chaque instance Cloud Run établit une connexion de longue durée au canal Redis contenant les messages reçus (à l'aide de la commande SUBSCRIBE
). Lorsque les instances de conteneur reçoivent un nouveau message sur le canal, elles peuvent l'envoyer à leurs clients via WebSockets en temps réel.
De même, lorsqu'un client émet un message à l'aide de WebSockets, l'instance qui reçoit le message publie le message sur le canal Redis (à l'aide de la commande PUBLISH
) et les autres instances abonnées à ce canal recevront ce message.
Si vous souhaitez un tutoriel complet sur le code, des exemples de code supplémentaires sont disponibles dans l'article Créer un service WebSocket Chat pour Cloud Run.