Como otimizar servidor MTA:SA: performance, tickrate e fim do lag
Guia prático pra otimizar servidor MTA:SA: tunar fps_limit, tickrate, scripts Lua, banco de dados e rede pra eliminar lag e manter 100 jogadores estáveis.
Servidor MTA:SA com lag não é um problema único — é um conjunto de gargalos que se manifesta como rubberbanding, dessincronização de tiros, queda de FPS no cliente e timeouts. A maioria dos guias na internet recomenda “aumentar a RAM” ou “trocar de host”, o que raramente resolve. O gargalo real é quase sempre CPU saturada por scripts Lua mal escritos, sync rate desalinhado com a banda disponível ou banco de dados bloqueando a main thread.
Este tutorial é pra quem administra um servidor MTA:SA — roleplay, deathmatch, freeroam ou racing — e quer parar de tratar sintoma e atacar a causa. Você vai aprender a identificar onde está o gargalo, ajustar o mtaserver.conf com base em dados reais, otimizar os resources Lua mais pesados e configurar o sistema operacional pra entregar pacotes UDP com latência baixa e consistente. Tempo estimado: 40-60 minutos com o servidor já instalado.
Antes de mudar qualquer parâmetro, deixe claro: otimização sem medição é palpite. Cada seção abaixo inclui o comando de diagnóstico antes da mudança e como validar o resultado.
Pré-requisitos
Servidor MTA:SA 1.6+ rodando em Linux (Ubuntu 22.04 LTS ou Debian 12), acesso SSH com sudo, e ao menos uma sessão de teste com 10-20 jogadores ou um bot de stress pra gerar carga representativa. Otimização baseada em servidor vazio é inútil — o comportamento muda completamente sob load.
22003 UDP 22005 TCP 22126 UDP mta-server64 Tenha também acesso ao painel ou shell onde o servidor roda e ao arquivo mtaserver.conf. Se você administra múltiplos servidores compartilhando o mesmo hardware, isole as métricas — CPU steal de um vizinho barulhento pode parecer problema seu.
Medindo o estado atual
Antes de tunar qualquer coisa, registre baseline. Sem números antes/depois, você não vai saber se a mudança ajudou.
Conecte no console do servidor (via terminal local ou painel) e habilite o monitor de performance interno:
debugscript 3
showperfO comando showperf exibe o tempo médio de processamento por frame em milissegundos, separado por categoria (sync, scripts, banco). Anote os valores em servidor vazio e com pelo menos 50% da capacidade ocupada.
No shell do Linux, capture uso de CPU por thread do processo:
top -H -p $(pgrep -f mta-server64)A thread principal (geralmente a primeira listada com mais CPU) é onde scripts Lua executam. Se ela está em 95-100% e o servidor é multi-core, você tem um gargalo single-threaded — comum em MTA, que não paraleliza Lua.
Veja o uso de rede em tempo real:
sudo iftop -i eth0 -P -BNote a banda usada por jogador conectado. Um servidor saudável usa 8-15 KB/s por jogador no estado normal. Acima de 25 KB/s indica sync rate alto demais ou broadcast desnecessário em scripts.
Salve esses três snapshots num arquivo de texto. Eles são sua referência pra validar cada mudança.
Ajustando o mtaserver.conf
O mtaserver.conf controla os intervalos de sincronização entre cliente e servidor. Valores agressivos demais saturam a banda e a CPU; valores conservadores demais geram a sensação de “borracha” no movimento dos outros jogadores.
Localize o arquivo (normalmente em /home/mta/mods/deathmatch/mtaserver.conf) e abra com editor de sua preferência. Procure as seções de sync.
Configure os intervalos pra um servidor de 60-100 jogadores com objetivo de gameplay fluido:
<player_sync_interval>100</player_sync_interval>
<light_sync_interval>1500</light_sync_interval>
<camera_sync_interval>500</camera_sync_interval>
<ped_sync_interval>400</ped_sync_interval>
<unoccupied_vehicle_sync_interval>1000</unoccupied_vehicle_sync_interval>
<keysync_mouse_sync_interval>100</keysync_mouse_sync_interval>
<keysync_analog_sync_interval>100</keysync_analog_sync_interval>Esses valores são o sweet spot pra DM e roleplay. Pra servidores de racing competitivo, reduza player_sync_interval pra 80 e keysync_mouse_sync_interval pra 80 — você ganha responsividade ao custo de ~25% mais banda por jogador.
Ajuste o limite de FPS do servidor e a alocação de recursos do simulador físico:
<fps_limit>0</fps_limit>
<server_logic_fps>100</server_logic_fps>
<bandwidth_reduction>none</bandwidth_reduction>fps_limit=0 desabilita o limite no cliente — isso não afeta o servidor diretamente mas evita que jogadores reclamem de cap artificial. server_logic_fps=100 é o padrão e quase nunca precisa mudar. bandwidth_reduction em “medium” só vale se sua banda total está estourando.
Ao reiniciar o servidor pra aplicar essas mudanças, jogadores conectados perdem a sessão. Faça em janela de manutenção avisada ou use refresh + refreshall no console pra recarregar resources sem derrubar conexões — embora mtaserver.conf exija restart completo.
Reinicie o servidor e meça de novo:
sudo systemctl restart mta-serverRepita showperf e iftop após 10 minutos de operação com jogadores. Os tempos de frame devem estar consistentes abaixo de 12ms na thread principal.
Otimizando scripts Lua
Scripts mal escritos são responsáveis por 70% dos casos de servidor MTA com lag — independente do hardware. A boa notícia é que dá pra identificar e corrigir os piores ofensores rapidamente.
No console do servidor, ative o profiler embutido por 60 segundos com o servidor sob carga real:
debugscript 3
debug-resources --top 10A saída lista os 10 resources que mais consomem CPU em ms por frame. Foque nos 3 primeiros — eles geralmente respondem por 50%+ do consumo total.
Identifique e elimine setTimer com intervalo curto. Esse é o anti-pattern mais comum:
setTimer(function()
for _, player in ipairs(getElementsByType("player")) do
local money = getPlayerMoney(player)
end
end, 50, 0)Esse código roda 20 vezes por segundo iterando todos os jogadores. Em servidor com 80 jogadores, são 1600 iterações por segundo só pra esse timer. Substitua por eventos disparados sob demanda:
addEventHandler("onPlayerMoneyChange", root, function()
end)Cache resultados de getElementsByType e similares. Cada chamada percorre a árvore de elementos do servidor:
local cachedPlayers = {}
addEventHandler("onPlayerJoin", root, function()
table.insert(cachedPlayers, source)
end)
addEventHandler("onPlayerQuit", root, function()
for i, p in ipairs(cachedPlayers) do
if p == source then
table.remove(cachedPlayers, i)
break
end
end
end)Iterar cachedPlayers é 10-30x mais rápido que getElementsByType("player") em loop apertado.
Disparar evento pro root envia pra todos os clientes, custando banda proporcional ao número de jogadores. Use triggerClientEvent(targetPlayer, ...) ou triggerClientEvent(getPlayersInRange(x, y, z, 200), ...) pra limitar broadcast. Servidores de roleplay com inventário em UI gastam metade da banda só por causa de eventos não-direcionados.
Banco de dados e persistência
SQLite é o default do MTA e geralmente é a melhor escolha. Mas a configuração padrão não habilita Write-Ahead Logging, o que causa bloqueio em writes simultâneos.
No primeiro carregamento do banco, ative WAL mode via SQL:
executeSQLQuery("PRAGMA journal_mode=WAL")
executeSQLQuery("PRAGMA synchronous=NORMAL")
executeSQLQuery("PRAGMA cache_size=-20000")WAL permite leituras concorrentes com escritas. synchronous=NORMAL reduz fsync sem comprometer durabilidade catastroficamente — aceita perder o último 1 segundo em caso de crash do servidor. cache_size=-20000 aloca 20 MB de cache pro SQLite.
Identifique queries lentas habilitando log temporário:
local startTime = getTickCount()
local result = executeSQLQuery("SELECT * FROM accounts WHERE last_login > ?", os.time() - 86400)
local elapsed = getTickCount() - startTime
if elapsed > 50 then
outputDebugString("Query lenta: " .. elapsed .. "ms")
endQualquer query acima de 50ms bloqueia a main thread e é candidata a otimização — adicione índices em colunas de busca ou paginação em resultados grandes.
Rede e sistema operacional
A camada de rede do Linux tem defaults conservadores que não foram pensados pra UDP de jogos. Ajustes corretos reduzem latência percebida sem mudar nada no jogo.
Habilite fq_codel como qdisc na interface principal:
sudo tc qdisc replace dev eth0 root fq_codelfq_codel elimina bufferbloat, mantendo latência consistente mesmo com a banda saturada. A diferença prática: jogadores no horário de pico não veem mais ping subir de 30ms pra 200ms quando o tráfego total cresce.
Aumente os buffers de UDP no kernel:
sudo sysctl -w net.core.rmem_max=8388608
sudo sysctl -w net.core.wmem_max=8388608
sudo sysctl -w net.core.netdev_max_backlog=5000Persista em /etc/sysctl.d/99-mta.conf pra sobreviver a reboot. Buffers maiores absorvem rajadas sem dropar pacotes, que é o que causa rubberbanding quando o link enche.
Algumas guias antigas recomendam tcp_congestion_control=bbr ou desativar GRO/LRO em servidores de jogos. Em hardware moderno, isso pode piorar a performance. Sempre meça antes e depois — não copie configurações cegamente de fóruns.
Verificação
Depois de aplicar as mudanças, valide com carga real:
showperf
Os tempos por frame devem estar consistentemente abaixo de 12ms na main thread, mesmo com servidor cheio. Use iftop pra confirmar que a banda por jogador caiu (se você reduziu broadcast desnecessário) ou ficou estável (se você aumentou sync rate por gameplay).
No cliente, peça pra 3-5 jogadores rodarem Net Stats (F11 no menu MTA) e reportarem jitter e packet loss durante 10 minutos de gameplay normal. Jitter abaixo de 5ms e zero packet loss é o alvo.
Resolução de problemas
Servidor reinicia sozinho sob carga
Geralmente é OOM killer matando o processo. Verifique com dmesg | grep -i "killed process". A solução é aumentar RAM ou criar swap de 4 GB. Scripts Lua vazando memória também causam isso — use getResourceUsedMemory pra identificar o resource culpado.
Latência alta só pra alguns jogadores
Não é o servidor. Peça pra eles rodarem mtr ou WinMTR pro IP do servidor durante o problema. Quase sempre é congestionamento na rota do ISP do jogador. Se o problema é consistente pra clientes de um único ISP brasileiro, considere mover o servidor pra uma região com melhor peering com aquele ISP.
”Server is full” mas tem slots livres
Verifique MaxPlayers no mtaserver.conf e maxplayers no arquivo de servidor master. Os dois precisam bater. Em alguns casos, scripts customizados implementam limite próprio via cancelEvent() no onPlayerConnect — busque por isso nos resources customizados.
Próximos passos
Otimização é processo contínuo — meça periodicamente, especialmente depois de adicionar resources novos. Algumas direções pra aprofundar:
- Configurar monitoramento de longo prazo com sistema de métricas externo plotando frame time e player count ao longo do dia
- Estudar Lua JIT e estruturas de dados eficientes pra scripts que processam grandes volumes (inventário, leaderboards)
- Implementar rate limiting nos eventos vindo do cliente pra prevenir flood malicioso
- Documentar o baseline de cada server hash pra detectar regressão após updates de resources
Se você está crescendo o servidor pra além de 100 jogadores simultâneos ou rodando múltiplos servidores MTA da mesma comunidade, uma hospedagem dedicada de MTA da Hostini já vem com kernel tunado pra UDP de jogos, proteção DDoS na borda e rede com peering brasileiro otimizado — três coisas que removem 80% das causas comuns de lag antes mesmo do primeiro jogador conectar.
Perguntas frequentes
Qual é o tickrate ideal pra um servidor MTA:SA?
MTA:SA não tem um "tickrate" único — o servidor opera com vários intervalos configuráveis em mtaserver.conf. Os principais são player_sync_interval (padrão 100ms), light_sync_interval (1500ms) e camera_sync_interval (500ms). Reduzir player_sync_interval pra 80ms melhora a fluidez do tiroteio mas aumenta a banda usada em ~25%. Não desça abaixo de 60ms sem rede dedicada.
Quantos jogadores um servidor MTA:SA aguenta numa VPS de 4 vCPUs?
Servidor stock vanilla com poucos scripts customizados aguenta 80-120 jogadores em 4 vCPUs e 4 GB de RAM. Servidores roleplay (DayZ, RPG brasileiro com inventário, garagem, etc) caem pra 40-60 jogadores no mesmo hardware porque o gargalo deixa de ser rede e vira CPU executando Lua. Profile antes de escalar hardware.
Por que meu servidor MTA fica em 60% CPU mesmo vazio?
Timers Lua mal feitos são a causa #1. Qualquer setTimer com intervalo abaixo de 100ms rodando em loop infinito consome CPU mesmo sem jogadores. Use debugscript 3 in-game pra ver quais resources estão consumindo CPU em ms por frame. Resources mal escritos podem queimar 30-40% sozinhos.
Compensa usar banco de dados externo ou SQLite interno basta?
Pra menos de 100 jogadores simultâneos e queries simples, SQLite é mais rápido por eliminar latência de rede. MySQL/MariaDB externo só compensa quando você tem múltiplos servidores compartilhando dados ou queries complexas com JOIN em tabelas grandes. Pra servidor único, SQLite com WAL mode é a melhor escolha.
MTU 1500 ou MTU otimizada pra MTA:SA?
MTA:SA usa pacotes UDP pequenos (60-400 bytes na maior parte). MTU padrão de 1500 funciona bem — não há ganho prático em reduzir. O que importa é eliminar bufferbloat: habilitar fq_codel ou cake como qdisc no Linux faz mais diferença que ajustar MTU.
Como sei se o lag dos jogadores é do servidor ou da rede deles?
Use o comando /showperf no console do servidor pra ver o tempo de cada frame em ms. Se está abaixo de 16ms consistentemente, o servidor está saudável. Lag relatado nesse cenário é problema de rota do jogador. Use mtrping ou WinMTR a partir de IPs de jogadores reclamantes pra confirmar perda de pacotes no caminho.