Retour au Blog

Pourquoi les modes créatifs subissent un ping deux fois plus élevé : correctifs architecturaux pour la multiplayer game server ping optimization

Publié le 5 juillet 2026
Pourquoi les modes créatifs subissent un ping deux fois plus élevé : correctifs architecturaux pour la multiplayer game server ping optimization

En bref

Cet article analyse les causes de la hausse de latence spécifique aux modes créatifs et sandbox par rapport au matchmaking classique. Il détaille l'impact de la baisse du tick rate sur le RTT perçu, les problèmes de fragmentation UDP liés à l'UGC, ainsi que les limites du routage unicast. Des solutions d'architecture concrètes, incluant la replication interleaving, l'orchestration de conteneurs dynamiques et le routage edge Anycast, sont présentées pour y remédier. Enfin, l'utilisation de la plateforme horizOn est abordée comme solution clé en main pour éliminer les cold starts et optimiser le trafic multiplayer.

Votre file d'attente principale de matchmaking en battle royale tourne à un ping impeccable de moins de 30 ms, mais dès que les joueurs rejoignent une session créative générée par l'utilisateur, leur latence double pour atteindre 60 ms ou plus. Cette « pénalité de latence du mode créatif » est un problème bien connu des studios qui sortent des jeux sandbox, et pourtant elle reste mal comprise. Elle découle directement de la dynamic server orchestration, du chargement dynamique d'assets et d'un routage régional sous-optimal. Pour y remédier, les développeurs doivent abandonner les architectures de matchmaking statiques au profit de stratégies modernes de multiplayer game server ping optimization.

Pourquoi les modes créatifs subissent une pénalité de latence

Dans les matchs multiplayer standards, les serveurs de jeu sont pre-warmed et regroupés dans des data centers régionaux de premier plan. Ces serveurs font tourner des maps de jeu optimisées et en lecture seule qui nécessitent un minimum d'initialisation d'actors dynamique ou de réplication d'assets. Les algorithmes de matchmaking attendent de regrouper des joueurs de régions similaires afin de s'assurer que le serveur sélectionné est physiquement proche de tout le monde dans le lobby.

Les modes créatifs et sandbox brisent complètement ce paradigme. Au lieu d'utiliser des serveurs pre-warmed, ces modes déploient à la demande des instances de conteneurs dédiées (dedicated container instances) dès qu'un chef de groupe (party leader) lance une session. Comme ces instances démarrent dynamiquement, l'orchestrateur est contraint de privilégier la disponibilité des serveurs par rapport à la latence réseau.

Si le data center principal le plus proche tourne à pleine capacité, la couche d'orchestration va rediriger la session vers une zone de disponibilité secondaire ou vers une région plus éloignée et moins coûteuse. Ce basculement dynamique ajoute instantanément 20 à 40 ms de temps de transit par fibre optique à la connexion du joueur. De plus, les environnements sandbox permettent aux joueurs de concevoir des niveaux personnalisés avec des milliers d'objets dynamiques, des scripts customisés et des appareils interactifs. Ces objets provoquent un overhead de réplication massif, ce qui ralentit le main thread du serveur et fait chuter son tick rate.

L'impact de la dégradation du tick rate sur la latence perçue

Lorsque le frame rate d'un serveur chute, la boucle de réplication réseau ralentit également. Si un serveur cible un tick rate de 30 Hz, le frame time attendu est de 33,3 ms. Si un client envoie un paquet qui arrive juste après que le serveur a commencé à exécuter son tick, ce paquet doit stagner dans le buffer réseau jusqu'au début du tick suivant.

Si des scripts sandbox non optimisés font chuter le tick rate du serveur de 30 Hz à 15 Hz, le frame time grimpe à 66,6 ms. Ce délai de traitement (processing delay) ajoute automatiquement 33,3 ms au round-trip time (RTT) du client. L'interface réseau en jeu du client enregistre ce délai de traitement local comme du ping réseau, alors même que la latence physique sur la fibre reste inchangée.

De plus, le streaming dynamique de contenu généré par les utilisateurs (UGC) force le serveur à sérialiser et à envoyer des payloads massifs aux joueurs qui rejoignent la partie. Ce pic de trafic réseau provoque du bufferbloat sur les routeurs domestiques et les interfaces réseau, ce qui entraîne une mise en file d'attente des paquets (packet queuing). Lorsque les paquets attendent dans une file d'attente, la latence s'envole et la perte de paquets (packet loss) augmente.

Lorsque des scripts UGC non optimisés surchargent le CPU, les chutes de tick rate peuvent dégénérer en freezes complets du serveur. Si vous subissez des pics de latence massifs sous charge, consultez notre protocole de résolution des crashs de serveur pour stabiliser votre netcode.

Le rôle du MTU et de la fragmentation des paquets lors du chargement de l'UGC

Lorsque les joueurs se connectent sur une map sandbox personnalisée, le serveur doit répliquer l'état de centaines d'actors personnalisés. Cette synchronisation d'état dépasse souvent la taille standard de la Maximum Transmission Unit (MTU) qui est de 1500 octets. Lorsque les paquets UDP dépassent cette limite, la couche réseau doit les fragmenter en plusieurs paquets IP plus petits.

Si ne serait-ce qu'un seul fragment est perdu en cours de route, la pile réseau (network stack) du client rejette l'intégralité du paquet UDP. Cela déclenche une retransmission des paquets (packet retransmission), provoquant un jitter important et des pics de ping pour le joueur. Comme les maps créatives contiennent des configurations très dynamiques, cette fragmentation se produit beaucoup plus fréquemment que lors de sessions de battle royale statiques.

Pour atténuer ce phénomène, les développeurs devraient implémenter des techniques de sérialisation personnalisées afin de compacter les données des actors. En maintenant les payloads de réplication sous le seuil des 1200 octets, vous pouvez éviter totalement la fragmentation IP. Ce simple changement stabilise les chemins de transit réseau et améliore considérablement la qualité de la connexion.

Le fonctionnement du dynamic server routing et des cold starts

Le routage IP standard repose sur des configurations de chemin statiques qui fonctionnent bien pour des serveurs aux emplacements fixes. Mais lorsque des instances de serveurs sont instanciées dynamiquement à travers un cloud distribué, le routage IP unicast standard ne parvient pas à choisir le chemin offrant la plus faible latence. Un joueur qui lance une session créative obtient une IP unicast dynamique liée à un nœud de conteneur (container node) fraîchement créé.

Comme cette IP est temporaire, elle ne peut pas bénéficier du routage Anycast global. Au lieu de cela, les paquets du joueur doivent transiter par l'internet public, en passant par plusieurs fournisseurs de transit non optimisés et des sauts de routage (routing hops) de FAI locaux. Cela contraste fortement avec les files d'attente de matchmaking principales, qui dirigent les joueurs via un proxy edge compatible Anycast.

Ces proxies terminent les connexions des clients au Point of Presence (PoP) le plus proche et acheminent les données via un tunnel à travers des backbones privés directement vers le game server. Le provisionnement dynamique introduit également des cold starts. Si un conteneur de serveur met trop de temps à démarrer, les joueurs risquent de rencontrer des échecs de connexion. Pour corriger cela, vous devez comprendre comment diagnostiquer les problèmes de driver et de timeout de connexion, comme détaillé dans notre guide sur la résolution des timeouts de lancement de session.

Analyse technique : Mesure de la latence réseau ICMP vs RTT de la boucle de jeu

Pour implémenter efficacement l'optimisation du ping des game servers en multiplayer, vous devez faire la distinction entre la latence de transit réseau physique (ping ICMP/UDP) et le round-trip time (RTT) au niveau applicatif. Le premier mesure le temps nécessaire à un paquet réseau brut pour faire l'aller-retour jusqu'au serveur. Le second inclut le délai de traitement de frame (frame processing delay) du serveur, le temps de sérialisation réseau et la latence d'interpolation côté client.

Le principal problème avec l'affichage du ping côté client est qu'il mesure le temps total écoulé entre l'envoi d'un paquet et la réception de son accusé de réception (ACK). Si le serveur subit un bottleneck CPU dû au Garbage Collection ou à des calculs physiques complexes, il retarde l'envoi de l'ACK. Le client ne peut pas faire la différence entre ce retard local du serveur et les délais de routage, ce qui se traduit par de faux rapports de ping réseau élevé.

En exécutant le test de ping au niveau du network driver et en le comparant au tick rate du main thread de jeu, les développeurs peuvent isoler ces bottlenecks. Cela permet à l'équipe d'orchestration backend de déterminer si elle doit optimiser le code ou modifier les chemins de routage réseau. Voyons comment nous pouvons implémenter cet agent de monitoring.

La classe C++ suivante, compatible avec Unreal Engine, montre comment suivre le ping réseau brut et le séparer de l'overhead de traitement de la boucle de jeu. En calculant cette différence, vous pouvez déterminer si le ping élevé d'un joueur est causé par un mauvais routage réseau ou par un serveur dont le frame rate s'effondre.

// PingMonitor.h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "PingMonitor.generated.h"

USTRUCT(BlueprintType)
struct FNetworkQualityStats
{
    GENERATED_BODY()

    UPROPERTY(BlueprintReadOnly, Category = "Network Quality")
    float NetworkPingMS;

    UPROPERTY(BlueprintReadOnly, Category = "Network Quality")
    float FrameProcessingDelayMS;

    UPROPERTY(BlueprintReadOnly, Category = "Network Quality")
    float TotalEffectiveRTT;

    FNetworkQualityStats()
        : NetworkPingMS(0.0f)
        , FrameProcessingDelayMS(0.0f)
        , TotalEffectiveRTT(0.0f)
    {}
};

UCLASS()
class MULTIPLAYERGAME_API APingMonitor : public AActor
{
    GENERATED_BODY()

public:
    APingMonitor();

protected:
    virtual void BeginPlay() override;

public:
    virtual void Tick(float DeltaTime) override;

    UFUNCTION(BlueprintCallable, Category = "Network Quality")
    FNetworkQualityStats GetCurrentNetworkStats() const;

private:
    float LastPingTime;
    float HeartbeatInterval;
    float ServerTickRate;
    
    TMap<int32, double> SentHeartbeats;
    int32 HeartbeatSequenceId;
    FNetworkQualityStats CachedStats;

    void SendHeartbeat();
    void HandleHeartbeatAck(int32 SequenceId);
};
// PingMonitor.cpp
#include "PingMonitor.h"
#include "GameFramework/PlayerController.h"
#include "Engine/World.h"

APingMonitor::APingMonitor()
    : HeartbeatInterval(1.0f)
    , ServerTickRate(30.0f)
    , HeartbeatSequenceId(0)
{
    PrimaryActorTick.bCanEverTick = true;
    PrimaryActorTick.TickInterval = 0.1f;
}

void APingMonitor::BeginPlay()
{
    Super::BeginPlay();
    LastPingTime = GetWorld()->GetTimeSeconds();
}

void APingMonitor::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    float CurrentTime = GetWorld()->GetTimeSeconds();
    if (CurrentTime - LastPingTime >= HeartbeatInterval)
    {
        SendHeartbeat();
        LastPingTime = CurrentTime;
    }
}

void APingMonitor::SendHeartbeat()
{
    HeartbeatSequenceId++;
    double SendTimeStamp = FPlatformTime::Seconds();
    SentHeartbeats.Add(HeartbeatSequenceId, SendTimeStamp);
}

void APingMonitor::HandleHeartbeatAck(int32 SequenceId)
{
    if (SentHeartbeats.Contains(SequenceId))
    {
        double SendTime = SentHeartbeats[SequenceId];
        double ReceiveTime = FPlatformTime::Seconds();
        float RTT = static_cast<float>((ReceiveTime - SendTime) * 1000.0);

        float FrameTimeMS = GetWorld()->GetDeltaSeconds() * 1000.0f;
        float ExpectedTickTimeMS = 1000.0f / ServerTickRate;
        float ProcessingDelay = FMath::Max(0.0f, FrameTimeMS - ExpectedTickTimeMS);

        CachedStats.NetworkPingMS = RTT - ProcessingDelay;
        CachedStats.FrameProcessingDelayMS = ProcessingDelay;
        CachedStats.TotalEffectiveRTT = RTT;

        SentHeartbeats.Remove(SequenceId);

        UE_LOG(LogNet, Log, TEXT("RTT: %.2fms | NetPing: %.2fms | FrameDelay: %.2fms"),
            CachedStats.TotalEffectiveRTT, CachedStats.NetworkPingMS, CachedStats.FrameProcessingDelayMS);
    }
}

FNetworkQualityStats APingMonitor::GetCurrentNetworkStats() const
{
    return CachedStats;
}

Cette classe calcule le FrameProcessingDelayMS en comparant le delta time réel du tick du serveur au tick rate cible. Si le délai de traitement est élevé, le développeur sait qu'il doit optimiser l'exécution des scripts côté serveur au lieu de rejeter la faute sur le fournisseur réseau. En faisant tourner ce système sur des serveurs de test, vous pouvez suivre les métriques de qualité réseau en temps réel.

Architecture d'un orchestrateur dynamique low-latency

Pour résoudre manuellement la pénalité de latence du mode créatif, vous devez repenser votre couche d'orchestration de serveurs. Une architecture typique repose sur trois piliers fondamentaux : le pre-warming géo-distribué, le routage edge facilité par Anycast, et un asset stripping agressif.

Premièrement, implémentez un orchestrateur de pre-warming à l'aide d'outils comme Agones sur Kubernetes. Au lieu de démarrer des conteneurs à partir de zéro, maintenez un petit pool d'instances de serveurs inactives et prêtes (warm) dans 8 à 12 régions mondiales. Le système de matchmaking doit surveiller en permanence la densité de joueurs et adapter dynamiquement la taille de ces pools pour éviter que les joueurs ne soient redirigés vers des régions éloignées pendant les heures de pointe.

Deuxièmement, placez un réseau de proxies edge devant vos serveurs de jeu. Ces proxies doivent utiliser le routage IP Anycast pour accepter les connexions UDP des clients à la périphérie (edge) du réseau la plus proche. Le proxy achemine ensuite le trafic de jeu via un tunnel sur un backbone privé dédié à faible latence (comme AWS Global Accelerator) jusqu'au conteneur du serveur final. Cela permet de contourner les chemins de routage publics non optimisés qui pénalisent les connexions unicast à la demande.

Troisièmement, optimisez vos builds de serveur. Supprimez tous les assets inutiles côté client — tels que les textures haute résolution, les fichiers audio et les skeletal meshes — de la build du dedicated server. Cela réduit la taille des images de conteneurs de plusieurs gigaoctets à moins de 200 Mo, raccourcissant ainsi le temps de pull du conteneur. Cela permet aux cold starts de s'exécuter en moins de 500 ms lorsque la capacité pre-warmed est épuisée.

Simplifier le routage edge et l'hébergement avec horizOn

Construire et maintenir un orchestrateur géo-distribué avec du routage edge Anycast requiert une équipe d'operations dédiée et des milliers de dollars de coûts d'infrastructure cloud (overhead). C'est une tâche d'ingénierie complexe qui détourne un temps précieux du développement du gameplay. C'est là que horizOn propose une solution clé en main pour les studios indépendants et de taille moyenne.

Plutôt que d'écrire des load balancers personnalisés ou de gérer des clusters Kubernetes sur plusieurs clouds, vous pouvez déployer vos builds de serveur directement sur la plateforme. En tirant parti du temps de boot de conteneur inférieur à la seconde de horizOn et de ses bases de données edge intégrées, vous éliminez les timeouts de cold start et les inefficacités de routage. Cela garantit à vos joueurs une latence aussi faible dans les sessions créatives sandbox que dans les lobbies de matchmaking structurés.

4 bonnes pratiques pour la multiplayer game server ping optimization

Si vous voulez maintenir des latences basses et des tick rates stables dans vos modes de jeu créatifs, appliquez ces quatre stratégies éprouvées sur le terrain :

  1. Implémenter la replication interleaving agressive : Regroupez les mises à jour d'actors non critiques (comme les éléments cosmétiques ou les décorations sandbox éloignées) et ne les répliquez que toutes les 3 ou 4 frames plutôt qu'à chaque frame. Cela réduit la taille du payload réseau et évite le bufferbloat sur les routeurs des clients.
  2. Plafonner les budgets de tick de l'UGC : Imposez des limites d'exécution strictes aux scripts générés par les utilisateurs. Si l'île personnalisée d'un joueur dépasse 5 ms de temps d'exécution de script par frame, limitez (throttle) ou désactivez les scripts de faible priorité pour empêcher le tick rate du serveur de descendre en dessous de 30 Hz.
  3. Utiliser des handshakes de connexion basés sur l'edge : Validez l'authentification des joueurs et les tokens de session au PoP edge le plus proche avant de les acheminer vers le game server. Cela empêche les requêtes d'authentification malveillantes de consommer des cycles CPU du serveur et de provoquer des délais d'attente de paquets pour les joueurs actifs.
  4. Déployer le dynamic tick-rate scaling : Lorsqu'un serveur créatif est inactif ou ne contient qu'un seul joueur, réduisez son tick rate à 10 Hz pour préserver les ressources CPU. Augmentez dynamiquement le tick rate à 30 Hz ou 60 Hz dès que d'autres joueurs rejoignent la session, garantissant ainsi une expérience réactive pendant les phases de gameplay multiplayer actif.

Conclusion et prochaines étapes

Prêt à optimiser votre infrastructure multiplayer ? Déployez votre prochaine build sur horizOn pour bénéficier d'un routage edge automatisé et de game servers low-latency distribués à l'échelle mondiale. Ou explorez la doc de leur API pour en savoir plus sur l'intégration de bases de données edge-network dans votre architecture backend.


Source : Higher ping especially in creative