Cómo hacer que Postgres sea lento
(byteofdev.com)- Introducción a un enfoque experimental sobre combinaciones de parámetros que pueden degradar drásticamente el rendimiento de Postgres
- En general, se ajustan a la inversa varios factores como caché, índices, WAL e I/O
- Al manipular de forma extrema shared_buffers, autovacuum y opciones relacionadas con WAL, se logró una caída de TPS de 42,000 veces
- También se aplicaron funciones recientes como io_method e io_workers de las nuevas versiones Postgres 18/19 para forzar una limitación a un solo hilo de I/O
- Los resultados demuestran que solo con el archivo de configuración de Postgres es posible provocar una degradación extrema del rendimiento
Resumen general
Este artículo presenta un experimento que, en vez de enfocarse en optimizar Postgres para hacerlo más rápido, busca exclusivamente hacerlo más lento, llevando el rendimiento al límite mediante cambios únicamente en distintos valores de configuración de PostgreSQL.
La prueba se basó en la carga TPC-C de BenchBase (128 almacenes, 100 conexiones, cada una intentando hasta 10,000 transacciones por segundo, Postgres 19devel reciente, Ryzen 7950x, 32GB de RAM, SSD de 2TB, durante 120 segundos).
Con la configuración base, el rendimiento fue de 7082 TPS, y se observó paso a paso cuánto se degradaba al manipular cada parámetro.
Reducir drásticamente el caché
- Postgres utiliza un caché potente (shared_buffers) para reducir el I/O de disco
- Al bajar shared_buffers a 8MB desde el valor base (10GB), el TPS cayó a cerca de 1/7 (1052 TPS)
- Se observó que la tasa de aciertos de caché bajó de 99.90% a 70.52%, y que las llamadas al sistema de lectura aumentaron más de 300 veces
- Se intentó reducirlo hasta 128kB, pero Postgres solo permitió un mínimo de aproximadamente 2MB, lo que produjo una caída adicional hasta 485 TPS
Aumentar las tareas en segundo plano (ajuste de autovacuum)
- Se llevaron al mínimo todos los umbrales relacionados con autovacuum, haciendo que vacuum se ejecutara casi en cada operación
- combinación de
autovacuum_vacuum_insert_threshold=1,autovacuum_naptime=1, etc. - vacuum se repetía prácticamente cada segundo incluso cuando en la práctica no tenía trabajo que hacer
- combinación de
- En este proceso también se redujo maintenance_work_mem a 128kB y se activó todo el logging de autovacuum
- Como resultado, el TPS cayó a 293 (menos de 1/20 del original)
- A través de los logs en tiempo real de autovacuum, se confirmó que la causa de la degradación eran las tareas en segundo plano excesivamente frecuentes
Empeorar al máximo las escrituras de WAL (Write-Ahead Log)
- Todos los parámetros relacionados con WAL se ajustaron al peor escenario posible
wal_writer_flush_after=0,wal_writer_delay=1,wal_sync_method=open_datasync, etc.- se forzaron checkpoints cada 30 segundos y se mantuvieron
min_wal_size/max_wal_size=32MBal mínimo wal_level=logical,wal_log_hints=on, haciendo que incluso se registrara información innecesaria en WAL- también se activó carga adicional como
track_wal_io_timing,summarize_wal
- Como resultado, el TPS cayó hasta 98 (menos de 1/70 del original)
- En los logs se observaron comportamientos anómalos, como checkpoints repitiéndose cada pocos cientos de ms
Eliminar el efecto de los índices
- Se configuró el uso de índices para que siempre se calculara con el costo máximo posible (
random_page_cost=1e300,cpu_index_tuple_cost=1e300), invalidando de hecho los índices - Se aumentó
shared_buffersa 8MB (para asegurar estabilidad) y el TPS cayó hasta 0.87 (logrando una ralentización de 7,000 veces)
Forzar I/O de un solo hilo
- Se aprovecharon funciones recientes de Postgres 18+
- Con
io_method=worker,io_workers=1, se forzó que todo el I/O pasara por un solo hilo worker - El TPS cayó aún más, hasta 0.016 (42,000 veces más lento)
- En la prueba de 100 conexiones durante 120 segundos, el rendimiento quedó tan limitado que solo se completaron 11 transacciones
Conclusión y guía de reproducción
- Se demuestra que con solo 32 manipulaciones de parámetros es posible llevar una DB en producción prácticamente a un estado de "parálisis"
- Es posible maximizar la degradación del rendimiento tocando únicamente la configuración de
postgresql.conf - Quienes quieran reproducir el experimento deben consultar BenchBase Postgres, el entorno TPC-C indicado arriba y la lista completa de configuraciones
- No se incluyen algunos parámetros adicionales ni otros intentos extra por hacerlo aún más lento
Lista resumida de parámetros
shared_buffers = 8MB- umbrales/
scale_factorrelacionados con autovacuum: minimizados a 0~1 - costos, memoria y logs relacionados con vacuum: minimizados y maximizados según corresponda
- opciones de sync/flush/logging/nivel relacionadas con WAL: mantenidas en modo lento
random_page_cost,cpu_index_tuple_costde índices: establecidos en1e300io_method = worker,io_workers = 1- para otros valores detallados, consultar la lista del cuerpo principal
Cierre
- Solo con el archivo
postgresql.confse puede provocar una degradación de rendimiento extrema - En la práctica, vale la pena tomar esta combinación como referencia en sentido inverso (para mejorar el rendimiento de forma eficiente)
- El artículo cierra mencionando que el autor interrumpió el experimento por dolor de espalda
2 comentarios
Opiniones de Hacker News
Excelente. Me encanta este tipo de enfoque.