Déployer un serveur de websockets sans coupures de service

a marqué ce sujet comme résolu.

Hello tout le monde,

J’ai un projet de jeu où j’utilise un serveur de websockets pour les parties (c’est du temps réel). J’ai pas vraiment de charge et je n’ai pas de problématique à vrai dire car je me vois bien couper le service à minuit pour un déploiement, et "tant pis". Mais quand même, je me posais la question de comment faire bien.

Concrètement, l’histoire simplifiée, c’est 2 dockers:

  1. Le docker qui contient une app front game
  2. Le docker qui contient le serveur server

Mon infra est ridiculesement simple pour le moment, et en même temps pas si mal: j’utilise docker-compose et traefik. Traefik route mon front sur / et mon serveur sur /server.

J’imagine que si je veux faire un déploiement sans coupure, il va falloir que j’ai au moins /server-1 et /server-2 à un moment. Mais je me dis que je ne peux pas être le seul à avoir ce genre de problématique… Du coup me voilà à demander: est-ce que vous avez déjà entendu parler de ce genre de problème ? Des outils pour le résoudre ? (quelque chose dans traefik qui permet de mitiger le soucis ?)

En espérant que vous aurez beaucoup à raconter… :)

Bonne fin de soirée.

Hello, ce que tu cherches à faire c’est du déploiement bleu-vert : en gros tu déploies ta nouvelle version à côté de l’ancienne, et tu y rediriges progressivement le trafic.

Le plus simple est effectivement d’avoir un équilibreur de charge en frontal pour gérer ce trafic, ainsi qu’un orchestrateur pour organiser l’affaire.

Par contre qui dit WebSockets qui application stateful : chaque instance devra être capable de communiquer avec l’ensemble des clients connectés, peu importe leur version de l’application.
Il va donc falloir mettre en place un système de coordination et d’échange de données… comme une base de données, mais en plus rapide/réactif pour ce genre de besoin (surtout que ça implique par mal de lecture/écriture ce genre de choses). Par exemple Redis est souvent utilisé pour ce genre de choses : chaque instance de serveur va pouvoir s’y connecter pour synchroniser une liste de sockets.

Sinon une autre solution est de mettre en place des sticky sessions au niveau de ton load balancer : tant qu’une socket est active, son trafic ici toujours vers la même instance même si d’autres existent. Mais ça implique potentiellement de ralentir la bascule car les clients déjà connectés resteront sur une instance ancienne tant qu’ils sont actifs.
Et même problème si tu veux synchroniser des données entre plusieurs clients/sockets : il va falloir un moyen pour partager/synchroniser ces infos.

Voilà des problèmes que nous avons eus avec @Amaury pour un projet personnel de jeux en ligne. L’architecture retenue ressemble à peu près à ce qu’indique viki53, voici quelques highlights. Je ne connais pas tes besoins spécifiques, donc les éléments que je donne ici sont plus des pistes plutôt que des recommandations.

  • Le nombre d’instances (conteneurs en cours d’exécution) peut être arbitraire car ils sont sans état interne. Dans notre cas, c’est Redis qui sert de « heap » partagée contenant l’état. Son modèle de concurrence permet d’éviter les conflits d’accès et de consistance.
  • Une alternative aux WebSockets permettant d’arriver au même résultat (selon les cas) tout en restant particulièrement "reverse proxy-friendly" (Traefik, HAProxy, NGINX) et "stateless-friendly" : utiliser à la fois les requêtes fetch habituelles pour pousser les données sur le serveur, et en conjonction les requêtes Server-sent events pour recevoir les données du serveur. Les SSE sont des appels HTTP comme les autres, mais ils ont juste la particularité de se maintenir en vie indéfiniment. Sur HTTP/2 et HTTP/3, le tout est multiplexé dans une même connexion TCP (ou QUIC) que le navigateur gère lui-même. D’un point de vue réseau, on ne s’éloigne donc pas du modèle des WebSockets. Mais d’un point de vue développeur, on a conceptuellement des canaux d’envoi et des canaux de réception à gérer en front, et en back on a juste des requêtes « classiques » à gérer. (On part du principe que le backend permet de gérer des connexions long-polling sans épuiser les ressources pour traiter d’autres requêtes concurrentes, avec un modèle async par exemple.)
    D’un point de vue reverse proxy, on a juste des requêtes « normales » à gérer, ce qui là aussi facilite bien des choses. Si toutefois une connexion SSE se ferme, l’API JS est prévue pour tenter automatiquement la reconnexion. Ce cas de figure peut se présenter si le reverse proxy mappait la liaison SSE à une instance venant de mourir, par exemple.
  • un modèle de propagation des données basées sur des streams d’événements : il faut que chaque joueur puisse avoir le même état, mais il y a plusieurs instances sans état et qui peuvent mourir ou spawner sans prévenir ! Redis sert donc de RAM commune, mais à la connexion (ou reconnexion suit à un SSE qui meurt) il faut obtenir les infos qui eussent été perdues dans l’intervalle. Pour cela, on se base sur un stream d’évènements qui permet de retomber sur l’état cohérent final. Pour notifier en temps réels les instances (et, via SSE, les joueurs), la fonction des streams de Redis le fait très bien. Bonus : pour les jeux en ligne, on a parfois envie d’avoir la liste de tous les états intermédiaires. Ce modèle permet aussi d’avoir un journal des actions des joueurs et de rejouer étape par étape une partie.

Merci beaucoup d’avoir pris le temps de me répondre, malheureusement vous n’exposez aucune solution - et pour être honnête - vous ne m’avez rien appris.

J’en retiens que vous ne connaissez pas non plus de solution et que vous ne savez pas non plus si une quelconque feature de traefik pourrait aider. (corrigez moi si j’ai mal lu, n’hésitez pas à réexpliquer)

Je vais probablement me tourner vers une solution "à la mano". Mais si je trouve quelque chose dans le doute je viendrai le poster ici 👍 .

+0 -0

En l’occurrence il n’y a pas de solution puisque tu vas remplacer un serveur par un autre, impliquant donc nécessairement une interruption de service (comme tu n’auras soit qu’un serveur dispo à la fois, soit pas de synchro des WS entre les instances).

Si tu veux éviter que cela se produise à l’avenir tu peux te pencher sur les solutions évoquées pour mettre en place un déploiement bleu-vert.

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte