1 pontos por GN⁺ 2024-06-25 | 1 comentários | Compartilhar no WhatsApp
  • Em vídeo ao vivo e conversas pela internet, o importante não é a “entrega não confiável” em si, mas sim descartar dados antigos e entregar os dados mais recentes no tempo certo
  • Se o roteador não descarta pacotes congestionados e os deixa acumulados na fila por muito tempo, ocorre bufferbloat, o que pode causar uma latência pior do que buffering em serviços em tempo real
  • Se você criar um protocolo diretamente sobre UDP, precisará reimplementar retransmissão, controle de congestionamento, criptografia, estimativa de RTT, validação de caminho, controle de fluxo etc., então é mais seguro usar uma biblioteca QUIC
  • Mesmo só com QUIC, é possível criar pontualidade sem datagramas combinando controle de congestionamento baseado em latência, separação independente de streams e priorização
  • Os padrões QUIC, WebTransport e MoQ incluem suporte a datagramas, mas a conclusão é que é melhor seguir o fluxo de Media over QUIC do que empilhar novamente um novo protocolo de vídeo sobre UDP

O objetivo não é “não confiabilidade”, e sim pontualidade

  • A escolha entre TCP e UDP costuma ser explicada como “entrega confiável” versus “entrega não confiável”, mas isso não significa que a aplicação queira não confiabilidade em si
  • Em vídeo ao vivo ou conversas pela internet, é mais importante que os dados mais recentes cheguem primeiro do que receber todos os dados antigos
  • Em conversas em tempo real, é preciso evitar situações como um spinner de buffering sobre o rosto da pessoa ou ouvir a voz de 5 segundos atrás
  • Os setores de vídeo ao vivo e de jogos frequentemente usam datagramas UDP em vez de streams TCP para obter essa pontualidade

Datagramas e filas de rede

  • Um datagrama é um envelope de 0s e 1s enviado de um endereço de origem para um endereço de destino, e em geral 1200 bytes é tratado como um tamanho seguro
  • Datagramas podem se perder silenciosamente e também podem chegar fora de ordem
  • Na camada física, os dados são convertidos em sinais analógicos e atravessam o meio, onde podem ocorrer serialização, desserialização, buffering, enfileiramento, retransmissão, descarte, corrupção, atraso, reordenação, duplicação e perda
  • Quando dados demais entram na rede, os roteadores descartam dados nos limites dos pacotes, e não em bits arbitrários

Bufferbloat e controle de congestionamento

  • Quando o roteador não descarta pacotes imediatamente e os acumula na fila, ocorre bufferbloat
  • O bufferbloat pode atrasar todos os pacotes por vários segundos, criando o pior cenário possível para transmissão em tempo real
  • Para evitar filas, é preciso estimar o enfileiramento do roteador com base no feedback do tempo de chegada dos pacotes, e o remetente deve reduzir a taxa de envio para esvaziar a fila
  • Essa área corresponde ao controle de congestionamento, e enviar pacotes em velocidade ilimitada pode levar ao desastre

O que você assume ao construir diretamente sobre UDP

Criando pontualidade com streams do QUIC

  • Há três formas principais de atingir pontualidade no QUIC
    • Evitar inchaço de buffer: controle de congestionamento baseado em latência, como BBR, detecta enfileiramento e reduz o volume de envio
    • O transport-wide-cc do WebRTC pode ser visto como um exemplo de abordagem melhor
    • Separação de streams: os bytes dentro de cada stream têm ordem e entrega confiável, e cada stream pode ser uma unidade atômica como um frame de vídeo, atualização de jogo, mensagem de chat ou blob JSON
    • Priorização de streams: como os streams são independentes, podem chegar sem relação de ordem entre si, e é possível instruir a pilha QUIC a entregar primeiro os streams mais importantes
    • Streams de baixa prioridade podem ficar sem recursos; para evitar desperdício de banda, eles podem ser fechados
  • Essa abordagem é o núcleo do Media over QUIC
  • A característica fire-and-forget dos datagramas só faz sentido quando a latência em tempo real é indispensável; fora isso, streams QUIC podem ser usados

Compromissos e exceções em torno dos datagramas

  • QUIC e padrões relacionados também incluem suporte a datagramas
  • O suporte a datagramas pode ser incluído porque a implementação é trivial e permite experimentação
  • O OPUS já inclui suporte a FEC, então isso vira um exemplo de MoQ suportando o envio de cada “frame” de áudio como datagrama
  • O protocolo antigo DNS pode ser tratado como exceção, mas em novos projetos a direção mais adequada seria algo como DNS over HTTPS
  • A conclusão é que, em vez de criar novamente um novo protocolo de vídeo sobre UDP, é melhor participar do Media over QUIC

1 comentários

 
GN⁺ 2024-06-25
Comentários do Hacker News
  • Os problemas do TCP aparecem muito em áreas de alta largura de banda e sensíveis à latência, como HFT ou vídeo, mas mesmo em redes de baixa largura de banda e alta latência o TCP também não é especialmente bom
    Por exemplo, em ambientes como NB-IoT, onde no pior caso a latência de ida e volta é de 10 segundos, o tempo de RTT é desperdiçado no handshake e na descoberta de MTU, ele continua tentando transmitir dados que já não têm mais utilidade, e quando a cobertura piora e a latência aumenta, o TCP interpreta isso como perda de pacotes por congestionamento e reduz a largura de banda
    Além disso, balanceadores de carga ou middleboxes podem encerrar a conexão pensando “não houve resposta por 4 segundos, então deve ter sumido”, e também é frustrante o fato de o TCP dividir os pacotes sem considerar a estrutura dos dados, o que impede a interpretação antes de receber tudo
    • O TCP assume que todos os dados chegam em ordem como um fluxo linear e, se o n-ésimo pacote não for recebido, também não mostra o pacote n+1 para a aplicação
      Em alguns casos isso é útil, mas em muitos casos é possível aproveitar o pacote n+1 mesmo sem o n-ésimo ainda
      Em transferências de arquivos grandes, é possível lidar automaticamente com 5% de perda de pacotes com codificação de apagamento, ou usar fountain code e continuar enviando até que o receptor diga “recebi tudo”
      Fountain code é a forma como sondas do espaço profundo enviam dados, e a latência até Júpiter ou Marte é bastante séria
    • Isso é ainda mais verdade com TLS, e hoje em dia TLS é praticamente o padrão nos principais casos de uso
      O handshake de TLS só pode começar depois que o handshake do TCP termina, mas o QUIC tem suporte no nível do protocolo para tratar a negociação de TLS dentro do handshake inicial
      Parece mais elegante combinar protocolo de rede e criptografia de forma mais solta, mas num mundo em que quase todo transporte já é criptografado, a vantagem prática de economizar um RTT por conexão parece maior
    • Fico pensando se hoje em dia a camada Wi‑Fi abaixo do TCP também não faz com frequência suas próprias retransmissões para perdas causadas por sinal fraco ou ruidoso
    • Fico curioso se NB-IoT ainda está sendo usado de fato hoje em dia. Lembro que foi muito promovido por um tempo, mas depois parece que sumiu do debate
  • Para streaming de dados de sensores em alta frequência, simplesmente usam datagramas UDP
    No lado de P&D, criaram um sistema novo usando QUIC e resolveram a maior parte dos problemas de chegada fora de ordem, mas como sensores de terceiros que precisam de suporte direto sem adaptadores só conseguem usar UDP, ainda usam datagramas UDP para tudo
    • Sistemas de arte midiática no mundo todo também quase sempre usam OSC sobre UDP
    • Isso me fez pensar em dados de sensores de alta frequência; fico curioso se há números de economia de energia em comparação com TCP
    • Fico curioso em que linguagem esse sistema foi feito. Parece bem legal
    • Para obter confiabilidade sobre UDP, também seria possível usar RoCE
  • Pode parecer uma implicância pequena, mas acho problemático chamar UDP de unreliable
    A forma mais comum e melhor é best-effort, e o UDP apenas tenta ao máximo entregar os datagramas, embora eles possam ser descartados
    Isso não significa que o UDP seja inerentemente não confiável
    https://en.wikipedia.org/wiki/Best-effort_delivery
    • Best-effort é uma expressão eufemística e confusa para quem está fora da área, e talvez ainda mais para falantes nativos de inglês
      Na prática, não significa que vai até o fim tentando enviar uma mensagem de A para B, mas algo mais próximo de “tentamos”
      Mesmo que os roteadores no caminho estejam congestionados ou que um link flap cause um blackhole de uns 50 ms antes de um fast reroute, ainda assim fica por isso mesmo: “bom, tentamos”
      Já a entrega confiável do TCP faz várias tentativas e fornece à aplicação um fluxo de dados em ordem
      Reliable/unreliable também pode ser uma terminologia ruim, mas é difícil dizer que best-effort seja melhor
      Sistemas não confiáveis costumam ser excelentes em uns 95% dos casos e também no throughput bruto, mas os 5% finais muitas vezes fazem uma diferença enorme
    • Em redes, best effort delivery é um termo evasivo que não melhora em nada em relação a unreliable, a ponto de poder ser abolido
      “Esforço” normalmente implica certa persistência diante de dificuldades, mas descartar pacotes porque houve problema de recurso dificilmente pode ser chamado de esforço, e menos ainda de best effort
      O uso jurídico e empresarial de “best efforts” é mais fraco que um compromisso firme, mas não significa simplesmente largar de mão, enquanto no networking o uso é bem diferente
      Separadamente, os checksums de UDP e TCP também não garantem tão bem a integridade quando o datagrama é entregue, sendo apenas um pouco melhores que o hardware
    • Eu achava que “o datagrama pode ser descartado” era exatamente o significado de unreliable, então não entendo bem que mal-entendido se está tentando evitar
    • Chamar a camada de transporte de unreliable não é uma boa forma de falar. Confiabilidade é uma propriedade do sistema, não do meio de transporte, e é possível construir um sistema não confiável com TCP e um sistema confiável com UDP
      Ainda assim, best-effort passa a impressão de que há algum esforço para garantir a entrega, quando na prática o pacote que parecer estranho ou encontrar um buffer lotado por azar é simplesmente descartado
      Gosto de lossy, mas isso entra na categoria de problemas de nomenclatura
    • Desde os anos 80 isso é chamado de unreliable transport, e de fato é isso mesmo
      Se o pacote precisa chegar, use TCP; se isso não importa tanto, use UDP
      É uma explicação simplificada, mas best effort é um termo bobo, ali não há esforço algum
  • Acho que a abstração de stream facilita demais a criação de programas frágeis, que demoram para se recuperar ou nem conseguem se recuperar quando a conexão cai, e também impõe restrições demais à camada de transporte
    Controle de congestionamento claramente é necessário, mas fora isso há muitas dúvidas
    Em um mundo orientado primeiro a datagramas, seria possível combinar vários enlaces de dados com muita eficiência ou fazer roaming atravessando fronteiras de rede sem derrubar a conexão
    Muitas aplicações conseguem lidar com quadros fora de ordem sem custo extra, e, se forem escritas de acordo com o modelo do UDP, podem ficar muito mais rápidas
    • O argumento de que o TCP é conveniente demais e por isso o software não é escrito direito perde força quando exige que se acredite que, em um mundo orientado primeiro a datagramas muito mais complexo, surgiria software perfeitamente robusto e eficiente
      Na prática, migrar para um transporte menos confiável não torna automaticamente o software mais confiável nem mais eficiente

ao contrário, os modos de falha e a complexidade que a equipe precisa lidar aumentam muito

  • em aplicações com código de correção de erros adequado, o controle de congestionamento também pode ser opcional
    ainda assim, se houver um gargalo estreito em algum ponto da conexão, não parece fazer muito sentido gerar uma quantidade enorme de pacotes que acabarão descartados nesse gargalo de qualquer forma
  • fico curioso sobre que tipo de aplicação está sendo considerada. entre os sistemas hoje normalmente feitos com TCP, o que poderia ser trocado por UDP?
    sites, áudio e vídeo em geral não combinam muito com quadros fora de ordem, e a maioria também não quer que o áudio ou o vídeo fique falhando
    alguns videogames podem ignorar pacotes perdidos, mas nesses casos eles já são feitos sobre UDP
  • um ponto pouco mencionado é que, quando há congestionamento, muitas redes descartam primeiro os pacotes UDP
    como esses pacotes não serão retransmitidos, isso é visto como uma forma eficaz de reduzir o tráfego excedente
    agora surgiram protocolos sobre UDP que retransmitem de forma agressiva, então fico curioso sobre como isso mudou a situação
    também lembro que, há alguns anos, o QUIC teve problemas de retransmissão em comparação com HTTP/1·HTTP/2 por causa disso
  • usei a própria redação do artigo para tentar mudar o título caça-cliques
    se eu encontrar no texto uma formulação mais representativa, posso mudar de novo
    isso segue a diretriz de títulos do HN: “use o título original, exceto quando for enganoso ou caça-cliques”: https://news.ycombinator.com/newsguidelines.html
  • não concordo com a premissa deste texto. UDP não existe por causa da falta de confiabilidade em si, mas como um compromisso de escolher entrega best-effort em vez de garantias, em troca de velocidade e eficiência
    dependendo da aplicação, isso faz sentido
    por exemplo, em jogos multiplayer em tempo real, se o processamento ficar para trás, os itens atrasados deixam de importar porque o estado do jogo já mudou
    em aplicações de negociação de alta frequência também pode acontecer de, em certas situações, só importar o dado de mercado mais recente, e não o que aconteceu 100 ms atrás
    • isso não é a premissa do texto, e sim uma noção comum que o autor corrige logo em seguida
      o texto também cita jogos e vídeo ao vivo como exemplos apropriados para UDP
    • se continuar lendo, o texto basicamente diz isso mesmo
      ele apresenta primeiro a “noção comum” e depois a rebate
  • coisas que realmente precisam ser baseadas em datagramas incluem descoberta local, broadcast e encapsulamento de pacotes
    por exemplo, descoberta local como DHCP, SLAAC, UPnP, mDNS, tinc e BitTorrent; broadcast como streaming em rede local; e encapsulamento como WireGuard, IPSec, OpenVPN e VLAN
    • um item que faltou é mídia em tempo real
      como retransmissão — e até mesmo apenas o buffering para reordenar pacotes — aumenta a latência, muitas vezes é melhor tolerar a perda com correção de erros ou ocultação de perda de pacotes
    • como alguém sem muito conhecimento de redes de baixo nível, tenho curiosidade de saber por que datagramas são necessários nesses casos de uso
    • jogos também entram nisso
  • o título é um caça-cliques bobo, e o próprio autor reconhece isso logo no começo
    UDP e TCP têm comportamentos e trade-offs diferentes, então a questão é apenas entendê-los antes de escolher com base no caso de uso
    não precisa desse gatekeeping no estilo “nunca faça X”
    • a menos que o asterisco antes de “never” tenha sido acrescentado nos 10 minutos entre a publicação do comentário e agora, esse asterisco claramente indica que há ressalvas
      só pelo título já fica bem claro que não é um texto tentando fazer gatekeeping para impedir o uso de UDP
      de fato, no fim do texto o autor sugere usar QUIC, que é baseado em UDP
  • a maioria das aplicações e casos de uso vai usar conexões baseadas em sessão, mas também existem usos para datagramas diretamente, então não há motivo para ter medo
    claro, você mesmo terá de cuidar de muito mais detalhes
    de quebra, também é uma boa forma de aprender os aspectos de baixo nível de redes
    • a SteamNetworkingMessages API para desenvolvimento de jogos permite usar bem essa abordagem nesse caso de uso sem precisar se preocupar com os detalhes internos