Estouro de buffers rasos por bursts de envio Sender bursts overflow shallow buffers
ID da causa rt-burst · Responsável principal Desenvolvimento do servidor (Equipe de desenvolvimento) · Também envolvidos Infraestrutura de servidores (Equipe de infraestrutura), Infraestrutura de rede (Equipe de infraestrutura)
Quando o servidor manda de uma vez, a cada tick, as atualizações de milhares de jogadores, o buffer pequeno do switch ou o limite instantâneo da nuvem estoura em menos de 1 ms, e parte dos pacotes é descartada.
Por quê No início do tick, os pacotes para todos os jogadores saem de uma vez → Efeito O buffer da porta do switch que junta o tráfego de vários servidores (de centenas de KB a alguns MB por porta) ou o limite da instância na nuvem estoura por um instante (a utilização média é baixa) → Na tela Vários jogadores teleportam ou engasgam ao mesmo tempo, e as métricas de média não mostram a causa
Responsável principal Desenvolvimento do servidor (Equipe de desenvolvimento) · Também envolvidos Infraestrutura de servidores (Equipe de infraestrutura), Infraestrutura de rede (Equipe de infraestrutura)
O que fazer (Equipe de desenvolvimento)
Distribuir o envio de um tick ao longo do tick (o pacing por conexão não resolve bem milhares de conexões disparando no início do tick), espalhar o horário de início do tick entre os servidores, limitar a taxa com SO_MAX_PACING_RATE nas conexões que enviam muitos dados.
O que fazer (Equipe de infraestrutura)
Servidores/SO: limitar a taxa de envio do servidor inteiro (shaper no SO do servidor, tc no Linux), suavizar com pacing (fila fq do Linux, BBR) os bursts de uma única conexão. Rede: switches com buffers maiores, verificar em intervalos curtos os contadores de descarte de saída das portas de switch (a utilização média não mostra o problema).
Números de referência
Uma porta de 10 Gbps envia cerca de 1,25 MB em 1 ms. Quando os ticks de vários servidores coincidem e convergem para uma porta, o buffer enche num instante.
No gráfico
Sobe com a carga · Descartes de saída na porta do switch, taxa de retransmissão
Onde olhar
Coletar a cada poucos segundos os descartes de saída (ifOutDiscards) da porta do switch onde o servidor está ligado e da porta acima dela; na nuvem, ver bw_out_allowance_exceeded e pps_allowance_exceeded no ethtool -S. Coletar as retransmissões do mesmo momento com o tcpretrans do bcc e cruzar os dados
Confirma se
A utilização média por minuto é baixa, mas os descartes de saída ou os excessos de allowance aumentam, crescendo com o número de jogadores simultâneos e de jogadores reunidos em um só lugar. As retransmissões não se concentram em faixas de IP de jogadores (operadora, região) e acontecem no mesmo instante em várias conexões do servidor
Descarta se
Erros de CRC e de entrada subindo junto na mesma porta: “Erros físicos”. Contadores de descarte da NIC ou softnet dropped subindo no servidor que recebe: “Descarte de pacotes no servidor receptor”
Como verificar
Ferramentas de infra (sem precisar do código do jogo)
Saiba mais
O pacing atua em cada conexão separadamente. Milhares de conexões mandando um ou dois pacotes cada no início do tick formam um burst que o pacing por conexão não resolve bem; o servidor do jogo precisa distribuir ele mesmo os momentos de envio. Já quando uma conexão manda muitos dados, a NIC corta dezenas de KB em pacotes e os despeja em sequência (TSO), e o pacing distribui bem esse tipo de burst.
Fontes
High-Resolution Measurement of Data Center MicroburstsMeta Mais de 70% dos bursts em switches de rack de data center terminam em dezenas de µs, e a relação entre a utilização média por minuto e os descartes é fraca (IMC 2017)
tc-fq(8) — Linux manual pageiproute2 A fila fq faz pacing por socket (conexão), e SO_MAX_PACING_RATE define a taxa máxima por conexão
net/ipv4/tcp_bbr.cLinux kernel O BBR envia definindo o pacing_rate pela largura de banda estimada do gargalo
IP SysctlLinux kernel O TCP define o tamanho dos frames TSO conforme a taxa do fluxo (máximo de 64 KB, tcp_min_tso_segs)
RFC 2863: The Interfaces Group MIBIETF ifOutDiscards: número de pacotes que, mesmo sem erro, foram descartados sem ser transmitidos, por motivos como liberar espaço no buffer