← Tous les cours / Chat temps réel serverless sur AWS Cours
00 — VUE D'ENSEMBLE

Un chat temps réel, sans serveur

Une messagerie instantanée, ça paraît banal — jusqu'à ce qu'on réalise que le bon vieux « la page demande, le serveur répond » ne tient plus du tout la route. Voyons pourquoi, et ce qu'on met à la place.

Pense à la dernière fois que tu as discuté en ligne. Tu tapes un message, et il apparaît sur l'écran de l'autre presque avant que tu aies relâché la touche Entrée. Cette immédiateté, on la tient pour acquise — mais elle casse complètement le modèle sur lequel repose la plupart des sites web.

Une application web classique fonctionne en question-réponse : ton navigateur demande quelque chose, le serveur répond, et la conversation s'arrête là jusqu'à la prochaine demande. C'est parfait pour afficher une page. Mais dans un chat, le serveur doit pouvoir te parler de lui-même, au moment où un message arrive, sans que tu aies rien demandé. Il faut donc un canal qui reste ouvert dans les deux sens, et un backend qui réagit à des événements plutôt qu'à des requêtes.

Temps réel
Un système où l'information est poussée vers toi à l'instant où elle naît, au lieu d'attendre que tu la réclames. Pour un chat, ça veut dire une connexion persistante et bidirectionnelle : le canal reste branché, et chacun peut parler quand il le souhaite.

On va bâtir ce chat entièrement en serverless, c'est-à-dire sans la moindre machine à administrer. Cinq services AWS se répartissent le travail, et le plus simple est de voir tout de suite à quoi sert chacun :

ServiceSon rôle dans le chat
API Gateway (WebSocket)Tient les connexions ouvertes et achemine chaque message
LambdaLe cerveau : trouve les présents, diffuse, déclenche l'archivage
DynamoDBLa mémoire : qui est en ligne, et tout l'historique des messages
SQSL'amortisseur : encaisse les pics avant l'écriture en base
IAMLe vigile : ouvre aux services les seuls accès dont ils ont besoin

Le cœur de l'affaire se résume à une boucle : un message entre par la porte, le cerveau le redistribue à tout le monde et en range une copie.

Client
API Gateway
Lambda
DynamoDB
💡 Le fil rouge de tout le cours : aucune de ces briques ne tourne « en attente ». Elles s'éveillent sur événement — une connexion qui s'ouvre, un message qui arrive — font leur travail, puis se rendorment. C'est ce qui permet au salon d'absorber un million de participants un soir de match et de ne rien coûter le lendemain matin.

Avant d'ouvrir chaque service, le simulateur ci-dessous montre pourquoi le temps réel change tout. Compare ce qui se passe quand un client doit sans cesse demander « du nouveau ? » et quand le serveur peut simplement pousser le message.

Envoie un message et compare les deux approches :

01 — DYNAMODB

DynamoDB : la mémoire partagée

Un calcul serverless n'a aucune mémoire : il se réveille, s'exécute, et oublie tout. Alors comment savoir, à la milliseconde près, qui est en ligne pour lui transmettre un message ?

Un salon de discussion ne peut pas fonctionner sans mémoire, et c'est là qu'un paradoxe nous attend. Le calcul serverless, par nature, n'a aucune mémoire à lui : il s'éveille, exécute son code, et se rendort en oubliant tout. Or, quand quelqu'un envoie un message, le système doit savoir qui est présent à cette milliseconde précise pour le leur transmettre — et conserver ailleurs la trace durable de la conversation.

Il nous faut donc un cerveau externe, partagé par tous les calculs : quelque chose de très rapide, toujours disponible, et taillé pour des données qui changent en permanence. C'est exactement le terrain de jeu de DynamoDB.

DynamoDB
Une base NoSQL entièrement gérée, conçue pour les charges très sollicitées : elle répond en quelques millisecondes quelle que soit sa taille. Comme elle est managée, on ne provisionne aucun serveur et on ne maintient aucune infrastructure — elle devient la couche de mémoire commune de l'application, sans le poids d'exploiter une base soi-même.

Pour notre chat, on lui confie deux rôles bien distincts, donc deux tables.

TableContientDurée de vie
connexions activesL'identifiant de connexion de chaque personne présenteÉphémère : on ajoute à l'arrivée, on retire au départ
historiqueChaque message envoyéPermanente : c'est l'archive du salon

La première est un tableau de présence qui se remplit et se vide au gré des allées et venues ; la seconde est un grand registre où chaque message s'ajoute pour de bon. Deux usages opposés, une seule technologie.

💡 Capacité on-demand, encore une fois. On configure les deux tables pour qu'elles grandissent toutes seules quand le trafic monte et se rétractent quand le salon se vide. Tu récupères l'élasticité et la performance, et quand personne ne discute, tu ne paies pas une capacité qui dort.

Le simulateur ci-dessous fait vivre les deux tables côte à côte. Fais entrer et sortir des participants, envoie quelques messages, et observe : la table de présence frémit sans cesse, tandis que l'historique ne fait que s'allonger.

Fais entrer des participants et envoie des messages :

02 — FILE SQS

SQS : l'amortisseur du système

Cinq cents personnes écrivent au même instant. Si chaque message file droit dans la base, elle plie sous le choc et le chat devient poussif. Il faut un tampon entre la vitesse et la durée.

On a maintenant où ranger l'historique. Mais écrire en base n'est jamais gratuit : ça prend du temps et ça consomme des ressources. Imagine cinq cents personnes qui appuient sur Entrée au même instant. Si l'application tente d'écrire chaque message directement dans la table d'historique, ce pic soudain d'écritures peut saturer le système — et le salon se met à ramer, avec des messages qui traînent et une impression de lenteur générale.

Le vrai problème, c'est qu'on mélange deux travaux de natures opposées : un travail rapide, diffuser le message en temps réel à ceux qui sont là, et un travail plus lent, l'archiver durablement. Les forcer à avancer au même rythme, c'est laisser le plus lent freiner le plus rapide.

SQS (Simple Queue Service)
Une file de messages entièrement gérée. Imagine une salle d'attente — ou mieux, un amortisseur. Plutôt que d'imposer à l'application une écriture lourde en base sur-le-champ, elle dépose simplement le message dans la file et repart aussitôt servir le salon. La file conserve le message en sécurité et patiente jusqu'à ce qu'un processus de fond soit prêt à le traiter.

Ce geste a un nom, et c'est l'une des idées les plus importantes des systèmes distribués : le découplage. En glissant la file entre la diffusion et l'archivage, on rend les deux indépendants — l'un peut accélérer sans attendre l'autre, et si l'archivage prend du retard, la file absorbe le surplus au lieu de tout bloquer.

Pic de messages
File SQS
Écriture régulière en base
🔑 Ce que la file protège vraiment. Quand un utilisateur envoie un message, l'application en pousse aussitôt une copie dans la file, sans attendre la base ni bloquer la diffusion. Peu importe la vitesse de frappe ou le nombre d'arrivées simultanées : la base est mise à l'abri des rafales, le salon reste vif, et l'historique reste intact.

Une file SQS standard privilégie le débit et la simplicité ; elle ne garantit pas un ordre strict ni l'absence de doublon. Si un jour ton besoin réclame un ordre rigoureux, il existe des files FIFO pour ça — mais pour archiver des messages de chat, la version standard fait parfaitement l'affaire. Le cours Files de messages creuse ces compromis — ordre, doublons, files de lettres mortes — bien au-delà d'AWS.

Le simulateur ci-dessous oppose les deux mondes. Déclenche une rafale et regarde la file gonfler puis se vider à rythme constant, pendant que l'écriture en base reste calme — là où l'écriture directe, elle, explose.

Provoque un pic de trafic et observe l'amortisseur :

03 — IAM & RÔLES

IAM : franchir le mur de sécurité

Par défaut, dans AWS, rien ne se parle. Ton code ne peut ni lire la base, ni écrire dans la file : tout est verrouillé. Reste à ouvrir exactement les bonnes portes — pas une de plus.

La base est prête, la file aussi. Avant d'écrire la moindre ligne de logique, on se cogne pourtant à un mur — et c'est une bonne nouvelle. Par défaut, dans AWS, les services sont totalement isolés les uns des autres. Notre futur code ne peut pas lire dans DynamoDB, ne peut pas déposer dans SQS : tout est verrouillé d'office.

On pourrait débloquer ça à la hache, en collant des clés d'accès directement dans le code. Mauvaise idée : une clé écrite en dur peut fuiter, être exposée, être détournée — et elle ouvre alors bien plus que ce salon de chat. Ce qu'on cherche, c'est l'inverse : accorder à l'application exactement les permissions dont elle a besoin, et rien de plus.

IAM
Le service qui décide qui — et quoi — peut accéder à tes ressources cloud. Pour une application, on ne crée pas un utilisateur avec un mot de passe : on crée un rôle. Pense à un badge de sécurité. Ce n'est pas une personne, c'est un jeu de permissions précis. Quand ton code s'exécute, il porte ce badge le temps d'agir, et n'obtient que l'autorité qu'on y a définie.

Le grand avantage, c'est qu'aucun mot de passe ne traîne dans le code, et qu'il n'y a aucun identifiant durable à gérer : le badge est temporaire par construction. Dans le TP, on crée un rôle dédié à la logique du chat, et on y attache précisément trois permissions.

PermissionPourquoi le chat en a besoin
lire/écrire DynamoDBConnaître les présents et archiver les messages
envoyer vers SQSDéposer une copie du message pour l'archivage différé
pousser via API GatewayRenvoyer le message vers les connexions ouvertes
🔑 Ni plus, ni moins. Cette dernière phrase est tout le principe du moindre privilège : le rôle reçoit ces trois autorisations parce qu'il en a strictement besoin, et surtout pas une de plus. Retire-en une, et c'est tout un pan du chat qui cesse silencieusement de fonctionner — comme tu vas le voir.

Le simulateur ci-dessous met ce principe à l'épreuve. Coupe une permission dans la policy, puis demande au cerveau du chat d'accomplir l'action correspondante : sans le bon droit, l'action échoue net.

Règle la policy du rôle, puis lance une action du chat :

04 — LAMBDA

Lambda : le cerveau qui diffuse

La base se souvient, la file amortit, le rôle autorise. Il manque celui qui décide : quand un message arrive, trouver tous les présents, le leur envoyer, puis en garder une trace.

Les fondations sont posées : la base retient l'état, la file amortit les pics, le rôle ouvre les bonnes portes. Il manque maintenant celui qui orchestre tout ça — le cerveau. C'est lui qui, dès qu'un message arrive, doit trouver toutes les personnes en ligne, l'afficher sur leur écran, et en glisser une copie dans les archives.

On pourrait faire tourner un serveur dédié vingt-quatre heures sur vingt-quatre à guetter les messages. Mais ce serait coûteux, et le faire grossir pendant les pics deviendrait vite un casse-tête. On ne veut pas d'une machine qui veille toute la journée ; on veut du code qui s'éveille uniquement quand il se passe quelque chose, s'exécute dans l'instant, et disparaît une fois le travail fait.

AWS Lambda
Le service de calcul serverless d'AWS. Tu déposes ton code, tu définis un déclencheur, et Lambda s'occupe du reste : il n'exécute ta fonction que lorsqu'un événement survient. Si dix messages arrivent en même temps, AWS lance aussitôt dix copies isolées de ton code, qui traitent chacune leur événement puis s'éteignent. Aucun serveur à gérer, aucune règle de montée en charge à régler.

Pour le chat, on déploie deux fonctions, et toutes deux portent le rôle IAM construit juste avant. Leur séparation n'est pas un détail : c'est elle qui garde la diffusion rapide et l'archivage tranquille.

chat handler — le cerveau principal
Déclenché à chaque message, il interroge la table des connexions pour trouver tous les présents, diffuse le message à chacun, puis dépose une copie dans la file SQS. Son obsession : aller vite.
chat archiver — l'archiviste discret
Déclenché non par l'utilisateur mais par la file SQS, il travaille en arrière-plan : il lit les messages de la file et les écrit dans la table d'historique, à son rythme, sans jamais ralentir la diffusion.

Ce partage des rôles est la clé de voûte de toute l'architecture. La diffusion ne s'occupe que du présent et reste véloce ; l'archivage avance en coulisses ; et la base, alimentée par la file, ne voit jamais passer les rafales.

💡 Diffuser à plusieurs, c'est du « fan-out ». Un message entrant en ressort multiplié : autant de copies envoyées qu'il y a de personnes connectées. Le cerveau lit la liste de présence, puis pousse le message vers chaque connexion, une par une. Plus le salon est rempli, plus le travail de diffusion grandit — et c'est précisément là que la file, en aval, protège l'archivage de cette amplification.

Le simulateur ci-dessous montre le cerveau à l'œuvre. Fais arriver un message : observe-le interroger les présents, se diffuser à chacun, puis filer dans la file vers l'archiviste.

Fais arriver un message et suis le travail du cerveau :

05 — LE RÉSEAU

Le réseau du temps réel

Derrière le mot « WebSocket » se cache une petite bascule réseau. Avant de voir comment AWS nous la sert clé en main, ouvrons le capot : qu'est-ce qui, côté réseau, rend une conversation vraiment instantanée ?

On a un backend complet, fin prêt à diffuser des messages. Mais entre lui et les utilisateurs, il y a le réseau — et c'est lui, au fond, qui décide si une conversation peut être réellement instantanée. Prenons un moment pour comprendre ce qui s'y joue, parce que c'est précisément le problème qu'API Gateway résoudra pour nous à la section suivante.

Le web ordinaire repose sur un échange poli, mais où l'initiative ne va que dans un sens : le client demande, le serveur répond, et tout le monde raccroche. Le serveur n'a aucun moyen de reprendre la parole de lui-même. Pour un chat, c'est rédhibitoire — comment te livrer le message d'un autre si tu n'as rien demandé ?

TCP, le tuyau sous tout le reste
Avant HTTP, avant WebSocket, il y a TCP : une connexion fiable et ordonnée entre deux machines, un tuyau d'octets qui circule dans les deux sens. HTTP comme WebSocket ne sont que deux manières différentes de se servir de ce même tuyau.

Si la plomberie des sockets t'intrigue — comment ce tuyau s'ouvre, se ferme et transporte les octets —, c'est tout l'objet du cours TCP & Sockets.

Le coup de génie de WebSocket, c'est qu'il ne réinvente rien. Une connexion WebSocket commence comme une requête HTTP des plus banales : le client y ajoute simplement un en-tête qui propose « et si on passait en WebSocket ? » (Upgrade: websocket). Si le serveur accepte, il répond par un code de statut un peu spécial — 101 Switching Protocols — et, à partir de cet instant, la même connexion TCP cesse de parler HTTP pour parler WebSocket.

🔑 Le handshake d'upgrade : il n'y a pas deux connexions, mais une seule qui change de langue en cours de route. C'est pour ça qu'un WebSocket franchit sans peine les pare-feux et les proxys qui ne laissent passer que le web : aux yeux du réseau, ça démarre comme du HTTP tout ce qu'il y a de plus normal.

Cette montée en gamme du protocole, depuis le HTTP/1.1 jusqu'à HTTP/2 et HTTP/3, a tout un cours dédié : HTTP · De 1.1 à 3.

Une fois le canal ouvert, on récolte le full-duplex : les deux extrémités peuvent parler et écouter en même temps, sans jamais attendre leur tour.

Simplex, half-duplex, full-duplex
Un mégaphone, c'est du simplex : ça ne va que dans un sens. Un talkie-walkie, c'est du half-duplex : chacun parle à son tour. Un téléphone, c'est du full-duplex : on peut se couper la parole, justement parce que les deux voix passent en même temps. Le WebSocket, c'est le téléphone.

WebSocket n'est d'ailleurs pas la seule façon de faire du temps réel : c'est l'aboutissement d'une petite famille de techniques, chacune un cran moins bricolée que la précédente.

TechniquePrincipeSens
PollingLe client redemande à intervalle fixeClient → serveur, en boucle
Long-pollingLe serveur garde la requête ouverte jusqu'à avoir du neufUne requête par message
SSEUn flux permanent du serveur vers le clientServeur → client seulement
WebSocketUn canal permanent, ouvert dans les deux sensBidirectionnel, full-duplex

Le cousin à sens unique, les Server-Sent Events et le streaming HTTP en général, méritent le détour quand le serveur n'a qu'à pousser sans rien recevoir : le cours Streaming HTTP y est consacré.

Reste la latence, et c'est l'argument décisif. Rouvrir une connexion à chaque message coûte cher : il faut repayer la poignée de main TCP, et le chiffrement par-dessus. Dans un chat où les messages fusent, ces allers-retours répétés se transforment vite en saccades. La connexion persistante du WebSocket, elle, ne paie cette mise en place qu'une seule fois ; ensuite, chaque message file sans cérémonie.

🔒 Et le chiffrement ? En production, tout ce trafic passe en wss:// — du WebSocket par-dessus TLS, exactement comme https:// est du HTTP par-dessus TLS. Le cours TLS/HTTPS explique cette couche de sécurité, valable ici à l'identique.

Une dernière question, qu'on oublie presque toujours : comment une connexion se ferme ? Proprement, comme elle s'ouvre. L'une des deux extrémités envoie une trame de fermeture — un close frame — avec un petit code qui dit pourquoi : 1000 pour une fermeture normale, 1001 quand un serveur s'arrête, 1009 si un message dépasse la taille permise. L'autre côté accuse réception, et le tuyau TCP se démonte. Entre-temps, pour vérifier que le voisin est toujours là, chacun peut envoyer de petites trames ping auxquelles l'autre répond par un pong.

⏱️ La fermeture automatique, côté API Gateway. Une connexion ne reste pas ouverte indéfiniment, et c'est voulu. AWS applique deux limites strictes, non modifiables : si aucun message ne circule pendant 10 minutes, la connexion est coupée pour inactivité ; et de toute façon, aucune connexion ne dépasse 2 heures, active ou non. Pour tenir au-delà des 10 minutes creuses, le client envoie un message d'entretien — un « keepalive » — toutes les quelques minutes ; pour survivre au plafond des 2 heures, pas de secret, il faut se reconnecter.

Voilà le décor réseau planté. La bonne nouvelle, c'est que tu ne géreras rien de tout cela à la main : API Gateway tient les connexions, orchestre le handshake et te livre les événements tout prêts. C'est l'objet de la section suivante.

Le simulateur ci-dessous rejoue l'établissement d'une connexion : la poignée de main TCP, puis la bascule en WebSocket. Une fois le canal ouvert, fais parler le client et le serveur dans n'importe quel ordre — sans jamais rouvrir quoi que ce soit.

Établis la connexion, puis discute dans les deux sens :

06 — API GATEWAY

API Gateway : le standard téléphonique

Tout le backend tourne, mais les utilisateurs restent dehors. Leur faire interroger le serveur en boucle épuiserait la batterie pour rien. Ce qu'il faut, c'est une ligne ouverte en permanence.

Le backend est complet : la base est prête, la file amortit, le cerveau traite. Et pourtant, les utilisateurs restent sur le pas de la porte — ils n'ont encore aucun moyen direct d'atteindre notre logique.

On pourrait leur ouvrir une API HTTP classique. Mais alors, pour savoir s'il y a du nouveau, l'appareil de chacun devrait interroger le serveur sans relâche : « un message ? un message ? un message ? », seconde après seconde. Ça vide les batteries, ça génère un trafic inutile, et ça introduit malgré tout un décalage. Ce qu'il nous faut est d'une autre nature : une seule porte ouverte en permanence, une ligne continue où les messages circulent dans les deux sens, à l'instant.

API WebSocket
Là où le HTTP classique raccroche après chaque échange, une connexion WebSocket reste ouverte et permet une communication bidirectionnelle : les deux extrémités peuvent parler et écouter en même temps. Pense à un appel téléphonique — une fois la ligne établie, personne n'a besoin de recomposer le numéro à chaque phrase.

Toute la mécanique réseau de ce canal — le handshake d'upgrade, le full-duplex, la différence avec le polling — est détaillée juste avant, à la section Le réseau du temps réel. Ici, on se contente de profiter du fait qu'API Gateway s'en charge à notre place.

Dans ce rôle, API Gateway devient le standardiste du système. Il maintient pour nous des milliers de connexions ouvertes, et dès qu'un message arrive sur l'une d'elles, il l'achemine vers notre fonction — sans qu'on ait à gérer le moindre serveur ni la moindre infrastructure de connexion.

Concrètement, on crée une API WebSocket, puis on définit des routes pour les trois moments de la vie d'une connexion :

connexion
·
déconnexion
·
message envoyé

On branche notre chat handler sur ces routes : à chaque événement — quelqu'un se connecte, se déconnecte ou parle — API Gateway déclenche aussitôt notre logique. C'est la dernière pièce, la porte d'entrée publique de toute l'architecture.

🧹 Gare aux connexions fantômes. La route $disconnect est déclenchée au mieux : lors d'une coupure réseau brutale, API Gateway n'a pas toujours l'occasion de la signaler. Ta table des connexions peut donc conserver des entrées mortes. Le réflexe est d'y poser un TTL — une date d'expiration automatique — dans DynamoDB, pour que les connexions oubliées s'effacent d'elles-mêmes.
🔑 Et la sécurité ? Pour tenir les bots à distance, on protège la route de connexion avec une clé d'API et un plan d'usage. Seuls les clients autorisés peuvent ouvrir une ligne, et on plafonne le débit auquel ils envoient des données — exactement le mécanisme décortiqué dans le cours Rate Limiting. Temps réel, oui — mais sous contrôle.

Le simulateur ci-dessous est ce standard téléphonique. Connecte quelques clients, fais-en parler un, et regarde le message remonter jusqu'à la logique avant d'être renvoyé, en un instant, à toutes les lignes ouvertes.

Connecte des clients, puis fais-en parler un :

07 — SYNTHÈSE

Le tableau complet

Cinq services, chacun avec une responsabilité nette. Assemblés, ils forment un système temps réel qui ne dort jamais tout à fait et ne coûte rien quand le salon est vide.

On a posé les pièces une à une ; reculons d'un pas pour voir le tableau complet. Chacune a une responsabilité que tu peux désormais résumer d'une phrase :

ServiceSa responsabilité
API Gateway (WebSocket)Gère les connexions et achemine chaque événement
LambdaTraite les événements : diffuse en direct, déclenche l'archivage
IAMSécurise la communication entre les services
SQSAmortit les pics de trafic avant la base
DynamoDBConserve l'état (qui est en ligne) et l'historique

Le trajet d'un message les fait travailler de concert : il entre par le standard, réveille le cerveau qui le diffuse à tous les présents, et en dépose une copie qui finira tranquillement archivée.

Client
API Gateway
Lambda
SQS
DynamoDB

Ce qui rend ce système solide, ce n'est pas une brique en particulier, mais la manière dont elles sont reliées. La connexion persistante donne l'immédiateté ; le découplage par la file donne la résistance aux rafales ; la séparation des deux fonctions garde la diffusion rapide ; et tout cela monte ou descend en charge tout seul, sans jamais coûter quoi que ce soit quand le salon est désert.

Ce que tu emportes
Tu ne sais pas seulement comment marche un chat. Tu sais comment on architecture un système temps réel dans le cloud : une connexion bidirectionnelle persistante, un état partagé en mémoire rapide, un découplage par file pour encaisser les pics, une logique événementielle qui se réveille à la demande, et une sécurité accordée au plus juste.

La dernière étape ne se lit pas, elle se construit : c'est le capstone. Reprends ces cinq services et câble-les toi-même, de zéro. Parce que lire une architecture, c'est une chose ; la bâtir de ses mains, c'est là qu'on en saisit vraiment l'idée.