Caso de estudio · Sistemas distribuidos
Frequency capping para los anuncios de Pluto TV: reglas, cuotas y 24 horas de impresiones
Un sistema basado en reglas, en producción, que evita que los espectadores vean el mismo anuncio una y otra vez entre cortes, construido sobre Kafka para unos 6k eventos de impresión por segundo con 10x de margen.
- Producto
- pluto.tv ↗
- Cliente
- Pluto TV
- Industria
- Streaming gratuito con publicidad (FAST)
- Rol
- Tech Lead · Diseñador de la solución
- Período
- 2021 – 2024
- Live
- en producción en Pluto TV
- 24 h
- de impresiones por dispositivo
- ~6k/s
- eventos de impresión
- 10x
- margen sobre el peor caso
Deslizá hacia el costado para ver el diagrama completo →
Contexto
Ver el mismo anuncio una y otra vez en el mismo corte o en la misma hora es una mala experiencia: la gente se desconecta cuando siente que le martillan el mismo mensaje. Pluto TV ya detectaba duplicados dentro de un mismo corte, pero no entre cortes.
El desafío
Extender la deduplicación entre cortes con un frequency cap propio (el mismo anuncio como máximo X veces cada Y minutos por espectador), configurable con reglas de negocio, decidido en el momento del corte sobre el camino de entrega y alimentado por los eventos de impresión de todos los dispositivos a escala de producción.
La solución
Dos caminos desacoplados alrededor de un almacenamiento compartido. El camino de escritura ingiere los eventos de anuncios vistos por Kafka, guarda 24 horas de impresiones por dispositivo y actualiza los contadores de cuota por regla. El camino de lectura, donde el servicio de ad pods llena los cortes desde FreeWheel, le pide a un servicio adSelection las cuotas restantes de cada dispositivo, y las calcula a partir de las reglas en el momento si todavía no hay contadores.
Reglas con prevalencia
Reglas genéricas (repetición por creatividad, marca e industria) y específicas por marca o creatividad, incluido OFF. Las específicas le ganan a las genéricas, y la creatividad le gana a la marca, que le gana a la industria.
Historial de impresiones de 24 horas
Una entrada por anuncio visto y por dispositivo, con fingerprint, marca e industria, guardada en Redis durante 24 horas.
Contadores de cuota con ventana deslizante
Cada impresión abre una ventana por regla y dimensión aplicable; solo cuentan contra el límite las impresiones cuya ventana sigue abierta.
Servicio adSelection
Encapsula la decisión: devuelve las cuotas restantes de un dispositivo en el momento absoluto del corte, para que el servicio de ad pods pueda filtrar las creatividades.
Camino de escritura por eventos
Una API ad-beacon publica eventos NEW_IMPRESSION en Kafka; consumers independientes insertan el historial, actualizan cuotas y limpian ventanas vencidas.
Decisiones clave
- 01
Decidir en el momento absoluto del corte
Si un anuncio está permitido depende de qué impresiones siguen dentro de su ventana cuando se reproduce el corte, no cuando se pidió. El mismo historial puede permitir un anuncio a las 9:00 y bloquearlo a las 8:30.
- 02
Reglas como datos, con prevalencia explícita
Operaciones de ads necesitaba ajustar la repetición sin deploys. Modelar las reglas por tipo (genéricas, específicas) y dimensión (creatividad, marca, industria) con un orden de prevalencia claro mantuvo el comportamiento predecible.
Alternativas evaluadas Límites fijos en código por campaña.
- 03
Precalcular cuotas, con fallback a reglas
El camino de entrega lee contadores precalculados para ser rápido; cuando un dispositivo todavía no tiene contadores, adSelection evalúa las reglas en el momento en lugar de bloquear el corte.
- 04
Desacoplado mediante Kafka
Los servicios solo conocen el stream de eventos, no se conocen entre sí. Ingesta, historial, cuotas y limpieza escalan y fallan de forma independiente, y el diseño sigue siendo agnóstico de la nube.
- 05
Dimensionado para 10x
La capacidad se planificó con seis meses de métricas de producción en el peor caso: unos 6k requests de impresión por segundo en el beacon, 12k mensajes por segundo en Kafka y unos 120 GB de historial de impresiones, con la exigencia de que la implementación soportara diez veces esos valores.
Qué hice
- Diseñé la solución: modelo de reglas, prevalencia, cuotas con ventana deslizante y la decisión en el momento del corte.
- Diseñé la arquitectura: caminos de lectura y escritura desacoplados, almacenamiento y eventos en Kafka.
- Dimensioné el sistema a partir de métricas de producción, con margen de 10x.
- Lideré la implementación como Tech Lead, del design review a producción.
Resultados
- En producción: frequency caps aplicados en todos los cortes que ve un espectador.
- Deduplicación extendida de un solo corte a 24 horas de impresiones por dispositivo.
- Un camino de escritura construido para unos 6k requests de impresión y 12k mensajes de Kafka por segundo.
- Capacidad planificada para diez veces la carga de producción en el peor caso.
- Repetición controlada por reglas de negocio que operaciones de ads puede cambiar sin deploys.