Streaming a miles: arquitectura para eventos de vídeo en directo a gran escala
En una entrada anterior defendíamos que una "videollamada" puede significar mucho más que una reunión en cuanto pasa a formar parte de un proceso de negocio real. Este caso lleva esa idea todavía más lejos: una plataforma en la que la parte de videollamada apenas importa, y el verdadero problema de ingeniería es la distribución a escala.
La forma del problema
Algunos eventos en directo (webinars, lanzamientos de producto, townhalls, espectáculos en directo) tienen un número reducido de presentadores activos, hablando de verdad y con la cámara encendida, y una gran cantidad de gente al otro lado de la pantalla, consumiendo el contenido pero participando por chat; la misma forma básica que un stream de Twitch o de YouTube Live, sobre una interfaz web a medida construida específicamente para un cliente (ese front-end no lo construimos nosotros, así que no es de lo que trata esta entrada).
El tamaño de la audiencia en un evento así es realmente impredecible. Una sesión pequeña puede atraer a una docena de espectadores; una bien promocionada puede atraer a miles. Y cada evento está acotado en el tiempo: intenso durante una hora o dos, y luego nada hasta el siguiente.
Latencia contra coste: el verdadero compromiso
A la hora de llegar a una audiencia grande hay dos opciones reales.
- Tiempo real completo. Varias empresas ya ofrecen WebRTC a gran escala, videollamadas con miles de participantes, o servidores de medios sobre los que construir una aplicación a medida. Es realmente en tiempo real, pero implica mantener una sesión en directo por cada espectador. (Contáctanos si ese es el compromiso que necesita tu caso.)
- Distribución por HLS. El stream llega una vez a una caché de borde (edge cache), y los espectadores tiran de ella en lugar de mantener cada uno su propia sesión con el origen. A cambio de algo de latencia (normalmente entre unos pocos segundos y unos treinta), para la mayoría de la distribución de medios a gran escala es la opción con mejor relación coste/eficiencia, y es lo que usan realmente las herramientas de webinar, Twitch y YouTube Live, y lo que usamos nosotros también, para este caso concreto.
Cómo encajan realmente las piezas
El mecanismo de fondo es, en sí mismo, bastante sencillo: los presentadores mantienen una videollamada WebRTC pequeña y corriente entre ellos. Un observador silencioso (la misma idea de "participante invisible" de la que ya hemos hablado antes, se une a esa llamada para capturar su salida compuesta, que después se trocea (chunking) casi en tiempo real para su distribución por HLS al resto.
Esa parte es lo básico. El problema realmente difícil es ejecutar muchas de estas sesiones de forma concurrente, cada una con su propio ciclo de vida específico de aplicación completo: levantar la llamada de los presentadores, el observador y el pipeline de chunking a la vez cuando empieza un evento, y desmontarlo todo de forma limpia cuando termina, para cuantos eventos estén corriendo a la vez. Ese es el problema que resuelve de verdad nuestra arquitectura.
Qué construimos
El resultado es lo que ahora llamamos ERTSA, nuestra Elastic Real-Time Serverless Architecture: cómputo que solo existe mientras un evento está realmente en marcha. AWS Lambda orquesta warm pools de EC2 para levantar, bajo demanda, un conjunto dedicado y efímero de nodos (la llamada, el observador, el pipeline de chunking) para cada evento, y lo desmonta todo de forma limpia cuando termina. Sin una flota inactiva dimensionada para el peor caso; sin planificación manual de capacidad por evento.
El resultado
El resultado es un sistema en el que cada sesión, webinar, stream o lo que sea, tiene un coste predecible. El procesamiento en el servidor es indiferente al número de espectadores, y casi indiferente al número de presentadores: un pico en el tamaño de la audiencia no toca para nada el cómputo de la sesión. La variable real es el coste de red, y es exactamente lo que el chunking para HLS y una buena gestión de caché reducen de forma notable frente a una sesión WebRTC.
ERTSA añade aislamiento sobre eso: cada sesión corre en su propio entorno, de forma que un pico en el número de sesiones concurrentes no afecta a la latencia ni al funcionamiento de ninguna de ellas, nuevas o ya en marcha.
Hasta dónde podría llegar esto con más experiencia en medios
Nuestro foco en este proyecto fue la arquitectura en sí, la capa de distribución, no las funcionalidades de cara al usuario que abre. Un par de ellas merece la pena nombrarlas aquí, porque son un paso natural siguiente una vez que esa fontanería de base es sólida, no un hueco en lo que ya existe.
Incorporar a un espectador a la llamada. Ahora mismo, la audiencia solo puede ver. Pero no hay ninguna razón técnica por la que un presentador o un administrador no pudiera elegir a alguien del chat o de la lista de espectadores e invitarlo directamente a la pequeña videollamada WebRTC, convirtiendo a un espectador pasivo en un participante activo por un momento. Es un tipo de evento bastante más interactivo, y una extensión natural de la arquitectura ya descrita.
Eventos sincronizados con el vídeo, no con el reloj. Imagina que un presentador lanza algo sensible al tiempo en mitad del directo, una promoción o una llamada a la acción. Lanzarlo en ese instante, por hora de sistema, hace que los espectadores lo vean en puntos muy distintos de su propia reproducción, porque la latencia de HLS es variable por naturaleza. El enfoque más justo es anclar el disparo a la posición local de cada espectador en la línea temporal del vídeo en lugar de al reloj, de forma que todos vivan ese momento en el mismo punto de lo que están viendo, sin importar lo retrasado que vaya su propio stream.
La parte difícil de verdad no es disparar el evento de forma justa, es recoger y ordenar de forma justa lo que los espectadores hacen en respuesta. Si un evento premia, por ejemplo, a los diez primeros en responder, ordenar por el instante de llegada en bruto al servidor simplemente premia a quien haya tenido la menor latencia, no a quien realmente haya reaccionado más rápido: alguien viéndolo con más retraso podría haber reaccionado en la mitad de tiempo. Hacerlo bien significa medir cada respuesta en relación con el momento en que ese espectador concreto recibió el disparo en su propio stream, no por cuándo llega la respuesta al servidor; una cola relativa, no una simple. Genuinamente más difícil de lo que parece, pero resoluble, no imposible.
Un patrón familiar, por una razón distinta
Merece la pena detenerse en esto: nadie pidió un "participante invisible" en este caso de uso; no aparece en ningún requisito. Aparece de todos modos, porque es sencillamente lo que necesita la arquitectura elegida (una presencia silenciosa en la sala para capturar lo que se trocea hacia la audiencia), no una funcionalidad que nadie pidiera expresamente. El mismo patrón que hay detrás de la auditoría sin presencia reaparece aquí por una razón completamente distinta: no es compliance, es fontanería. Eso suele ser una buena señal de que estás ante una pieza arquitectónica genuina y no ante una funcionalidad puntual: aparece por sí sola, por motivos que no tienen nada que ver entre sí.