Como implementar pontualidade no QUIC sem Datagram
(quic.video)- 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
- Se você usar UDP diretamente para criar um protocolo de transporte, no mínimo precisará das seguintes funções
- Para criar um protocolo melhor, você também precisará destes recursos
- Para elevar o nível de maturidade, também é preciso considerar ambiente operacional e implantação
- Protocolos de vídeo ao vivo como WebRTC, SRT, Sye e RIST são exemplos construídos sobre UDP
- Isso leva à conclusão de que é melhor usar uma biblioteca QUIC do que criar um novo protocolo do zero
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 QUIC oferece suporte a datagramas por meio de uma extensão
- O WebTransport exige suporte a datagramas
- A versão mais recente do MoQ adiciona suporte a datagramas
- A próxima versão do MoQ deverá exigir 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
Comentários do Hacker News
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
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
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
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
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
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
“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
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
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
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
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
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
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
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
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
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
o texto também cita jogos e vídeo ao vivo como exemplos apropriados para UDP
ele apresenta primeiro a “noção comum” e depois a rebate
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
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
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”
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
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