Compilación de Postgresql con la extensión de Spock para cluster Multi-master con un sólo nodo
· 20 min · linux
Introducción
En este artículo, vamos a explicar cómo compilar Postgresql con la extensión de Spock para crear un cluster Multi-master. Esta configuración es útil para aplicaciones que requieren alta disponibilidad y escalabilidad.
Requisitos previos
Para empezar deberías contar una máquina con Ubuntu 24.04 Server por ejemplo.
Repositorio de Scripts de instalación
Primeros pasos
Fichero config.sh
#!/bin/bash
PG_VERSION="17.5"
PG_VERSION_BASE="17"
SRC_DIR="/usr/local/src/postgres17-spock"
INSTALL_PREFIX="/usr/local/pgsql"
DATA_DIR="${INSTALL_PREFIX}/data"
NUM_CORES=$(nproc)
PG_CTL="${INSTALL_PREFIX}/bin/pg_ctl"
PGDATA="${DATA_DIR}"
SERVICE_FILE="/etc/systemd/system/postgresql.service"
Este fichero nos permite definir las variables que vamos a utilizar en el script de compilación e instalación.
Fichero install_postgres_spock.sh
source ./config.sh
set -euo pipefail
install_dependencies() {
echo "Instalando dependencias..."
sudo apt update
sudo apt install -y make build-essential libssl-dev zlib1g-dev libreadline-dev \
libxml2-dev libxslt-dev libkrb5-dev flex bison libxml2-utils xsltproc \
ccache pkg-config git libjansson-dev
}
# /usr/local/src/
prepare_source_dir() {
echo "Preparando directorio de código fuente..."
sudo mkdir -p "$SRC_DIR"
sudo chown "$(whoami)" "$SRC_DIR"
cd "$SRC_DIR"
}
download_postgres() {
if [ ! -f "postgresql-${PG_VERSION}.tar.gz" ]; then
echo "Descargando PostgreSQL ${PG_VERSION}..."
wget "https://ftp.postgresql.org/pub/source/v${PG_VERSION}/postgresql-${PG_VERSION}.tar.gz"
fi
}
extract_sources() {
echo "Extrayendo PostgreSQL..."
tar -xvzf "postgresql-${PG_VERSION}.tar.gz"
}
clone_spock() {
if [ ! -d "spock" ]; then
echo "Clonando Spock..."
git clone https://github.com/pgEdge/spock
fi
}
apply_patches() {
echo "Aplicando parches de Spock..."
cd "${SRC_DIR}/postgresql-${PG_VERSION}"
for patch in ../spock/patches/pg${PG_VERSION_BASE}-*.diff; do
echo "Aplicando $(basename "$patch")"
patch -p1 < "$patch"
done
}
configure_postgres() {
echo "Configurando compilación..."
./configure --prefix="$INSTALL_PREFIX" \
--with-readline --with-zlib --with-icu --with-openssl --with-libxml
}
build_and_install_postgres() {
echo "Compilando PostgreSQL..."
make -j"$NUM_CORES"
sudo make install
}
configure_path() {
echo "Añadiendo ${INSTALL_PREFIX}/bin al PATH del sistema..."
sudo tee /etc/profile.d/pgsql.sh >/dev/null <<EOF
#!/bin/sh
export PATH=${INSTALL_PREFIX}/bin:\$PATH
EOF
sudo chmod +x /etc/profile.d/pgsql.sh
source /etc/profile.d/pgsql.sh
}
create_postgres_user() {
if ! id postgres >/dev/null 2>&1; then
echo "Creando usuario postgres..."
sudo adduser --system --home /var/lib/postgresql --group --shell /bin/bash postgres
fi
}
# configurar directorio de datos de postgres
setup_data_dir() {
echo "Creando directorio de datos..."
sudo mkdir -p "$DATA_DIR"
sudo chown postgres:postgres "$DATA_DIR"
}
# inicializar el clúster
init_db_cluster() {
echo "Inicializando base de datos..."
sudo -u postgres "${INSTALL_PREFIX}/bin/initdb" -D "$DATA_DIR"
}
install_spock() {
echo "Compilando e instalando Spock..."
cd "${SRC_DIR}/spock"
cp compat${PG_VERSION_BASE}/* .
env PATH="${INSTALL_PREFIX}/bin:$PATH" make -j"$NUM_CORES"
sudo env PATH="${INSTALL_PREFIX}/bin:$PATH" make install
}
# configurar postgresql.conf para Spock
# borra y añade al final
configure_spock() {
echo "🛠️ Configurando postgresql.conf para Spock..."
CONF_FILE="${DATA_DIR}/postgresql.conf"
sudo sed -i "/^#*shared_preload_libraries *=/d" "$CONF_FILE"
sudo sed -i "/^#*track_commit_timestamp *=/d" "$CONF_FILE"
sudo sed -i "/^#*wal_level *=/d" "$CONF_FILE"
sudo sed -i "/^#*max_worker_processes *=/d" "$CONF_FILE"
sudo sed -i "/^#*max_replication_slots *=/d" "$CONF_FILE"
sudo sed -i "/^#*max_wal_senders *=/d" "$CONF_FILE"
{
echo ""
echo "# Configuración necesaria para Spock"
echo "shared_preload_libraries = 'spock'"
echo "track_commit_timestamp = on"
echo "wal_level = 'logical'"
echo "max_worker_processes = 10 # one per database needed on provider node"
echo ""
echo "max_replication_slots = 10 # one per node needed on provider node"
echo "max_wal_senders = 10 # one per node needed on provider node"
} | sudo tee -a "$CONF_FILE" >/dev/null
}
# resumen
show_summary() {
echo "✅ PostgreSQL ${PG_VERSION} y Spock compilados e instalados correctamente."
echo "🔧 PostgreSQL instalado en: $INSTALL_PREFIX"
echo "📁 Datos en: $DATA_DIR"
}
main() {
install_dependencies
prepare_source_dir
download_postgres
extract_sources
clone_spock
apply_patches
configure_postgres
build_and_install_postgres
configure_path
create_postgres_user
setup_data_dir
init_db_cluster
install_spock
configure_spock
show_summary
}
main
Como vemos aquí definimos una serie de funciones que nos permiten realizar la instalación de Postgresql y Spock. Veamos un poco el paso a paso de lo que hace el script:
- Instalación de dependencias: Se instalan las dependencias necesarias para compilar Postgresql y Spock.
- Preparación del directorio de código fuente: Se crea el directorio donde se va a descargar y compilar Postgresql.
- Descarga de Postgresql: Se descarga la versión especificada de Postgresql.
- Extracción de fuentes: Se extraen los archivos de Postgresql.
- Clonación de Spock: Se clona el repositorio de Spock desde GitHub.
- Aplicación de parches: Se aplican los parches necesarios para integrar Spock con Postgresql.
- Configuración de Postgresql: Se configura la compilación de Postgresql con las opciones necesarias.
- Compilación e instalación de Postgresql: Se compila e instala Postgresql en el directorio especificado.
- Configuración del PATH: Se añade el directorio de Postgresql al PATH del sistema para que sea accesible.
- Creación del usuario Postgres: Se crea el usuario
postgres
si no existe. - Configuración del directorio de datos: Se crea el directorio de datos para Postgresql y se le asigna el propietario correcto.
- Inicialización del clúster de base de datos: Se inicializa el clúster de base de datos en el directorio de datos.
- Instalación de Spock: Se compila e instala Spock en el directorio de Postgresql.
- Configuración de Spock en postgresql.conf: Se configura el archivo
postgresql.conf
para habilitar Spock y sus parámetros necesarios. - Resumen: Se muestra un resumen de la instalación y configuración realizada.
Lanzamiento del script de compilación e instalación
Para lanzar el script, primero debemos darle permisos de ejecución:
chmod +x config.sh
chmod +x install_postgres_spock.sh
./install_postgres_spock.sh
fichero setup_postgres_service.sh
Para configurar Postgresql podemos ejecutar el siguiente script llamado setup_postgres_service.sh:
#!/bin/bash
# variables de configuración
source ./config.sh
set -euo pipefail
# servicio systemd
create_service_file() {
echo "Creando archivo de servicio systemd..."
sudo tee "$SERVICE_FILE" > /dev/null <<EOF
[Unit]
Description=PostgreSQL database server
After=network.target
[Service]
Type=forking
User=postgres
Group=postgres
ExecStart=${PG_CTL} start -D ${PGDATA} -l ${PGDATA}/logfile
ExecStop=${PG_CTL} stop -D ${PGDATA}
ExecReload=${PG_CTL} reload -D ${PGDATA}
Environment=PATH=${INSTALL_PREFIX}/bin:/usr/bin:/bin
Restart=on-failure
[Install]
WantedBy=multi-user.target
EOF
}
enable_service() {
echo "Recargando systemd y habilitando el servicio..."
sudo systemctl daemon-reexec
sudo systemctl daemon-reload
sudo systemctl enable postgresql
sudo systemctl start postgresql
}
main() {
create_service_file
enable_service
echo "✅ Servicio PostgreSQL configurado y iniciado."
}
main
Este script crea un archivo de servicio para Postgresql en systemd, lo habilita y lo inicia.
Lanzamiento del script de configuración del servicio
Para lanzar el script, primero debemos darle permisos de ejecución:
chmod +x setup_postgres_service.sh
./setup_postgres_service.sh
Verificación del lanzamiento del servicio
Para verificar que el servicio se ha iniciado correctamente, podemos ejecutar el siguiente comando:
systemctl status postgresql
Acceso a la consola de Postgresql
Para acceder a la consola de Postgresql, nos cambiamos al usuario postgres
:
sudo -iu postgres
Y luego ejecutamos el comando:
psql -h localhost -p 5432 -U postgres
Si ha ido todo bien, deberíamos ver el prompt de Postgresql y poder ejecutar comandos SQL. Como por ejemplo, podemos crear una base de datos de prueba:
CREATE DATABASE testdb;
o listar las bases de datos existentes:
\l
Ficheros de configuración
Los ficheros de configuración de Postgresql se encuentran en el directorio de datos que hemos especificado en el script de instalación. Por defecto, este directorio es /usr/local/pgsql/data
. Los ficheros más importantes son:
postgresql.conf
: Configuración principal del servidor.pg_hba.conf
: Configuración de autenticación de clientes.
Configuración de Spock
Como vemos en el fichero install_postgres_spock.sh
, hemos configurado Spock en el archivo postgresql.conf
añadiendo las siguientes líneas:
# Add settings for extensions here
# Configuración necesaria para Spock
shared_preload_libraries = 'spock'
track_commit_timestamp = on
wal_level = 'logical'
max_worker_processes = 10 # one per database needed on provider node
max_replication_slots = 10 # one per node needed on provider node
max_wal_senders = 10 # one per node needed on provider node
Esto habilita Spock y configura los parámetros necesarios para su funcionamiento.
Prueba de funcionamiento
Para probar que Spock está funcionando correctamente, podemos ejecutar los siguientes comandos en la consola de Postgresql:
## Paso 1: Crear las Bases de Datos
-- Crear base de datos origen (proveedor)
CREATE DATABASE proveedor_db;
-- Crear base de datos destino (suscriptor)
CREATE DATABASE suscriptor_db;
Paso 2: Configurar la Base de Datos Proveedor
Conectar la base de datos proveedor y configurarla:
-- Conectar a proveedor_db
\c proveedor_db
-- Crear la extensión spock
CREATE EXTENSION spock;
-- Crear tabla de ejemplo
CREATE TABLE public.clientes (
id SERIAL PRIMARY KEY,
nombre TEXT NOT NULL,
email TEXT UNIQUE NOT NULL,
creado_en TIMESTAMP DEFAULT now()
);
-- Insertar datos de prueba
INSERT INTO public.clientes (nombre, email)
VALUES
('Ana', 'ana@example.com'),
('Juan', 'juan@example.com');
-- Crear nodo spock proveedor
SELECT spock.node_create(
node_name := 'proveedor1',
dsn := 'host=localhost port=5432 dbname=proveedor_db'
);
-- Añadir tabla al conjunto de replicación
SELECT spock.repset_add_table(
set_name := 'default',
relation := 'public.clientes',
synchronize_data := true
);
-- Alternativa: replicar todas las tablas del esquema public
-- SELECT spock.repset_add_all_tables('default', ARRAY['public']);
Paso 3: Configurar la Base de Datos Suscriptor
Conectar a la base de datos suscriptor y configurarla:
-- Conectar a suscriptor_db
\c suscriptor_db
-- Crear extensión spock
CREATE EXTENSION spock;
-- Crear nodo del suscriptor
SELECT spock.node_create(
node_name := 'suscriptor1',
dsn := 'host=localhost port=5432 dbname=suscriptor_db'
);
-- Crear suscripción con sincronización completa
SELECT spock.sub_create(
subscription_name := 'sub1',
provider_dsn := 'host=localhost port=5432 dbname=proveedor_db',
replication_sets := ARRAY['default', 'ddl_sql'],
synchronize_structure := true, -- Por defecto viene a false
synchronize_data := true
);
Paso 4: Verificar la Replicación
-- Esperar la sincronización (aunque es inmediata en este ejemplo)
SELECT spock.sub_wait_for_sync('sub1');
-- Verificar que los datos se replicaron
SELECT * FROM public.clientes;
-- Verificar el estado de la suscripción
SELECT * FROM spock.sub_show_status();
Paso 5: Añadir más datos
-- En proveedor_db, insertar un nuevo registro
\c proveedor_db
INSERT INTO public.clientes (nombre, email)
VALUES ('Lucia', 'lucia@example.com');
-- verificar
\c suscriptor_db
SELECT * FROM public.clientes ORDER BY id;
Otros comandos probados
-- Resincronizar una tabla específica si es necesario
SELECT spock.sub_resync_table(
subscription_name := 'sub1',
relation := 'public.clientes',
truncate := true -- Borra los datos antes de volver a sincronizar
);
-- Ver el estado de todos los nodos
SELECT * FROM spock.node;
-- Ver el estado de las suscripciones
SELECT * FROM spock.subscription;
Conclusión
En este artículo hemos visto cómo compilar Postgresql con la extensión de Spock para crear un cluster Multi-master. Hemos explicado los pasos necesarios para instalar y configurar Postgresql, así como la configuración de Spock para habilitar la replicación entre bases de datos. También hemos realizado una prueba de funcionamiento para verificar que la replicación está funcionando correctamente.