Utiliser WebSockets

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.

Dans Cloud Run, l'affinité de session n'est pas disponible. Par conséquent, les requêtes WebSockets peuvent éventuellement aboutir sur d'autres instances de conteneur, en raison de l'équilibrage de charge intégré. Pour résoudre ce problème, vous devez synchroniser les données entre les instances de conteneur.

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 :

  1. 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
    
  2. Accédez au répertoire de l'exemple :

    cd socket.io/examples/whiteboard/
    
  3. Déployez un nouveau service Cloud Run en compilant le service à partir du code source à l'aide de l'outil de ligne de commande gcloud :

    gcloud beta run deploy whiteboard --allow-unauthenticated --source=.
    
  4. 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 de conteneur via WebSockets.

Exemple de tutoriel complet sur WebSockets Chat

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 de conteneur Cloud Run. Cette opération est difficile en raison de l'autoscaling et de la nature sans état des instances de conteneur, 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 qui comporte au moins une connexion WebSockets ouverte est considérée comme active et est donc facturée.

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.

Toutefois, comme Cloud Run effectue un scaling automatique des instances de conteneur et équilibre la charge de chaque requête entre les instances de conteneur disponibles, il n'offre aucune persistance entre les requêtes. Par conséquent, les requêtes ultérieures émises par un même client feront l'objet d'un équilibrage de charge aléatoire entre les instances de conteneur et peuvent ouvrir WebSockets vers une autre instance de conteneur.

En raison de l'équilibrage de charge entre les instances de conteneur, il est possible que les clients se connectant à votre service Cloud Run soient traités par des instances de conteneur 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 instances de conteneurs

En raison de la nature sans état et de l'autoscaling des instances de conteneur Cloud Run, il se peut que les clients se connectant à un service Cloud Run ne reçoivent pas les mêmes données qu'avec la connexion WebSockets.

Par exemple, si vous créez un service de salon de discussion à l'aide de WebSockets et que vous définissez votre paramètre de simultanéité maximale sur 1000, lorsque plus de 1000 utilisateurs se connectent à ce service simultanément, ils sont répartis dans différentes instances de conteneur et ne peuvent donc pas voir les mêmes messages dans le salon de discussion.

Pour synchroniser les données entre vos instances de conteneur 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é.

L'utilisation de files d'attente de messages est plus efficace 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 de conteneur 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

Architecture du service de salon de discussion WebSockets

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 de conteneur 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 de conteneur qui reçoit le message publie le message sur le canal Redis (à l'aide de la commande PUBLISH) et les autres instances de conteneur 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.