sql >> Base de Datos >  >> RDS >> PostgreSQL

Utilizando pg_prewarm y pg_hibernator de contrib de almacenamiento en caché en PostgreSQL 9.4.

Numerosos DBA (contándome a mí), hacen preguntas todo el tiempo a los piratas informáticos/desarrolladores/arquitectos de PostgreSQL en la lista de correo:

  • P1. ¿PG tiene la capacidad de almacenar en caché/calentar una relación?
  • P2. ¿Es posible volver al estado anterior de la memoria caché donde estaba antes de cerrar el servidor de la base de datos debido al mantenimiento?

En versiones anteriores de PostgreSQL, no había posibilidad de calentar una relación o almacenar estados de caché, pero desde PostgreSQL 9.4 en adelante, cada una de las consultas anteriores (Q1, Q2) se aborda con dos módulos de contribución pg_prewarm y pg_hibernator . A pesar del hecho de que son distintivos en la practicidad, sin embargo, la combinación parece ser extremadamente viable y útil en el futuro para los DBA. En resumen sobre las contribuciones:

pg_precalentamiento contrib (Autor:Robert Haas), proporciona la capacidad de cargar datos de una relación en el caché del búfer del sistema operativo o en el caché del búfer del PG. Tiene la funcionalidad de primer o último número de bloque para precalentar. (Nota:no tiene protección especial en los datos precalentados contra el desalojo del caché y también si la instancia de la base de datos se reinicia, entonces es necesario volver a calentar las relaciones).

pg_hibernator contrib (Autor:Gurjeet Singh), proporciona la capacidad de guardar automáticamente la lista de contenidos de búfer compartidos en el disco al cerrar la base de datos y restaurar automáticamente los búferes al iniciar la base de datos, de la misma manera que guardar/restaurar una instantánea de shared_buffers. Utiliza el módulo PG 9.3 para registrar el "proceso de trabajo en segundo plano" y genera dos procesos "Ahorro de búfer", "Lector de búfer" para guardar/restaurar. Curiosamente, con un pequeño truco, pg_hibernator también puede permitir que el esclavo en espera comience a atender consultas a toda velocidad con el mismo contenido del maestro, lo verá en un minuto :).

Por último, necesitamos pg_buffercache módulo para mirar dentro del contenido actual de Shared_buffers de PostgreSQL. Este módulo ayuda a comprender qué porcentaje de búfer está ocupado por una relación.

Pongamos todas estas contribuciones en juego y veamos cómo cumplen el propósito de dos preguntas (Q1, Q2). Voy a usar una tabla 'foo' de 885 MB de tamaño en mi VM local, junto con una consulta pg_buffercache estándar.

SELECT c.relname,
count(*) AS buffers
FROM pg_class c
INNER JOIN pg_buffercache b ON b.relfilenode=c.relfilenode AND c.relname='foo'
INNER JOIN pg_database d ON (b.reldatabase=d.oid AND d.datname=current_database())
GROUP BY c.relname
ORDER BY 2 DESC LIMIT 10;

Uso de pg_prewarm contrib y calentamiento de la tabla 'foo'.

postgres=# create extension pg_prewarm;
CREATE EXTENSION
postgres=# dt+
List of relations
Schema | Name | Type | Owner | Size | Description
--------+------+-------+----------+--------+-------------
public | foo | table | postgres | 885 MB |
(1 row)
postgres=# select pg_prewarm('foo');
pg_prewarm
------------
113278
(1 row)
--pg_buffercache query output
relname | buffers
---------+---------
foo | 113278
(1 row)

Uso muy simple y directo de pg_prewarm con una salida de bloques calentado en shared_buffers para la relación 'foo'. Desde pg_buffercache resultado de la consulta, podemos evaluar que hay 113278 (113278 * 8/1024 =884 MB) búferes de tamaño de bloque de 8 KB de relación 'foo' que coincide con la salida pg_prewarm. Aquí, si el servidor de Postgres se reinicia por algún motivo, los búferes compartidos están vacíos y el DBA necesita volver a calentarse para volver a la etapa de calentamiento anterior. Para una sola mesa, volver a calentar siempre es simple, excepto para un grupo de mesas, es una agonía.

En este punto, podemos hacer uso de pg_hibernator contrib, porque tiene la flexibilidad de guardar el contenido de shared_buffer y restaurarlo al inicio. Habilitemos pg_hibernator/pg_prewarm juntos y ejecutemos un ejercicio similar simplemente incluyendo un paso de reinicio y veamos si el estado del caché regresa como está o no. No voy a cubrir la instalación de pg_hibernator, porque en git está muy bien descrito, sin embargo, saltaría directamente a la parte de implementación e iniciaría el servidor con pg_hibernator.

postgres 24623     1  0 02:06 pts/4    00:00:00 /usr/local/pgpatch/pg/bin/postgres -D /usr/local/pgpatch/pg/data_10407
postgres 24627 24623 0 02:06 ? 00:00:00 postgres: logger process
postgres 24631 24623 0 02:06 ? 00:00:00 postgres: checkpointer process
postgres 24632 24623 0 02:06 ? 00:00:00 postgres: writer process
postgres 24633 24623 0 02:06 ? 00:00:00 postgres: wal writer process
postgres 24634 24623 0 02:06 ? 00:00:00 postgres: autovacuum launcher process
postgres 24635 24623 0 02:06 ? 00:00:00 postgres: archiver process
postgres 24636 24623 0 02:06 ? 00:00:00 postgres: stats collector process
postgres 24637 24623 0 02:06 ? 00:00:00 postgres: bgworker: Buffer Saver
postgres 24638 24623 11 02:06 ? 00:00:01 postgres: bgworker: Block Reader 2

In database server logs at startup time:

-bash-4.1$ more postgresql-2014-06-02_083033.log
LOG: database system was shut down at 2014-06-02 08:13:00 PDT
LOG: starting background worker process "Buffer Saver"
LOG: database system is ready to accept connections
LOG: autovacuum launcher started

Dado que es la primera vez que pg_hibernator está en juego, puede ver dos procesos y también registros con información sobre el inicio de "Ahorro de búfer". Ahora, precalentemos la relación 'foo' y reiniciemos el servidor, luego verifiquemos el estado del búfer si pg_hibernator llenó el búfer donde lo dejó.

-bash-4.1$ psql -p 10407
psql (9.4beta1)
Type "help" for help.

postgres=# select pg_prewarm('foo');
pg_prewarm
------------
113278
(1 row)

--pg_buffercache query output
relname | buffers
---------+---------
foo | 113278
(1 row)
postgres=# q

-bash-4.1$ /usr/local/pgpatch/pg/bin/pg_ctl -D /usr/local/pgpatch/pg/data_10407 stop
waiting for server to shut down.... done
server stopped

-bash-4.1$ ls -l $PGDATA/pg_hibernator/
total 12
-rw------- 1 postgres postgres 160 Jun 3 01:41 1.global.save
-rw------- 1 postgres postgres 915 Jun 3 01:41 2.postgres.save

-bash-4.1$ /usr/local/pgpatch/pg/bin/pg_ctl -D /usr/local/pgpatch/pg/data_10407 start
server starting

Hemos reiniciado el servidor de la base de datos, examinemos los registros

-bash-4.1$ more postgresql-2014-06-03_020601.log
LOG: database system was shut down at 2014-06-03 02:05:57 PDT
LOG: starting background worker process "Buffer Saver"
LOG: database system is ready to accept connections
LOG: autovacuum launcher started
LOG: registering background worker "Block Reader 2"
LOG: starting background worker process "Block Reader 2"
LOG: Block Reader 2: restored 113433 blocks
LOG: Block Reader 2: all blocks read successfully
LOG: worker process: Block Reader 2 (PID 24638) exited with exit code 1
LOG: unregistering background worker "Block Reader 2"
LOG: registering background worker "Block Reader 1"
LOG: starting background worker process "Block Reader 1"
LOG: Block Reader 1: restored 20 blocks
LOG: Block Reader 1: all blocks read successfully
LOG: worker process: Block Reader 1 (PID 24664) exited with exit code 1
LOG: unregistering background worker "Block Reader 1"

Entonces, "Buffer Reader" ha restaurado bloques de 113433 + 20, de los cuales 113278 pertenecen a la relación 'foo'. Genial, conectemos y veamos.

-bash-4.1$ psql -p 10407
psql (9.4beta1)
Type "help" for help.

--pg_buffercache query output
relname | buffers
---------+---------
foo | 113278
(1 row)

Genial... pg_hibernator ha recuperado el estado de caché sin la interferencia del DBA.

Otra cosa buena de pg_hibernator es que un standby recién creado puede tener el mismo contenido de búfer compartido que el maestro, de modo que el standby puede comenzar a atender consultas a toda velocidad. Para hacer este ejercicio, mientras tomaba una copia de seguridad del directorio $PGDATA, pasé SIGTERM al proceso "Ahorro de búfer" para que escriba el contenido de shared_buffers del estado actual en el disco ($PGDATA/pg_hibernator directorio) y luego seguí con la configuración en espera.

postgres 24637 24623  0 02:06 ?        00:00:00 postgres: bgworker: Buffer Saver
postgres 24653 15179 0 02:06 ? 00:00:01 postgres: wal receiver process streaming 1/6A000A10
postgres 24654 24623 0 02:06 ? 00:00:00 postgres: wal sender process postgres ::1(65011) streaming 1/6A000A10

Después de la configuración, mi esclavo comenzó con el mismo contenido que el principal

-bash-4.1$ psql -p 10477
psql (9.4beta1)
Type "help" for help.

postgres=# select pg_is_in_recovery();
pg_is_in_recovery
-------------------
t
(1 row)

--pg_buffercache query output
relname | buffers
---------+---------
foo | 113278
(1 row)

Gracias a ambos autores por una extensión maravillosa sobre el almacenamiento en caché.