Cómo lograr oportunidad en QUIC sin usar Datagram
(quic.video)- En video en vivo y conversaciones por internet, lo importante no es la “entrega no confiable” en sí, sino descartar los datos viejos y entregar los más recientes a tiempo
- Si un router no descarta los paquetes congestionados y en cambio los acumula mucho tiempo en cola, aparece el bufferbloat, que en servicios en tiempo real puede causar una latencia peor que el buffering
- Si se construye un protocolo directamente sobre UDP, hay que volver a implementar retransmisión, control de congestión, cifrado, estimación de RTT, validación de ruta y control de flujo, entre otras cosas, así que es más seguro usar una biblioteca de QUIC
- Solo con QUIC ya se puede lograr oportunidad sin datagramas combinando control de congestión basado en latencia, separación independiente de streams y priorización
- Los estándares de QUIC, WebTransport y MoQ incluyen soporte para datagramas, pero la conclusión es que conviene más ajustarse al flujo de Media over QUIC que volver a montar un nuevo protocolo de video sobre UDP
La meta no es la “inestabilidad”, sino la oportunidad
- La elección entre TCP y UDP suele explicarse como “entrega confiable” frente a “entrega no confiable”, pero eso no significa que la aplicación quiera inestabilidad como tal
- En video en vivo o conversaciones por internet, suele ser más importante que llegue antes el dato más reciente que recibir todos los datos viejos
- En una conversación en tiempo real hay que evitar situaciones como ver un spinner de buffering sobre la cara de alguien o escuchar una voz de hace 5 segundos
- La industria del video en vivo y la del gaming suelen usar datagramas UDP en lugar de streams TCP para lograr esa oportunidad
Datagramas y colas de red
- Un datagrama es un sobre de 0 y 1 que va de una dirección de origen a una de destino, y por lo general se considera que 1200 bytes es un tamaño seguro
- Un datagrama puede perderse silenciosamente y también puede llegar fuera de orden
- En la capa física, los datos se convierten en señales analógicas para atravesar el medio, y pueden ocurrir serialización, deserialización, buffering, encolado, retransmisión, descarte, corrupción, demora, reordenamiento, duplicación y pérdida
- Cuando entra demasiada información a la red, los routers no descartan bits arbitrarios, sino datos en los límites de los paquetes
Bufferbloat y control de congestión
- Si el router no descarta los paquetes de inmediato y en cambio los acumula en cola, aparece el bufferbloat
- El bufferbloat puede retrasar todos los paquetes durante varios segundos, creando el peor escenario posible para la entrega en tiempo real
- Para evitar el encolado, hay que estimar la cola del router a partir de la retroalimentación del tiempo de llegada de los paquetes, y el emisor debe reducir su tasa de envío para vaciarla
- Esta área corresponde al control de congestión, y enviar paquetes a velocidad ilimitada puede terminar en un desastre
Lo que hay que asumir si se construye directo sobre UDP
- Si se usa UDP directamente para crear un protocolo de transporte, como mínimo se necesitan estas funciones
- Para construir un protocolo mejor, también hacen falta estas capacidades
- Para elevar el nivel de madurez, también hay que considerar el entorno operativo y el despliegue
- Protocolos de video en vivo como WebRTC, SRT, Sye y RIST son ejemplos construidos sobre UDP
- Esto lleva a la conclusión de que conviene más usar una biblioteca de QUIC que crear un protocolo nuevo desde cero
Cómo lograr oportunidad con streams de QUIC
- La forma de alcanzar oportunidad en QUIC puede resumirse en tres puntos
- Evitar la inflación del buffer: un control de congestión basado en latencia como BBR detecta el encolado y reduce la tasa de envío
- El transport-wide-cc de WebRTC puede verse como un ejemplo de una mejor aproximación
- Separación de streams: los bytes dentro de cada stream mantienen orden y se entregan de forma confiable, y cada stream puede representar una unidad atómica como un frame de video, una actualización de juego, un mensaje de chat o un blob JSON
- Priorización de streams: como los streams son independientes, pueden llegar sin relación de orden entre sí, y se puede indicar al stack de QUIC que entregue antes los streams importantes
- Los streams de baja prioridad pueden quedar hambrientos, y para evitar desperdiciar ancho de banda se pueden cerrar
- Este enfoque es el núcleo de Media over QUIC
- La naturaleza fire-and-forget de los datagramas solo encaja cuando se necesita latencia en tiempo real; fuera de eso, se pueden usar streams de QUIC
Compromisos y excepciones alrededor de los datagramas
- QUIC y los estándares relacionados también incluyen soporte para datagramas
- QUIC ofrece soporte de datagramas mediante una extensión
- WebTransport exige soporte para datagramas
- La versión más reciente de MoQ agrega soporte para datagramas
- La próxima versión de MoQ probablemente exigirá soporte para datagramas
- El soporte para datagramas puede incluirse porque su implementación es trivial y permite experimentar
- OPUS incorpora soporte de FEC, así que sirve como ejemplo de un caso en el que MoQ admite enviar cada “frame” de audio como datagrama
- El protocolo antiguo DNS puede tratarse como una excepción, pero en diseños nuevos se considera preferible seguir una dirección como DNS over HTTPS
- La conclusión es que, en vez de volver a construir un nuevo protocolo de video sobre UDP, es mejor sumarse a Media over QUIC
1 comentarios
Opiniones de Hacker News
Por ejemplo, en un entorno como NB-IoT, donde en el peor caso la latencia de ida y vuelta es de 10 segundos, se desperdicia tiempo de ida y vuelta en el handshake y el descubrimiento de MTU; además, intenta seguir transmitiendo datos que ya no sirven, y si la cobertura empeora y aumenta la latencia, TCP lo interpreta como pérdida de paquetes por congestión y reduce el ancho de banda
También un load balancer o un middlebox puede cortar la conexión pensando “no hubo respuesta durante 4 segundos, así que habrá desaparecido”, y también es una pena que TCP divida los paquetes sin considerar la estructura de los datos, por lo que no se pueden interpretar hasta recibirlos completos
En algunos casos eso es útil, pero muchas veces se puede aprovechar el n+1 aunque el n todavía no esté
En transferencias de archivos grandes se podría manejar automáticamente una pérdida de paquetes del 5% con códigos de borrado, o usar fountain codes y seguir enviando hasta que el receptor diga “ya recibí todo”
Los fountain codes son la forma en que las sondas del espacio profundo envían datos, y la latencia hasta Júpiter o Marte es bastante seria
Hay que terminar el handshake de TCP para poder iniciar el handshake de TLS, pero QUIC tiene soporte a nivel de protocolo para manejar la negociación TLS dentro del handshake inicial
Parecería más elegante poder combinar de forma laxa el protocolo de red y el cifrado, pero en un mundo donde casi todo el transporte ya va cifrado, la ventaja práctica de ahorrar un tiempo de ida y vuelta por conexión parece mayor
En R&D hicimos un sistema nuevo que usa QUIC y resolvió la mayor parte del problema de llegadas fuera de orden, pero como los sensores de terceros que tenemos que soportar directamente, sin adaptadores, solo pueden usar UDP, seguimos usando datagramas UDP para todo
La expresión más común y mejor es best-effort: UDP hace el mejor intento por entregar datagramas, solo que los datagramas pueden descartarse
Eso no significa que UDP sea inherentemente no confiable
https://en.wikipedia.org/wiki/Best-effort_delivery
En realidad no significa que se hará todo lo posible para enviar un mensaje de A a B, sino algo más cercano a “se intentó”
Si un router en la ruta está congestionado, o si por un flap de enlace se genera un agujero negro de unos 50 ms antes de una reruta rápida, termina siendo “bueno, lo intenté”
En cambio, la entrega confiable de TCP reintenta varias veces y ofrece a la aplicación un stream de datos en orden
reliable/unreliable también pueden ser malos términos, pero es difícil decir que best-effort sea mejor
Los sistemas no confiables funcionan muy bien en un 95% y también son buenos para el throughput bruto, pero el último 5% muchas veces marca una diferencia enorme
“Esfuerzo” normalmente implica cierta persistencia ante la dificultad, pero descartar paquetes porque hay problemas de recursos difícilmente puede llamarse esfuerzo, y mucho menos best effort
En terminología legal y de negocios, “best efforts” es más débil que un compromiso definitivo, pero no significa lavarse las manos abiertamente; en redes, su uso es bastante distinto
Por separado, los checksums de UDP y TCP tampoco garantizan muy bien la integridad cuando se entrega un datagrama; son apenas algo mejores que el hardware
Dicho eso, best-effort da la impresión de que se hace algún esfuerzo para garantizar la entrega, cuando en realidad simplemente se descarta un paquete que parece raro o que tuvo la mala suerte de encontrarse con un buffer lleno
Me gusta lossy, pero esto cae en el problema de nombres de “solo hay dos problemas difíciles”
Si los paquetes tienen que llegar, usa TCP; si no importa demasiado, usa UDP
Es una explicación simplificada, pero best effort es un término tonto, no hay ningún esfuerzo ahí
El control de congestión claramente es necesario, pero fuera de eso tengo muchas dudas
En un mundo priorizando los datagramas, no habría habido problemas para agrupar varios enlaces de datos de forma muy eficiente, o para hacer roaming cruzando fronteras de red sin cortar la conexión
Muchas aplicaciones pueden manejar frames fuera de orden sin costo adicional, y si se escriben ajustándose al modelo UDP podrían ser mucho más rápidas
En la práctica, pasar a un transporte menos confiable no hace automáticamente que el software sea más confiable ni más eficiente
Más bien, aumentan mucho los modos de falla y la complejidad que el equipo tiene que manejar
Pero si hay un cuello de botella estrecho en algún punto de la conexión, no parece tener mucho sentido generar una enorme cantidad de paquetes que de todos modos se van a descartar en ese cuello de botella
Los sitios web, el audio y el video por lo general no encajan bien con frames fuera de orden, y la mayoría no quiere cortes en el audio o el video
Algunos videojuegos pueden ignorar paquetes faltantes, pero esos casos ya están escritos con UDP
La idea es que, como esos paquetes no se van a retransmitir, es una forma efectiva de reducir el tráfico excedente
Ahora hay protocolos sobre UDP que retransmiten de forma agresiva, y me pregunto cómo cambió eso la situación
También recuerdo que hace unos años QUIC tuvo problemas de retransmisión frente a HTTP/1 y HTTP/2 por este motivo
Si se puede encontrar una frase más representativa en el artículo, se puede volver a cambiar
Esto sigue la guía de títulos de HN: “usar el título original, salvo cuando sea engañoso o sensacionalista”: https://news.ycombinator.com/newsguidelines.html
Según la aplicación, puede tener sentido
Por ejemplo, en un juego multijugador en tiempo real, si el procesamiento se queda atrás, los elementos atrasados ya no importan porque el estado del juego ya cambió
En aplicaciones de trading de alta velocidad, en ciertas situaciones también importa solo el dato de mercado más reciente, no lo que pasó hace 100 ms
El artículo también pone como ejemplos adecuados para UDP los juegos y el video en vivo
La estructura es presentar primero la “creencia común” y luego refutarla
Por ejemplo, entran ahí DHCP, SLAAC, UPnP, mDNS, tinc y BitTorrent como descubrimiento local; el broadcast como streaming en redes locales; y WireGuard, IPSec, OpenVPN y VLAN como encapsulación
No solo la retransmisión, sino incluso el buffering para reordenar paquetes aumenta la latencia, así que es preferible tolerar las pérdidas mediante corrección de errores u ocultamiento de pérdida de paquetes
UDP y TCP tienen comportamientos y compromisos distintos, y todo se reduce a entenderlos antes de elegir según el caso de uso
No hace falta hacer de guardián con frases tipo “nunca hagas X”
Solo con ver el título queda bastante claro que no es un texto que intente impedirte usar UDP como guardián
De hecho, al final del artículo el autor propone usar QUIC, que está basado en UDP
Claro que tendrás que encargarte personalmente de muchos más detalles
Además, es una buena forma de aprender los aspectos de bajo nivel de las redes