Caso de éxito · Plataforma de analítica confidencial, Norteamérica

Rendimiento de ingesta 10 veces mayor en un pipeline de analítica en PostgreSQL con tablas UNLOGGED

Cómo UnlockLive usó tablas UNLOGGED de PostgreSQL, ingesta COPY por lotes y un patrón disciplinado de dos tablas para llevar un pipeline de analítica de alto volumen de 8K a 80K eventos/seg — sin perder las garantías de integridad de datos que exigía la ruta auditada.

  • SectorDatos / Analítica
  • Año2024
  • PaísEE. UU.
  • Duración3 meses
10x Ingest Throughput on a PostgreSQL Analytics Pipeline Using UNLOGGED Tables hero screenshot

Resultados de un vistazo

  • 10xRendimiento de ingesta sostenido (de 8K a más de 80K eventos/s)
  • 60%Menor costo de IOPS de RDS en la misma clase de instancia
  • <50msLatencia p95 de inserción de la etapa 1 bajo carga sostenida
  • 0Regresiones de integridad de datos en la ruta de reportes auditada

El reto

Una plataforma de analítica ingería eventos de producto de una base de clientes en crecimiento en una única tabla "raw_events". El esquema original era correcto pero lento: cada evento llegaba a una tabla con registro y siete índices, el WAL era el cuello de botella y el rendimiento de ingesta se había estancado en unos 8,000 eventos por segundo. Las IOPS de RDS eran la partida de costo dominante, y una expansión prevista de clientes de 3 veces iba a romper el pipeline antes de firmar el siguiente contrato.

El equipo había leído los consejos habituales — "use una cola", "fragmente la tabla", "pase a una TSDB dedicada" — pero todas esas respuestas implicaban una migración de varios trimestres. La verdadera pregunta era: ¿puede PostgreSQL seguir el ritmo si dejamos de pelear con él? La dificultad era un requisito estricto: todo lo que llegara a las tablas de informes auditados debía ser duradero, consistente e indexado. No podíamos sacrificar la integridad en el lado de analítica para salvar el lado de ingesta.

Nuestra solución

Dividimos el pipeline en dos etapas claramente separadas con dos contratos de durabilidad distintos.

Etapa 1 (ingesta): una tabla de staging UNLOGGED que recibe el torrente de datos. Las tablas UNLOGGED de PostgreSQL omiten las escrituras WAL en las inserciones, lo cual es justo la compensación adecuada para datos de staging de corta vida — obtenemos de 5 a 10 veces más rendimiento de inserción bruta a cambio de perder las filas en staging si el servidor se cae. Combinado con COPY por lotes (no INSERT) desde un servicio de ingesta en Python y una regla deliberada de "sin índices en la tabla de staging", la ingesta bruta pasó de 8K a más de 80K eventos/seg en la misma instancia RDS.

Etapa 2 (duradera): un worker de Celery vacía la tabla de staging en microlotes hacia la tabla real `events`, con registro completo e índices, dentro de una única transacción con upserts idempotentes. La ruta de informes auditados solo lee de la tabla duradera. Si el servidor se cae durante la ingesta, perdemos como máximo unos segundos de eventos en tránsito de la tabla de staging — y los productores originales reintentan, de modo que la tabla duradera converge de nuevo a lo correcto.

Lo complementamos con una capa operativa pequeña pero cuidadosa: un panel de Grafana para la tasa de llenado de la etapa 1, una alerta crítica si el drenador se retrasa, rotación de particiones en la tabla duradera y un runbook escrito para los tres modos de fallo que importan.

  • Tabla de staging UNLOGGED sin índices — diseñada específicamente para el rendimiento de inserción bruta
  • Ingesta COPY por lotes desde un servicio Python/FastAPI, no INSERT fila por fila
  • Drenador Celery que mueve microlotes a la tabla de eventos duradera y totalmente indexada
  • Upserts idempotentes (ON CONFLICT DO NOTHING) para que los reintentos de los productores sean seguros
  • Particionado mensual en la tabla duradera para acotar el trabajo de vacuum e índices
  • Paneles y alertas de latencia de extremo a extremo en Grafana / Datadog
  • Runbook escrito que cubre la conmutación por error de RDS, la caída del drenador y la contrapresión de los productores
  • Aprobación de auditoría del perfil de durabilidad antes del lanzamiento — sin sorpresas

Cómo lo construimos

  1. 01

    Identificación del verdadero cuello de botella

    Antes de tocar el esquema dedicamos una semana a pg_stat_statements, RDS Performance Insights y un rastreador personalizado del throughput de WAL. Los datos fueron inequívocos: las escrituras de WAL y el mantenimiento de índices en la única tabla de eventos voluminosa representaban el 78 % del tiempo de escritura. El problema no eran la CPU ni la memoria, sino la durabilidad.

  2. 02

    Diseño del contrato de dos tablas

    Redactamos un breve documento de diseño que definía exactamente qué nos aportaba UNLOGGED, qué nos costaba y qué garantías debían ofrecer los productores upstream (entrega al menos una vez, ID de evento idempotentes). El contrato hizo explícito el perfil de pérdida para que el equipo de auditoría pudiera aprobarlo de antemano: "puede perder hasta N segundos de eventos en staging en una conmutación por error de RDS; la tabla durable no se ve afectada."

  3. 03

    COPY por lotes y drenador en microlotes

    Reemplazamos las inserciones fila a fila por un servicio de ingesta en Python que almacena eventos en memoria hasta 250 ms y los vuelca mediante PostgreSQL COPY a la tabla de staging UNLOGGED. Un drainer de Celery traslada micro-lotes de 5000 filas a la tabla durable dentro de una única transacción con ON CONFLICT DO NOTHING para la idempotencia.

  4. 04

    Operaciones, particionado y runbook

    Añadimos particionado mensual a la tabla durable (para que el vacuum y la reconstrucción de índices sigan siendo baratos), paneles de Grafana para el retraso de extremo a extremo, alertas sobre el llenado de staging y el retraso del drainer, y un runbook escrito que cubre los tres modos de fallo reales: caída del drainer, conmutación por error de RDS y contrapresión del productor. Lo entregamos al equipo de guardia del cliente con acompañamiento.

Stack tecnológico

  • PostgreSQL 16
  • Python
  • FastAPI
  • Celery
  • Redis
  • AWS RDS
  • AWS S3
  • Grafana
  • Datadog
  • Ingeniería de rendimiento backend
  • Python y FastAPI
  • Soluciones en la nube
  • Arquitectura de bases de datos
“Esperábamos dedicar un trimestre a migrar a una base de datos de series temporales dedicada. En cambio, UnlockLive nos mostró cómo hacer que Postgres cumpla esa función, y nuestros auditores aprobaron el nuevo diseño antes de lanzarlo.”
Director de Ingeniería de Datos · Plataforma de analítica (nombre confidencial)

Preguntas frecuentes

¿Son seguras las tablas UNLOGGED de PostgreSQL en producción?

Sí, para el trabajo adecuado. Las tablas UNLOGGED omiten las escrituras en el WAL, lo que ofrece un rendimiento de inserción bruto de 5 a 10 veces mayor a cambio de un perfil de pérdida documentado: las filas se descartan ante una caída del servidor y no se replican. Son ideales para datos de staging de corta vida cuando un sistema aguas arriba puede reproducir los eventos. Son pésimas para cualquier cosa que necesite releer de forma fiable. Siempre las combinamos con una tabla duradera y con registro de la que realmente lee la ruta auditada.

¿Por qué no usar simplemente una base de datos de series temporales dedicada como TimescaleDB o ClickHouse?

Porque el costo de migración y la superficie operativa son reales. Si su equipo ya opera bien PostgreSQL y su objetivo de rendimiento es de decenas de miles de eventos por segundo, el patrón UNLOGGED + COPY por lotes suele llevarle allí en semanas en lugar de trimestres. Recomendamos una TSDB dedicada cuando la carga de trabajo realmente necesita almacenamiento columnar, índices particionados por tiempo o consultas de rango en milisegundos a escala.

¿Puedo añadir índices a una tabla de staging UNLOGGED de PostgreSQL?

Puede, pero casi no debería. El objetivo de la capa de staging es la velocidad de inserción bruta; cada índice que agrega cuesta rendimiento de ingesta. Mantenemos la tabla de staging sin índices y ponemos todos los índices en la tabla duradera aguas abajo sobre la que realmente se ejecutan las consultas analíticas.

¿Cómo garantizan que no haya pérdida de datos al usar tablas UNLOGGED en un pipeline?

Dos reglas. Primero, los productores aguas arriba deben ofrecer entrega al menos una vez con IDs de evento idempotentes para que los reintentos sean seguros. Segundo, el lado duradero del pipeline solo lee de la tabla aguas abajo con registro completo, nunca de la tabla de staging UNLOGGED. El peor caso se reduce a unos segundos de eventos de staging reproducibles ante una caída, nunca a un reporte perdido.

¿Qué rendimiento de ingesta se puede lograr con una sola instancia de PostgreSQL usando este patrón?

Depende del tamaño de las filas, la red y la clase de instancia, pero en una modesta AWS RDS db.r6g.xlarge con este patrón exacto de dos tablas vemos de forma habitual entre 60 000 y 100 000 eventos por segundo sostenidos, con latencia de inserción de la etapa 1 en p95 por debajo de 50 ms. Más allá de eso, particionaríamos la tabla de staging o escalaríamos horizontalmente con un enrutador de escritura.

¿Quiere un resultado como este?

Hable con el mismo equipo que construyó Rendimiento de ingesta 10 veces mayor en un pipeline de analítica en PostgreSQL con tablas UNLOGGED. Definiremos el alcance de su proyecto, le daremos una propuesta a precio fijo y le mostraremos el caso más parecido de nuestro portafolio.

Reservar una llamada estratégica