Files
games/docs/studies/027-V0_3_5_REALTIME_TRANSPORT_MEASUREMENT.md
2026-09-22 11:38:58 +02:00

6.0 KiB

Étude 0.3.5 — caractérisation bornée WebSocket / WebTransport

Objet

Cette étude définit la méthode de 0.3.5-alpha.10. Elle ne cherche pas à produire un benchmark général de WebSocket contre WebTransport, mais à caractériser les deux implémentations dans games.sasedev, sur loopback, avec le même contrat fiable et des charges bornées.

Les valeurs dépendent de la machine, du kernel, du scheduler, du profil Cargo et de l'état local du système. Elles ne doivent pas être extrapolées à un réseau mobile, à Internet, à un navigateur distant ou à une charge serveur multi-utilisateur.

Outil

Le launcher technique est :

crates/apps/game-realtime-transport-measure

Exécution de référence :

cargo run --release -p game-realtime-transport-measure

Le profil --release est recommandé pour réduire le poids du code de mesure lui-même. La gate peut aussi exécuter le profil debug pour vérifier le fonctionnement, mais les chiffres debug ne doivent pas être comparés à des chiffres release.

Préparation commune

Les deux chemins fiables utilisent leurs configurations produit par défaut et le contrat RealtimeConnection.

WebSocket :

TCP loopback
ws://127.0.0.1:<port>/measure
Tokio + tokio-tungstenite

WebTransport :

UDP loopback
https://127.0.0.1:<port>/measure
QUIC + HTTP/3
certificat P-256 loopback en mémoire
pin SHA-256 exact
stream bidirectionnel primaire

L'outil ne configure ni loss artificiel, ni jitter, ni bandwidth shaping.

Établissement

Pour chaque backend :

samples = 8

WebSocket mesure du début du connect/accept jusqu'à la connexion établie après handshake.

WebTransport mesure jusqu'au chemin fiable utilisable : session WebTransport établie et stream bidirectionnel primaire ouvert/accepté.

Le rapport fournit :

min_us
median_us
p95_us
max_us

Les premières connexions peuvent inclure des coûts froids ; aucun échantillon d'établissement n'est supprimé.

RTT fiable

Charge :

warmup = 16
samples = 128
payload = 32 octets

Le client envoie un message et attend l'écho exact avant d'envoyer le suivant. Seuls les 128 échantillons post-warmup entrent dans le résumé.

Le résultat mesure donc le RTT applicatif du contrat RealtimeConnection, pas le RTT brut TCP/QUIC.

Throughput fiable

Charge :

messages = 128
payload = 64 KiB
volume utile = 8 MiB

Le client envoie les messages sans ACK applicatif intermédiaire. Le serveur draine exactement les 128 messages puis renvoie un ACK final. Le chronomètre client s'arrête à réception de cet ACK.

Le résultat fournit :

elapsed_us
mib_per_s
messages_per_s

Il inclut le framing du backend, les copies/allocation du POC et la backpressure réellement appliquée par les wrappers.

Fenêtre de messages en vol

Charge :

messages = 64
payload = 1 KiB

Le client émet 64 messages sans ACK applicatif intermédiaire, puis attend un ACK unique après drainage côté serveur.

Cette mesure ne prétend pas connaître le nombre exact de paquets réseau simultanément en vol. Elle valide une fenêtre applicative bornée de 64 messages non acquittés individuellement et rapporte son temps de complétion.

Datagram WebTransport

Le datagram est mesuré séparément du contrat fiable :

attempted = 64
payload = min(256, client_max_datagram_size, server_max_datagram_size)

Le client émet les 64 datagrams puis le serveur les reçoit jusqu'à atteindre 64 ou jusqu'à une attente locale de 250 ms sans nouveau datagram.

Le rapport fournit :

attempted
received
receive_ratio
payload_bytes
client_max
server_max
elapsed_us

receive_ratio = 1.0 sur loopback ne transforme pas les datagrams en transport fiable. Une perte observée n'est pas automatiquement un défaut de protocole : elle doit être interprétée avec la sémantique non fiable de WebTransport.

Format de sortie

Chaque mesure utilise une ligne stable :

MEASURE transport=<...> metric=<...> ...

La fin normale est :

CONCLUSION webtransport=retain scope=second-backend reason=reliable-browser-fallback-datagram-capabilities
game-realtime-transport-measure: PASS

Lecture des résultats

Aucun seuil automatique « gagnant/perdant » n'est défini. Une différence loopback de quelques microsecondes ou quelques pourcents n'a pas de valeur produit suffisante à elle seule.

Les dimensions utiles sont :

  • absence d'échec ou de timeout inattendu ;
  • ordre de grandeur de l'établissement ;
  • stabilité médiane/p95 du RTT ;
  • absence d'effondrement évident du throughput fiable ;
  • capacité à soutenir la fenêtre applicative bornée ;
  • observation distincte de la capacité datagram.

Conclusion technique retenue

Décision consolidée pour 0.3.5 : retained.

Cela signifie : conserver WebTransport comme second backend realtime expérimental/évolutif à côté de WebSocket. Cette décision repose sur l'ensemble des preuves 0.3.5 déjà acquises :

  • backend natif fiable ;
  • client navigateur/WASM ;
  • smoke navigateur réel ;
  • robustesse et deadlines ;
  • fallback WebSocket strictement classifié ;
  • datagrams optionnels backend-spécifiques.

Cette conclusion ne signifie pas que WebTransport est déclaré plus rapide que WebSocket. Les runs alpha.10.fix.1 et beta.1 montrent au contraire des avantages différents selon le pattern mesuré : établissement plus coûteux pour WebTransport, RTT local plus faible dans ces runs, throughput 64 KiB supérieur pour WebSocket et fenêtre 1 KiB nettement supérieure pour WebTransport. Ces écarts servent à caractériser les wrappers actuels, pas à produire un classement général.

La validation large a ensuite confirmé le workspace complet, les smokes natifs, le chemin navigateur/WASM réel et la cross-compilation Android ARM64/API 21. Les valeurs exactes des runs validés restent dans history/0.3.5/alpha.10.fix.1.md et history/0.3.5/beta.1.fix.1.md.