Como automatizar testes de carga no GameServer do seu servidor de MU Online
Monte um pipeline de testes de carga que simula centenas de conexões simultâneas no ConnectServer e GameServer do seu servidor de MU Online, medindo latência, uso de CPU/memória e o limite real antes do lançamento.
Lançar um servidor de MU Online sem saber quantos jogadores simultâneos ele realmente suporta é uma aposta às cegas: o primeiro dia de divulgação, quando mais gente tenta entrar ao mesmo tempo, é justamente o pior momento para descobrir que o ConnectServer trava em 200 conexões ou que o banco de dad
Lançar um servidor de MU Online sem saber quantos jogadores simultâneos ele realmente suporta é uma aposta às cegas: o primeiro dia de divulgação, quando mais gente tenta entrar ao mesmo tempo, é justamente o pior momento para descobrir que o ConnectServer trava em 200 conexões ou que o banco de dados satura o pool antes do esperado. Este tutorial mostra como montar um pipeline de teste de carga automatizado, simulando conexões e ações simultâneas no ConnectServer e GameServer, medindo os indicadores certos e identificando o limite real do seu ambiente antes que os jogadores o façam por você.
Por que testar carga antes do lançamento
Divulgação bem-sucedida (grupos, YouTube, Discord parceiros) costuma gerar um pico de acessos concentrado nas primeiras horas após o lançamento — muito acima da média que o servidor vai sustentar depois. Se o ambiente quebra nesse pico, a primeira impressão dos jogadores é péssima e boa parte não volta a tentar. Testar a carga com antecedência permite corrigir gargalos (configuração de banco, hardware subdimensionado, limite de conexões do SO) enquanto ainda não há jogadores reais em risco.
Diferenciando os tipos de teste
Nem todo teste de carga precisa simular o jogo inteiro. Dividir por camada facilita isolar onde está o gargalo:
| Tipo de teste | O que simula | Ferramenta típica |
|---|---|---|
| Teste de conexão (login) | Centenas de handshakes simultâneos no ConnectServer | Script próprio (Python/C#) emulando o protocolo |
| Teste de autenticação | Login + seleção de personagem no GameServer | Script com o protocolo de login do emulador |
| Teste de gameplay | Movimento, ataque, troca de mapa, uso de NPC | Bots que jogam de fato (mais custoso) |
| Teste de banco de dados | Concorrência de leitura/escrita em MEMB_INFO, Character | sysbench ou script SQL direto |
| Teste de rede/infra | Banda, latência, pacotes perdidos | iperf3, monitoramento de interface |
Preparando o ambiente de staging
Nunca rode o teste de carga contra o banco/servidor de produção — o risco de corromper dados reais ou derrubar o servidor durante divulgação é alto demais. Clone a configuração (mesmas versões de emulador, mesma configuração de banco, hardware o mais parecido possível) em um ambiente isolado, com dados de teste sintéticos:
CREATE DATABASE mu_staging;
-- Restaure um dump limpo/sintético, nunca dados reais de jogadores
Simulando conexões no ConnectServer
O ConnectServer é o primeiro gargalo em um pico de acesso — ele resolve qual GameServer o cliente deve usar e mantém uma fila de conexões. Um script simples em Python, usando sockets crus, pode simular centenas de handshakes:
import socket
import threading
import time
def simular_conexao(host, porta, resultados, i):
inicio = time.time()
try:
s = socket.create_connection((host, porta), timeout=5)
s.close()
resultados.append(time.time() - inicio)
except Exception as e:
resultados.append(None)
resultados = []
threads = []
for i in range(500):
t = threading.Thread(target=simular_conexao, args=("staging.meuservidor.com", 44405, resultados, i))
threads.append(t)
t.start()
time.sleep(0.01) # espaça levemente para simular chegada gradual
for t in threads:
t.join()
sucesso = [r for r in resultados if r is not None]
print(f"Conexões bem-sucedidas: {len(sucesso)}/{len(resultados)}")
print(f"Latência média: {sum(sucesso)/len(sucesso):.3f}s")
Esse teste básico já revela se o ConnectServer aceita as conexões rapidamente ou começa a enfileirar/recusar acima de determinado volume.
Simulando o fluxo de login completo
Para medir o gargalo real de autenticação (que envolve consulta ao banco de contas), é preciso emular o protocolo de pacotes do seu emulador — a estrutura varia entre IGCN, MuEMU e X-Team, mas o princípio é o mesmo: montar o pacote de login binário e ler a resposta:
import struct
def montar_pacote_login(conta, senha):
# Estrutura simplificada — ajuste aos offsets reais do seu emulador
corpo = conta.encode('ascii').ljust(10, b'\x00') + senha.encode('ascii').ljust(10, b'\x00')
tamanho = len(corpo) + 4
return struct.pack('BBB', 0xC1, tamanho, 0xF1) + corpo
Rodar esse pacote de forma concorrente contra o GameServer de staging, medindo o tempo até a resposta de sucesso/falha, mostra a real capacidade de autenticação simultânea — geralmente o gargalo aparece primeiro aqui, não na conexão TCP em si.
Testando concorrência no banco de dados
Independente do teste de rede, o banco de dados costuma ser o limite real de escala. Use o sysbench para simular carga de leitura/escrita equivalente ao padrão de acesso do servidor (muitas leituras de personagem, poucas escritas de posição a cada poucos segundos):
sysbench oltp_read_write \
--db-driver=mysql --mysql-db=mu_staging \
--mysql-user=teste --mysql-password=senha \
--tables=10 --table-size=100000 \
--threads=200 --time=120 \
run
Compare os resultados de latência (p95, p99) do sysbench com o número de jogadores simultâneos esperado — se o p99 já degrada com 200 threads simuladas e sua meta é 500 CCU, o banco (não o GameServer) é o gargalo a resolver primeiro.
Monitorando recursos durante o teste
Enquanto o teste roda, colete métricas de sistema em paralelo para correlacionar carga com consumo de recurso:
# Em uma janela separada, durante todo o teste:
top -b -n 100 -d 5 | grep -E "GameServer|ConnectServer|mysqld" >> /tmp/monitor_carga.log
vmstat 5 100 >> /tmp/monitor_carga.log
| Métrica | Ferramenta | O que indica |
|---|---|---|
| CPU do processo GameServer | top/htop | Gargalo de processamento de lógica de jogo |
| Memória residente | top/ps | Vazamento de memória sob carga prolongada |
| Conexões ativas no MySQL | SHOW PROCESSLIST; | Saturação de pool de conexões |
| Latência de disco | iostat -x 5 | Gargalo de I/O em bancos grandes |
| Pacotes perdidos/latência de rede | iperf3, ping -f | Limite de banda ou configuração de rede |
Definindo os cenários de teste (rampa gradual)
Em vez de disparar todos os "jogadores simulados" de uma vez (o que não reflete o padrão real de chegada), estruture o teste em rampa — aumentando a carga gradualmente e observando em que ponto cada métrica começa a degradar:
| Fase | CCU simulado | Duração | Objetivo |
|---|---|---|---|
| Aquecimento | 50 | 2 min | Confirmar baseline sem carga |
| Rampa 1 | 150 | 5 min | Meta mínima de lançamento |
| Rampa 2 | 300 | 5 min | Meta esperada de pico |
| Rampa 3 | 500 | 5 min | Estresse acima da meta (margem de segurança) |
| Rampa 4 | 700+ | até quebrar | Identificar o ponto de ruptura real |
Automatizando a execução do pipeline completo
Um script orquestrador simples encadeia as etapas e salva os resultados com timestamp, para comparar execuções ao longo do tempo (ex.: antes e depois de uma otimização de configuração):
#!/bin/bash
DATA=$(date +%F_%H%M)
mkdir -p /tests/$DATA
python3 teste_conexao.py > /tests/$DATA/conexao.log &
sysbench oltp_read_write --threads=200 --time=300 run > /tests/$DATA/banco.log &
top -b -d 5 -n 60 > /tests/$DATA/recursos.log &
wait
echo "Teste de carga $DATA concluído. Resultados em /tests/$DATA/"
Interpretando os resultados e agindo sobre eles
O objetivo final não é só gerar números, é decidir ações concretas. Um resultado típico de análise:
- Se a latência de login degrada antes da CPU do GameServer saturar, o gargalo é o pool de conexões do banco — aumente
max_connectionsno MySQL/MSSQL e ajuste o pool do emulador. - Se a CPU do GameServer satura primeiro, o hardware está subdimensionado para a meta de CCU — considere upgrade de vCPU ou otimização de lógica de eventos que rodam em loop.
- Se a rede degrada com poucas centenas de conexões, o link contratado pode ser insuficiente para o volume esperado — revise o plano com o provedor.
Erros comuns e soluções
| Sintoma | Causa provável | Solução |
|---|---|---|
| Teste derruba o ambiente de staging rapidamente | Rampa muito agressiva desde o início | Use rampa gradual (50 → 150 → 300 → 500) |
| Resultados não são reprodutíveis | Ambiente de staging com hardware diferente da produção | Alinhe specs de CPU/RAM/disco entre staging e produção |
| Latência alta mas CPU/memória OK | Gargalo de banco de dados (pool ou índice) | Rode sysbench isolado e revise SHOW PROCESSLIST |
| Script de simulação trava com erro de socket | Limite de conexões do SO (ulimit) atingido no cliente do teste | Aumente ulimit -n na máquina que gera a carga |
| Teste não revela nada de útil | Métricas de sistema não coletadas durante a execução | Rode top/vmstat/iostat em paralelo, sempre |
| Produção quebra mesmo após teste "aprovado" | Teste rodou só a camada de conexão, não gameplay real | Complemente com teste de bots simulando ações reais |
Checklist de teste de carga
- Ambiente de staging isolado, com specs equivalentes à produção.
- Script de simulação de conexão no ConnectServer funcionando.
- Script de simulação de login/autenticação testado.
- Teste de concorrência de banco (
sysbench) executado e analisado. - Monitoramento de CPU, memória, conexões e disco coletado durante o teste.
- Rampa gradual de carga executada até identificar o ponto de ruptura.
- Ações corretivas definidas com base nos gargalos encontrados.
- Reteste realizado após ajustes para confirmar melhoria.
Com o limite real do seu ambiente mapeado antes do lançamento, você troca surpresas de produção por decisões de dimensionamento tomadas com dados. Se a base do seu servidor ainda está em configuração inicial, comece pelo tutorial de criação de servidor de MU Online antes de investir tempo em testes de carga avançados.
Perguntas frequentes
Preciso de bots reais logando no jogo, ou dá para simular só o protocolo?
Para testes de carga de conexão (ConnectServer e login), simular o protocolo de rede diretamente com um script é mais eficiente e escalável do que abrir centenas de clientes reais. Para testar comportamento de gameplay (movimento, combate, drop), bots que emulam o protocolo do GameServer são necessários, mas ainda assim mais leves que o cliente completo.
Quantos jogadores simultâneos devo simular no teste?
Comece pela meta realista de lançamento (ex.: 300 CCU) e vá além dela em 50-100% para descobrir a margem de segurança real. Se seu objetivo é 300 online, teste até 450-600 para saber onde o sistema realmente quebra.
O teste de carga pode ser feito no servidor de produção?
Não é recomendado. Use um ambiente de staging com hardware e configuração o mais parecidos possível do de produção. Testar em produção arrisca corromper dados reais de jogadores ou causar uma queda visível durante o teste.
O que exatamente devo medir durante o teste?
No mínimo: uso de CPU e memória do processo do GameServer/ConnectServer, tempo de resposta de login, tempo de resposta de troca de mapa, número de pacotes perdidos/latência de rede e uso de conexões do banco de dados.
Depois do teste, o que fazer com os resultados?
Documente o ponto exato onde a performance degrada (ex.: 'acima de 400 CCU a latência de troca de mapa passa de 2s') e use isso para dimensionar hardware, ajustar configurações do banco (pool de conexões) ou definir um limite de fila de entrada (login queue) antes do lançamento oficial.