한국어English日本語简体中文繁體中文DeutschไทยTiếng ViệtРусскийPortuguês (Brasil)EspañolBahasa Indonesia

Guia do Lag em Jogos › L8 Sockets e protocolos

Algoritmo de Nagle + ACK atrasado Nagle + delayed ACK (TCP_NODELAY off)

ID da causa sk-nagle · Responsável principal Desenvolvimento do servidor (Equipe de desenvolvimento) · Também envolvidos Desenvolvimento do cliente (Equipe de desenvolvimento)

Abrir o card interativo, com figuras e simulações →

O algoritmo de Nagle, que junta pacotes pequenos antes de enviar, e o ACK atrasado, que demora para mandar o ACK, se combinam, e cada mensagem escrita em partes atrasa 40–200 ms.

Por quê Mensagens pequenas escritas em partes sem ligar o TCP_NODELAY → Efeito Quem envia espera o ACK, e quem recebe atrasa o ACK → Na tela Ping da conexão baixo, mas todas as ações demoram por igual: input lag

Sintomas
Input lag
Fatores
Latência
Quem é afetado
Servidor inteiro, Só eu
Quando
Sempre, Ao fazer ações específicas
Responsável
Responsável principal Desenvolvimento do servidor (Equipe de desenvolvimento) · Também envolvidos Desenvolvimento do cliente (Equipe de desenvolvimento)
O que fazer (Equipe de desenvolvimento)
Servidor: ligar o TCP_NODELAY, juntar as mensagens de um tick e escrever tudo de uma vez, não contar com formas de desligar o ACK atrasado do lado de quem recebe (o TCP_QUICKACK do Linux dura pouco, e no Windows é preciso mudar o registro em cada PC), porque o jogo não tem controle garantido sobre elas. Cliente: ligar o TCP_NODELAY, juntar as mensagens de um frame e escrever tudo de uma vez.
Números de referência
No Linux, o ACK atrasado costuma ser de 40 ms (até 200 ms, conforme a situação). No Windows, versões antigas usavam 200 ms e as atuais usam 40 ms (o template padrão do Windows Server 2019 usa 40 ms). Como o ACK atrasado é definido pelo SO de quem recebe, se o servidor envia mensagens em partes com o Nagle ligado, o atraso pode ser de 40–200 ms, dependendo do PC que recebe.
No gráfico
Sempre alto desde o início · Tempo de resposta das ações (RTT no jogo)
Onde olhar
Ver o intervalo entre pedido e resposta numa captura de pacotes do lado do servidor (tcpdump ou Wireshark) e conferir se o código do servidor e do cliente liga o TCP_NODELAY
Confirma se
Ping da conexão baixo, mas lacunas de cerca de 40 ms (200 ms em versões antigas do Windows) se repetem entre pacotes pequenos e terminam logo depois que chega o ACK do outro lado. Somem ao ligar o TCP_NODELAY
Descarta se
Intervalo de resposta parecido com o ping da conexão: não é esta causa. Servidor do jogo demorando para gerar a resposta: processamento no servidor (“Acúmulo na fila de mensagens”)
Como verificar
Ferramentas de infra (sem precisar do código do jogo)

Fontes

  1. RFC 9293: Transmission Control Protocol (TCP) IETF
    O Nagle segura dados pequenos enquanto houver dados sem ACK; deve ser possível desligá-lo por conexão; o ACK atrasado deve ser menor que 0,5 s; o problema da combinação dos dois
  2. include/net/tcp.h (Linux v6.12) Linux kernel
    ACK atrasado do Linux com mínimo TCP_DELACK_MIN (HZ/25 = 40 ms) e máximo TCP_DELACK_MAX (HZ/5 = 200 ms)
  3. TCP improvements in the Windows network stack (IETF 98 TCPM) Microsoft
    O timeout padrão do ACK atrasado no Windows passou a ser 40 ms (apresentado em 2017)
  4. TCP Templates for Windows Server 2019 – How to tune your Windows Server Transports (Advanced users only 😉) Microsoft
    Template do Server 2019: DelayedAckTimeout 40 ms, MaxSynRetransmissions 2, InitialRto 3000 ms
  5. Design issues - Sending small data segments over TCP with Winsock Microsoft
    No TCP antigo do Windows, ao receber dados, arma-se um timer de ACK atrasado de 200 ms, e o Nagle vem ligado por padrão, então pacotes pequenos esperam o ACK; a solução é o TCP_NODELAY

Veja também

Mesma camada: L8 Sockets e protocolos

Mesmo sintoma (Input lag) em outras camadas

Ver o card interativo, com figuras e simulações