Calentando motores con pgFincore

Tema: 

Hoy pase toda la mañana ayudando a un cliente con un problema que ya le estaba causando dolores de cabeza. Cada vez que por algún motivo (por ejemplo mantenimiento) debe apagar el servidor al arrancar trabaja desesperantemente lento y tarda casi una hora en empezar a trabajar normalmente.

¿Por qué? La respuesta es bastante obvia: la cache esta vacía. Aclaremos un poco la idea; la información de la base de datos esta en el disco pero como el disco es casi siempre la parte mas lenta de casi cualquier sistema, cuando se lee algo del disco se graba en memoria (primero en shared buffers y cuando sale de ahí va a parar a la RAM controlada por el SO), esa memoria que se usa para guardar páginas de disco que podríamos volver a necesitar la llamamos "cache".

Volviendo al punto cuando reiniciamos la maquina ambas "cache" (la del SO y la de postgres, shared buffers) están vacías lo que obliga a leer toda la información del disco. Si tenemos mucha concurrencia, ahora tendremos un gran problema: un montón de consultas queriendo leer el disco.

¿Qué hacer?
Bueno en el caso del cliente del que hable antes el debía esperar una hora antes de que sus consultas empezarán a responderse en un tiempo razonable.

Una solución mejor consiste en usar una herramienta llamada pgFincore, la cual provee funciones para cargar a memoria del SO las páginas de disco de una tabla o índice que le indiquemos. Por ejemplo select * from pgfadvise_willneed('pgbench_accounts'); cargará a memoria las páginas de disco de la tabla pgbench_accounts.

Pero antes de que vayan corriendo a querer usar esa función para subir todas sus tablas a memoria, deténganse un momento a pensar en si es realmente eso lo que quieren hacer. Por ejemplo, si tu base de datos no entra en memoria todo lo que conseguirás es que las últimas que subiste saquen a alguna de las primeras que subiste. ¿Te imaginas que esa tabla histórica gigantesca que nunca consultas saque de la memoria a esas otras tablas que subiste primero y que son el corazón de tus consultas?

Lo correcto no es subir datos al azar. Una alternativa sería usar la función pgfincore() para guardar un snapshot de que tenía en memoria para luego restaurar al mismo estado al reiniciar.


CREATE TABLE pgfincore_snapshot AS
SELECT relname, (pgfincore(oid)).*, now() as date_snapshot
FROM pg_class
WHERE relkind in ('i', 'r');

Y luego restauras el snapshot con la función pgfadvise_loader() (la correcta manera de usarla le queda de ejercicio al lector).

Claro que esto solo carga al cache del sistema operativo. Sin embargo, Robert Haas mostro hace unos días una implementación de una herramienta (pg_prewarm) para subir tablas/índices a shared buffers.

En todo caso, a calentar motores y que sigan esas consultas salvajes...

Comentarios