Guzmán D. Darío Senior Python Developer Español Hire me
Taller autoguiado

De bloqueante a tiempo real: un pipeline de video multi-cámara con asyncio

Paso 18 de 23
Paso 18 de 23

Observabilidad: qué te dice una cola

Tu pipeline funciona, escala y se apaga bien. Falta lo que separa un sistema que corre de uno que puedes operar: saber, en cualquier momento, dónde está el cuello de botella.

Y la buena noticia es que ya construiste el instrumento sin darte cuenta. Las colas te lo dicen.

Tres estados y tres diagnósticos

La longitud de una cola no es un número decorativo: es la relación entre quien produce y quien consume, medida en tiempo real. Solo hay tres casos.

Casi vacía. El consumidor va más rápido que el productor y le sobra capacidad. La cola casi nunca acumula nada. Si esto pasa en todas tus colas, tienes margen de sobra.

Estable a media altura. Producción y consumo van igualados. Es el estado sano de un sistema bien dimensionado: hay un colchón para absorber picos, pero no crece.

Siempre al máximo. El consumidor no da abasto. La cola vive llena y el productor o espera o descarta. Ahí está tu cuello de botella, sin ambigüedad.

Las tres lecturas de una cola. La primera casi vacía, la segunda estable a media altura, la tercera pegada al tope: esa última es la que señala el cuello de botella.
Las tres lecturas de una cola. La primera casi vacía, la segunda estable a media altura, la tercera pegada al tope: esa última es la que señala el cuello de botella.

Analogía · El fregadero

Abre el grifo y mira el fregadero. Si el agua baja tan rápido como entra, no se acumula nada: el desagüe puede con todo.

Si el nivel sube hasta el borde y se queda ahí, el desagüe no da abasto. Y fíjate en lo que ese nivel te dice: no necesitas medir el desagüe ni desarmar la tubería. El nivel del agua ya te señaló el problema.

Una cola llena es exactamente eso.

Verlo en vivo

Agrega este monitor a pipeline.py y lánzalo como una tarea más en main.py, junto a los trabajadores:

pipeline.py python
async def monitor(infer_q, publish_q, stats, every=1.0):
    last = dict(stats)
    while True:
        await asyncio.sleep(every)
        now = dict(stats)
        rates = {k: (now[k] - last[k]) / every for k in now}
        last = now
        print(f"infer={infer_q.qsize():3d}  publish={publish_q.qsize():3d}    "
              f"read={rates['read']:6.1f}/s  inferred={rates['inferred']:6.1f}/s  "
              f"dropped={rates['dropped']:6.1f}/s")

Levanta los servicios con muchas cámaras y arranca el pipeline:

terminal 1 bash
python services.py --fake --cameras 64
terminal 2 bash
INFER_WORKERS=16 python main.py
salida text
infer= 32  publish=  0    read=1520.0/s  inferred= 118.0/s  dropped=1402.0/s
infer= 32  publish=  1    read=1498.0/s  inferred= 121.0/s  dropped=1377.0/s

Lee esa salida como un diagnóstico médico, de izquierda a derecha:

infer= 32, y el maxsize de esa cola es justamente 32. No baja de ahí. La cola de inferencia vive llena: el cuello de botella está en el modelo.

publish= 0 o 1. La cola de publicación está casi siempre vacía, así que la etapa de publicación va sobrada y no es el problema.

dropped sigue el ritmo de read. Como la primera cola está llena, casi todo lo que entra se descarta. Coherente con lo anterior.

Con dos números por segundo sabes exactamente dónde invertir: no en optimizar la publicación, no en leer más rápido las cámaras, sino en darle más capacidad al modelo. Que es lo que hiciste en el paso 13 subiendo MODEL_THREADS.

Checkpoint · Sin abrir un profiler

Deberías estar viendo la primera cola pegada a su tope y la segunda casi vacía. Ahora repite el experimento del paso 13: para los servicios y vuelve a levantarlos con MODEL_THREADS=16.

Mira cómo cambia la primera columna. Esa es la diferencia entre adivinar y medir.

Por qué esto es mejor que un profiler

Un profiler te dice en qué funciones se va el tiempo dentro de tu proceso. Pero en este pipeline tu proceso casi no hace nada: espera sockets. Un profiler te diría que te pasas la vida en select o en epoll, que es cierto y completamente inútil.

Las colas, en cambio, miden lo que de verdad importa en un sistema de etapas: el desequilibrio entre ellas. Y funcionan igual si el cuello de botella está en otra máquina, en un servicio ajeno o en la red.

Ojo

Instrumenta tus colas desde el primer día, no cuando ya tengas un problema. Son tres líneas de código y te ahorran tardes enteras de suposiciones. Y si vas a mandar métricas a algún sitio, la longitud de cada cola es el primer número que deberías exportar.

Checkpoint

Con esto termina el pipeline. Tienes ingesta concurrente, inferencia fuera del proceso, colas con política explícita, aislamiento de fallos, apagado ordenado y diagnóstico en vivo.

Lo que viene son cuatro capítulos bonus: conectar fuentes de video reales, y ver qué forma toma todo esto cuando pasas a cientos de streams.