PostgreSQL Server Replication Hot-StandBy
Este mini-howto de como replicar dos servidores PostgreSQL surge debido a las Charlas IRC que estan siendo dictadas en el canal IRC del Linux User Group MENdoza (Lugmen irc://irc.freenode.net/lugmen). Cuando se me pregunto si estaba interesado en dar una charla me parecio interesante tocar el tema de PostgreSQL debido al desconocimiento general sobre las capacidades de este motor de base de datos Objeto-Relacional, que poco tiene que envidiarle a los monstruos propietarios (Informix, Oracle, etc).
PostgreSQL es un sistema Open Source bajo la licencia PostgreSQL License. Libre de uso y modificación.
Que es PostgreSQL ?
- Queries Complejos
- Foreign Keys
- Triggers
- Views
- Integridad transaccional
- Control de concurrencia
Y el motor lo podemos extender a nuestro gusto y placer de varias formas:
- Creando nuevos “Data Types”
- Creando nuestras propias funciones
- Operadores
- Métodos de indexación
- Lenguajes propios de procedimientos almacenados (Store Procedures)
- Extensiones en C (Shared libreries)
El post se va a centrar en replicación pero antes es necesario explicar un poco el funcionamiento de PostgreSQL y algunos terminos importantes
TableSpace: Es un contenedor de base de datos, cuando se crea un tablespace se le especifica la ubicacion dentro del filesystem del sistema operativo (Basicamente un directorio)
Cluster: Es una instancia de un servidor PostgreSql que contiene tablespaces y que escucha en determinado puerto. En una misma maquina se pueden tener varios clusters corriendo a la vez.
WAL o Write-Ahead Logging: Es un metodo estandar para asegurar la integridad de los datos. Todos los cambios a los archivos de datos solo son escritos en disco luego de que han sido logueados en un medio de almacenamiento permanente.
Esto ultimo permite que si el servidor se cae cuando se estaban escribiendo los datos en los archivos de datos, se puede recuperar desde los archivos WAL. Es muy similar a los Logical Logs que utilizan otros motores.
Para el almacenamiento de archivos PostgreSQL se basa en el filesystem donde esta hosteado (http://www.postgresql.org/docs/9.0/interactive/storage-file-layout.html). Dentro del cluster (/var/lib/postgresql/<version>/data) se encuentran los archivos de configuración y los logs.
La caracteristica que vamos a ver es Hot-Standby replication que es una funcion nueva en PostgreSQL 9.0 (PostgreSQL 8.3 solo soporta stand-by replication)
Replication
Vamos a ver dos tipos de replicacion
Warm-StandBy: Permite tener un servidor con los mismos datos que el servidor principal, el mismo se esta replicando constantemente y esta esperando a que lo activemos como primario
En este tipo de replicación NO podemos acceder al servidor secundario, osea que no podemos consultar los datos contenidos en el mismo.
Hot-Standby: Se basa en mantener un servidor secundario replicado con el servidor principal. Pero se permiten conexiones y hacer consulta de datos al servidor secundario
Este tipo de replicación es muy util para sistemas en los que se utiliza mucho procesamiento para la emision de reportes. Entonces podemos tener un servidor para insertar y modificar datos y 1 o mas servidores para realizar consultas y reportes
Lo primero que hay que tener en cuenta para replicar PostgreSQL es que todas las maquinas que participen en la replicación tienen que tener la misma arquitectura
ej: Ambos servidores deben ser Intel/Amd (x86) de 64 bits. No se podria mezclar un servidor de 32 bits con uno de 64.
Lo primero que debemos hacer para lograr la replicación es llevar el servidor secundario a un estado lo mas cercano posible al servidor primario.
Esto se realiza copiando el cluster completo de una maquina a otra. Esto incluye el archivo de configuración, por lo que segun el caso pueden ser necesarios algunos cambios en los archivos de configuración.
Aqui hay que tener en cuenta que copiar un cluster que este online va a resultar en un cluster duplicado inconsistente esto es debido a que mientras copiamos el cluster los archivos del mismo seguramente cambiaran.
El tema de la inconsistencia del cluster que acabamos de copiar lo podemos solucionar con los archivos WALs.
PostgreSQL genera segmentos Wals de 16 MB o cada ciertos intervalos de tiempo (Todo configurable), si almacenamos todos los segmentos Wals que se generaron mientras copiabamos el cluster (osea todos los cambios que se hicieron en los datos), podemos reproducir los mismos en el cluster inconsistente hasta llevarlo al ultimo punto consistente.
Este metodo es el mas usado para la realización de backups, ya que un dump de una base de datos grande demora mucho tiempo en ser recuperado.
WAL Archiving / Backup Inicial / Warm-StandBy
Para realizar este tipo de copiado de cluster en caliente necesitamos activar “WAL archiving” en el cluster primario.
Para ello en el archivo de configuracion (postgresql.conf) debemos habilitar el parametro archive_mode
archive_mode = on
Esto indica que se realizara el guardado de los segmentos WALs, adicionalmente debemos setear archive_command,este ultimo es el comando que se ejecutara cada vez que se tenga un nuevo segmento wal.
archive_command = "cp -i %p /mnt/server/archivedir/%f"
si se fijan estoy pasando como parametro %p y %f
%p es la ubicación del archivo Wal que se genero y %f es el nombre del mismo
Aqui lo que estamos haciendo es copiar los segmentos wals al directorio /mnt/server/archivedir/. Esto podria ser un mountpoint NFS por red, asi podriamos estar enviando los segmentos cuando se general al servidor secundario. Tambien podria usarse SCP para copiar los archivos, en este ultimo hay que tener en cuenta de generar las ssh-keys.
Esto es todo lo necesario desde el lado del servidor principal por ahora.
Ahora en el servidor Secundario para reprocesar archivos WALs hay que setear el cluster secundario en recovery mode. Para ello simplemente creamos un archivo recovery.conf con el siguiente contenido:
standby_mode = 'on' restore_command = 'cp /path/to/archive/%f $p' trigger_file = '/path/to/trigger_file'
standby_mode = ‘on’ permite que el motor se quede esperando nuevos segmentos WALs hasta que encuentre el trigger_file
restore_command es el comando a ejecutarse cada ve que se necesite un nuevo WAL
Los archivos de los segmentos Wals tienen un nombre correlativo, postgreSQL ira recuperando todos los archivos, si el comando restore_command devuelve un valor distinto de 0 va a reintentar con ese mismo archivo hasta que este disponible
Entonces lo ideal es desde el servidor primario enviar los segmentos Wals al servidor secundario y en este colocar como restore_command un simple ‘cp /path/to/archive/%f $p’ aca el significado de %f y %p es el mismo que comentamos anteriormente.
Una vez que tenemos todo configurado, debemos indicar al cluster primario que se va a realizar un backup, esto permite marcar un punto de inicio y un punto de fin para obtener consistencia.
Esto se realiza ejecutando una consulta sql (funcion de postgresql) en el cluster primario:
echo "SELECT pg_start_backup('lugmen');" | pgsql -U postgres
Esto lo que hace es generar un flush de todos los Wals actuales a disco y marca el “punto de inicio” del copiado de datos.
Luego simplemente copiamos todos los archivos del cluster primario al cluster secundario
scp -rp /path/cluster_primario user@host:/path/cluster_secundario
Puede ser SCP, NFS, o lo que fuera, inclusive con un disco usb.
Mientras se realiza el copiado de los archivos, todos los segmentos wals tienen que estar siendo almacenados y copiados al servidor secundario, una vez que termina el copiado ejecutamos:
echo "SELECT pg_stop_backup();" | pgsql -U postgres
Con esto indicamos que se ha terminado y se marca el “punto de fin” para lograr la consistencia.
Luego simplemente iniciamos el cluster secundario y automaticamente (gracias al archivo recovery.conf) comenzara a procesar los archivos WALs hasta llegar a un punto consistente, aunque asi cuando llegue al punto consistente el servidor secundario, debido a “standby_mode = on“, continuara levantando nuevos archivos Wals que detecte en el directorio.
En modo recovery el motor de base de datos no permite conexiones, si queremos “levantar” el servidor para poder hacer consultas debemos crear el trigger_file. Cuando se detecta la existencia de este archivo, se levanta el motor en el ultimo punto consistente que se tiene.
Con esto logramos que el cluster secundario este replicado con el cluster primario. Efectivamente existe un atraso debido a que hay que esperar a que el cluster principal genere un nuevo segmento WAL. Estos tiempos son controlables gracias al parametro de configuracion: archive_timeout. Con el podemos especificar cada cuantos segundos queremos que se guarde un segmento Wal.
Si el parametro archive_timeout esta en 0 (Por defecto), significa que no se generaran archivos wals hasta que no se llenen los 16 MB que ocupa un segmento Wal. Este valor debera ser configurado teniendo en cuenta el retardo de datos que queremos tener (Tiempo maximo de perdida de datos) y el ancho de banda disponible para el copiado de los segmentos.
Hot-StandBy Replication
Ahora vamos a ver la nueva caracteristica de PostgreSQL que permite disminuir este tiempo a menos de 1 segundo gracias a streaming replication
A partir de la version 9.0 PostgreSQL incorpora la posibilidad de realizar el envio de WALs mediante un stream de datos. Esto permite tener el cluster secundario actualizado mucho mas rapido (Debajo de 1 segundo).
Para permitir a los clusters secundarios conectarse al cluster primario, debemos configurar la siguiente entrada en el archivo pg_hba.conf del servidor primario.
host replication replicationuser 192.168.1.110/32 md5
aca doy acceso a “replication” al usuario “replicationuser” desde la ip 192.168.1.110 mediante autenticacion md5
El usuario replication es un superuser que debemos crear en el cluster primario:
echo "CREATE ROLE replicationuser LOGIN WITH PASSWORD 'replication' SUPERUSER INHERIT CREATEDB CREATEROLE;" | pgsql -U postgres
Ahora debemos ir al archivo de configuracion del servidor principal y debemos indicar cuantos segmentos Wals mantendremos para el envio a los clusters secundarios y ademas cuantos clusters secundarios estaran conectados:
El primer parametro es max_wal_senders donde indicamos cuantos servidores secundarios se conectaran para replicarse, luego tenemos wal_keep_segments que indica la cantidad de segmentos que se guardaran para ser enviados a los clusters secundarios
Este parametro es importante ya que permite que ante una caida del enlace de comunicaciones, cuando se retoma la replicacion, el servidor secundario pueda sincronizarse nuevamente. Mientras mas grande el numero mas tiempo puede estar caida la comunicacion entre los servidores con el inconveniente de que ocupa mucho mas espacio en disco.
Con esto tendriamos configurado el servidor primario, ahora pasamos al secundario donde debemos configurar la conexion de replicación en el archivo recovery.conf
primary_conninfo = 'host=192.168.1.144 port=5432 user=replicationuser password=replication'
Aca simplemente le especificamos el string de conexion para la replicación, en el ejemplo el servidor principal esta en la ip 192.168.1.144.
Al tener primary_conninfo, cuando no se encuentran mas segmentos Wals en archivo (Exit code 1), el cluster secundario realiza una conexion al servidor primario y comienza a recibir un stream de informacion WAL.
En este punto podriamos tener un servidor StandBy replicado con un retardo de menos de un segundo (depende de la capacidad del servidor secundario y del enlace de comunicaciones)
Antes de levantar el motor secundario, vamos activar el modo Hot-standBy para que se nos permita hacer selects en el cluster secundario
En el servidor principal es necesario cambiar el parametro wal_level a “hot_standby”
En el servidor secundario debemos habilitar el parametro “hot_standby = on”
En este punto podemos levantar el servidor secundario y este deberia sincronizarse con el primario.
En el archivo de logs del servidor primario deberiamos ver:
2010-12-03 20:16:10 UTC LOG: entering standby mode
Con esto nos indica que el motor va a quedar en standby mode
2010-12-03 20:16:10 UTC LOG: consistent recovery state reached at 1E0/2A8984F8
Nos informa de la ultima transaccion consistente que posee.
2010-12-03 20:16:10 UTC LOG: database system is ready to accept read only connections
Aca indica que el parametro hot_standby esta en ‘on’
2010-12-03 20:16:10 UTC LOG: streaming replication successfully connected to primary
Indica que se pudo conectar con el servidor primario para realizar la replicación binaria por streaming.
En este punto ya podemos realizar consultas en ambos servidores. Si probamos hacer un insert en el servidor primario veremos como se espeja en el secundario. el tiempo que tarda en replicarse es imperceptible (menos de 1 segundo).
Tener en cuenta que al crear nuevos tablespaces o agregar funciones linkeadas a librerias externas (Shared Libraries) en el servidor secundario deben existir las librerias y los directorios de los tablespaces.