Voltar ao Blog

Arquitetando Servidores Zero-Waste: Análise da Proposta de Hibernação para Otimização de Servidores do Fortnite

Publicado em 25 de fevereiro de 2026
Arquitetando Servidores Zero-Waste: Análise da Proposta de Hibernação para Otimização de Servidores do Fortnite

Todo desenvolvedor multiplayer acaba batendo no mesmo muro financeiro: sua infraestrutura de servidor está queimando dinheiro para simular espaço vazio. Quando você sobe um Dedicated Server para um battle royale de larga escala, jogo de sobrevivência ou MMO, os ciclos de CPU são pesadamente desviados para cálculos de ociosidade. Você está pagando taxas premium de Cloud Computing para calcular a gravidade de pedras que ninguém está olhando, processar navegação de IA para inimigos sem alvos e manter World States em setores completamente desprovidos de atividade de jogadores.

Recentemente, uma proposta técnica fascinante surgiu na comunidade Unreal Engine direcionada à liderança da Epic Games. A tese central? A escala massiva do Fortnite exige uma transição de um modelo de hospedagem centralizado de alta manutenção para um modelo de "Zero-Waste Infrastructure". O autor argumentou que, ao eliminar o desperdício de simulação, a Epic poderia reduzir os Operating Expenses (Opex) em 60-70%, teoricamente permitindo que reduzissem o preço da moeda premium para um MSRP de $1,99 por 1.000 V-Bucks.

Embora a viabilidade econômica do preço dos V-Bucks seja um debate para designers de monetização, o pilar técnico desta proposta — Sector Physics Hibernation (SGH) — é uma aula mestre em arquitetura de servidor moderna.

Nesta análise da indústria, vamos dissecar a mecânica da proposta de hibernação para otimização de servidores do Fortnite, explorar como o Logic-Side Culling funciona no Unreal Engine 5 e demonstrar como você pode implementar uma infraestrutura zero-waste em seus próprios títulos multiplayer.

A Matemática do Desperdício de Simulação

Para entender por que a Sector Physics Hibernation é necessária, temos que olhar para a matemática brutal dos Dedicated Servers de jogos.

Considere um mapa padrão de battle royale de 100km². No início de uma partida, 100 jogadores caem em vários pontos de interesse. Nos primeiros 5 minutos, 50% dos jogadores são eliminados, e os sobreviventes convergem para uma Safe Zone que encolhe.

No minuto 10, mais de 70% da área total do mapa contém zero jogadores ativos. No entanto, em uma configuração padrão de Authoritative Server, o Dedicated Server continua a processar o Tick de todo o World State a 30Hz.

  • Physics Calculations: Rigid Bodies, ambientes destrutíveis e balística ainda estão sendo rastreados na memória.
  • Actor Ticking: Milhares de instâncias de AActor estão chamando suas funções Tick() 30 vezes por segundo.
  • NavMesh Processing: IA errante ou obstáculos dinâmicos continuam a consultar a Navigation Mesh.

Se você está rodando seus servidores em instâncias AWS c5.2xlarge, você está pagando cerca de $0,34 por hora por máquina. Se uma única máquina só consegue hospedar duas instâncias de jogo de 100 jogadores porque a CPU está no limite calculando espaço vazio, sua escala está severamente limitada.

A proposta sugere que, ao recuperar esse overhead de CPU desperdiçado, os desenvolvedores podem compactar 5-6 instâncias de jogo no mesmo hardware (reduzindo as contas de servidor em ~60%), ou redirecionar esse poder de processamento recuperado para aumentar o Tick Rate global do servidor de 30Hz para 60Hz+, garantindo um Hit Registration perfeito e um gameplay fluido.

Deep Dive: Sector Physics Hibernation no UE5

A solução técnica proposta baseia-se em aproveitar o sistema de World Partition existente no Unreal Engine 5, mas invertendo seu caso de uso principal do gerenciamento de memória no cliente para o gerenciamento de CPU no servidor.

O Problema com Dedicated Servers Padrão

Por padrão, o World Partition do UE5 carrega e descarrega células para o cliente com base na distância da fonte de streaming (a câmera do jogador). Isso é excelente para manter o uso de memória do cliente baixo e as taxas de quadros altas.

No entanto, o Dedicated Server geralmente carrega o mapa inteiro na memória para manter a autoridade. Se um sniper dispara uma bala através de um vale, ou se um evento global é acionado, o servidor precisa dos dados de colisão e Actor States prontamente disponíveis para validar a ação. Carregar e descarregar dados dinamicamente do disco no servidor (Level Streaming) é frequentemente muito lento e causa travamentos massivos, arruinando o Tick Rate.

A Solução SGH: Logic-Side Culling

Em vez de descarregar o setor da memória (o que causa gargalos de IO), a Sector Physics Hibernation propõe CPU-Sleep States.

O setor permanece na RAM, mas todos os Ticks, cálculos de física e atualizações de estado são pausados agressivamente. Quando uma célula da Spatial Grid de um setor detecta zero entidades ativas (jogadores, veículos de jogadores ou projéteis ativos), o servidor suspende a alocação de CPU para aquele Grid específico.

Implementando um Hibernation Manager em C++

Para construir isso no Unreal Engine, você precisa de um subsistema que monitore as células da Spatial Grid e alterne dinamicamente o estado de Tick dos atores dentro delas. Abaixo está um protótipo arquitetônico simplificado de como você pode implementar um SectorHibernationManager.

#include "SectorHibernationManager.h"
#include "EngineUtils.h"
#include "GameFramework/Actor.h"
#include "GameFramework/PlayerController.h"

void USectorHibernationManager::Initialize(FSubsystemCollectionBase& Collection)
{
    Super::Initialize(Collection);
    HibernationCheckInterval = 2.0f; // Verificar a cada 2 segundos
    TimeSinceLastCheck = 0.0f;
    GridCellSize = 10000.0f; // Células de grid de 100m
}

void USectorHibernationManager::Tick(float DeltaTime)
{
    TimeSinceLastCheck += DeltaTime;
    if (TimeSinceLastCheck >= HibernationCheckInterval)
    { 
        EvaluateSectors();
        TimeSinceLastCheck = 0.0f;
    }
}

void USectorHibernationManager::EvaluateSectors()
{
    UWorld* World = GetWorld();
    if (!World) return;

    // Passo 1: Mapear posições de jogadores ativos para células do grid
    TSet<FIntVector> ActiveCells;
    for (FConstPlayerControllerIterator Iterator = World->GetPlayerControllerIterator(); Iterator; ++Iterator)
    { 
        APlayerController* PC = Iterator->Get();
        if (PC && PC->GetPawn())
        { 
            FVector PlayerPos = PC->GetPawn()->GetActorLocation();
            FIntVector CellCoord = FIntVector(
                FMath::FloorToInt(PlayerPos.X / GridCellSize),
                FMath::FloorToInt(PlayerPos.Y / GridCellSize),
                FMath::FloorToInt(PlayerPos.Z / GridCellSize)
            );
            
            // Marcar esta célula e células adjacentes como ativas (zona de buffer)
            MarkAdjacentCellsActive(CellCoord, ActiveCells);
        }
    }

    // Passo 2: Iterar pelos atores hibernáveis e alternar o tick
    for (TActorIterator<AActor> ActorItr(World); ActorItr; ++ActorItr)
    { 
        AActor* Actor = *ActorItr;
        
        // Pular atores de infraestrutura essenciais
        if (!Actor->ActorHasTag(FName("Hibernatable"))) continue;

        FVector ActorPos = Actor->GetActorLocation();
        FIntVector ActorCell = FIntVector(
            FMath::FloorToInt(ActorPos.X / GridCellSize),
            FMath::FloorToInt(ActorPos.Y / GridCellSize),
            FMath::FloorToInt(ActorPos.Z / GridCellSize)
        );

        bool bShouldBeActive = ActiveCells.Contains(ActorCell);
        
        if (bShouldBeActive && !Actor->IsActorTickEnabled())
        { 
            // Acordar
            Actor->SetActorTickEnabled(true);
            Actor->SetActorEnableCollision(true);
        }
        else if (!bShouldBeActive && Actor->IsActorTickEnabled())
        { 
            // Dormir
            Actor->SetActorTickEnabled(false);
            // Opcional: Rebaixar colisão para apenas consultas simples para economizar tempo na thread de física
            Actor->SetActorEnableCollision(false); 
        }
    }
}

A Complexidade da Fase de "Wake-Up"

O código acima ilustra o conceito central, mas o verdadeiro desafio de engenharia reside na fase de despertar. Se um jogador dispara um rifle sniper de alta velocidade em um setor adormecido, o projétil atravessará o limite antes que o loop de avaliação de 2 segundos o detecte.

Se o setor acordar depois que a bala chegar, você experimentará um desync catastrófico. A bala pode passar direto por um veículo em hibernação porque sua colisão estava desativada. Este fenômeno está intimamente relacionado aos problemas detalhados em nosso guia sobre The Unreal Engine Multiplayer Sync Bug Ruining Your World States And How To Fix It, onde discrepâncias de tempo entre o estado do servidor e a predição do cliente quebram completamente a simulação.

Para resolver isso, a infraestrutura zero-waste requer Predictive Wake-Ups. Em vez de apenas rastrear as posições dos jogadores, o servidor deve calcular os vetores de velocidade de todos os projéteis ativos e veículos de alta velocidade. Se um vetor interceptar uma célula de grid adormecida, o servidor deve forçar instantaneamente um evento de despertar naquela célula específica antes da chegada do objeto.

Orquestrando Servidores Zero-Waste em Escala

Implementar Logic-Side Culling dentro da sua engine de jogo é apenas metade da batalha. A outra metade é a orquestração da infraestrutura.

Se o seu Dedicated Server de UE5 reduzir com sucesso sua pegada de CPU em 60% dinamicamente, seu ambiente de hospedagem de servidor precisa ser inteligente o suficiente para reconhecer essa queda no uso de recursos e compactar novas instâncias de jogo no mesmo nó de hardware.

Construir essa orquestração por conta própria exige uma quantidade imensa de engenharia DevOps. Você precisaria implantar clusters Kubernetes, configurar Agones para gerenciamento do ciclo de vida do servidor de jogo, escrever métricas de escala personalizadas baseadas na utilização da CPU e gerenciar Load Balancers para rotear os jogadores para as instâncias corretas. Isso são facilmente 4-6 meses de trabalho dedicado à infraestrutura — tempo tirado diretamente do desenvolvimento do seu jogo.

Com horizOn, esses serviços de orquestração de Backend já vêm pré-configurados. A plataforma lida com compactação dinâmica de instâncias, Auto-Scaling baseado na carga do servidor em tempo real e pipelines de implantação automatizados para seus builds de Dedicated Server. Ao deixar que um Backend-as-a-Service especializado cuide da infraestrutura, você pode lançar seu jogo multiplayer em vez de passar meio ano lutando com manifestos do Kubernetes.

Além disso, quando você compacta mais instâncias em um único nó, aumenta o risco de problemas de Noisy Neighbor afetando sua thread de rede. Proteger seu Netcode contra esses gargalos é crítico, um tópico que cobrimos extensivamente em The Uefn Server Performance Exploit Explained Hard Armoring Your Unreal Engine Netcode.

Melhores Práticas para Arquitetura Multiplayer Zero-Waste

Seja você construindo um battle royale de 100 jogadores ou um jogo de sobrevivência de mundo aberto persistente, implementar hibernação e técnicas zero-waste requer disciplina arquitetônica rigorosa. Aqui estão cinco melhores práticas testadas em batalha para garantir que o Opex do seu servidor permaneça baixo sem sacrificar a experiência do jogador:

1. Desacople o Game State do Tick Loop

O maior inimigo da performance do servidor é a consulta contínua de dados. Nunca use Tick() para verificar se um evento deve acontecer. Mude inteiramente para uma Event-Driven Architecture. Se uma fogueira precisa apagar após 5 minutos, não processe o tick a cada frame para subtrair tempo. Defina um timer delegate que dispara exatamente uma vez após 300 segundos. Isso permite que o ator da fogueira permaneça completamente adormecido por 4 minutos e 59 segundos.

2. Implemente NetCullDistanceSquared Agressivo

O Unreal Engine determina quais atores replicar para quais clientes com base no NetCullDistanceSquared. Muitos desenvolvedores deixam isso nos valores padrão, forçando o servidor a serializar e comprimir dados para atores que estão a centenas de metros de distância de um jogador. Audite suas distâncias de cull. Uma arma caída não precisa ser replicada além de 5.000 unidades (50 metros). Calcule o raio mínimo absoluto necessário para o seu Gameplay Loop e aplique-o estritamente.

3. Use Spatial Hash Grids para Lookups O(1)

Ao calcular quais atores devem dormir, iterar sobre cada ator no mundo (TActorIterator) torna-se um gargalo por si só se você tiver 100.000 entidades. Implemente um Spatial Hash Grid. Quando um ator se move, ele atualiza sua posição no hash map. Isso permite que seu Hibernation Manager consulte "O que está na Célula de Grid X?" em complexidade de tempo O(1), tornando a avaliação de hibernação virtualmente gratuita na CPU.

4. Utilize Buffer Zones para Despertares Sem Interrupções

Nunca hiberne um setor exatamente até o limite da visão de um jogador. Sempre mantenha uma "Buffer Zone" de setores ativos de pelo menos uma célula de largura ao redor de qualquer entidade ativa. Se suas células de grid têm 100 metros de largura e um jogador está na Célula A, todas as células adjacentes (um grid 3x3) devem permanecer totalmente ativas. Isso garante que, se um jogador correr de repente através de uma fronteira, a célula de destino já esteja totalmente inicializada e processando ticks.

5. Faça Profile dos seus builds de Dedicated Server regularmente

Não adivinhe o que está consumindo sua CPU. Use Unreal Insights em um ambiente de Dedicated Server empacotado com carga simulada. Olhe especificamente para os tempos da GameThread. Se você vir Physics ou TickTime dominando o gráfico da thread quando os jogadores estão parados, sua lógica de hibernação está falhando. Telemetria é a única maneira de validar que sua arquitetura zero-waste está funcionando na realidade, não apenas na teoria.

O Futuro do Opex de Servidor

A proposta da comunidade Fortnite lança luz sobre uma verdade crítica: o padrão atual da indústria de forçar o desempenho do servidor com Cloud Compute caro é insustentável. À medida que os mundos ficam maiores e a contagem de jogadores aumenta, o escalonamento linear dos custos de infraestrutura sugará lentamente os orçamentos de Live-Ops.

Sector Physics Hibernation, Logic-Side Culling e compactação dinâmica de instâncias não são mais apenas otimizações para estúdios AAA; são requisitos de sobrevivência para jogos multiplayer de todos os tamanhos. Ao adotar uma mentalidade zero-waste cedo no seu ciclo de desenvolvimento, você garante que a lucratividade do seu jogo escale junto com sua base de jogadores.

Se você está pronto para implementar o escalonamento dinâmico de servidor sem a dor de cabeça do DevOps, experimente o horizOn gratuitamente ou confira a documentação da API para ver como a infraestrutura multiplayer pode ser integrada perfeitamente.


Fonte: [Technical Proposal] Unified Operational Sovereignty: Decoupling Opex to Enable a $1.99 V-Buck Economy