Workstation Logo
Productos
Labs de IAAgentes OpenAIAgentes ClaudeGrok BotWorkstation CRM (WSL CRM)MarketingTodos los Productos
Soluciones IA
Estaciones de Trabajo IAAI SME PackagesIA PrivadaClústeres GPUIA en el BordeLaboratorio IA EmpresarialIA por Industria
Servicios
Modernización de plataformaIngeniería digitalFundamentos de datos e IAOperaciones autónomasConsultoría de IAAutomatización DevOpsCiberseguridadDesarrollo de softwareCreación de agentesConfiguración MLOps
Sobre Nosotros
SociosHistorias de Clientes
Artículos
Documentación
WSL ProxyRing PromoterWSL VaultJobshoutSysOps 24/7
Blog
ContáctenosLogin
Workstation

Estaciones de trabajo de IA, software multiagente de IA, infraestructura de GPU y soluciones de agentes inteligentes para empresas modernas.

Contáctenos

Soluciones de IA

Estaciones de Trabajo IAAI SME PackagesIA PrivadaClústeres GPUIA en el BordeLaboratorio IA EmpresarialIA por Industria

Productos

Todos los ProductosWSL CRM y ERPMarketingAgentes OpenAIWSL ProxyRing PromoterWSL VaultJobshoutSysOps 24/7

Empresa

Sobre NosotrosPor qué WorkstationSociosHistorias de ClientesPreciosContacto

Recursos

ArtículosDocumentaciónBlogBuscarMapa del Sitio
Oficina Reino Unido
77-79 Marlowes, Hemel Hempstead HP1 1LFCómo llegar: tome la salida 20 de la M25, Outer LondonN.º de empresa: 11641870Lun - Vie: 9:00 - 18:00 GMT
+44 7515 356 146
Oficina Bélgica
Workstation SRL, Rue Vanderkindere 34, 1180 Uccle, BrusselsBE 0751.518.683Lun - Vie: 9:00 - 18:00 CET
+32 492 45 67 46
Oficina India
#159 Sector 9, Pocket 1, DDA Flats, 110077 Dwarka, New Delhi
+91 98881 98841

© 2026 Workstation AI. Todos los derechos reservados.

PrivacidadCookiesTérminos de ServicioMapa del sitio web

Loading blog...

Home / Blog
DatabaseKubernetesDevOpsBackend

Alta disponibilidad nativa de PostgreSQL: Patroni, replicación de streaming y estrategias de conmutación por error de producción

PostgreSQL HA nativo con Patroni, replicación de streaming y HAProxy

Balinder Walia12 de abril de 202634 min read

Ejecutar una única instancia PostgreSQL es sencillo hasta que la primera interrupción no planificada le recuerda que una base de datos es tan valiosa como su disponibilidad. Las fallas de disco, los pánicos en el kernel, las particiones de red y las actualizaciones fallidas no son riesgos teóricos: son certezas operativas en un período de tiempo suficientemente largo. PostgreSQL no viene con conmutación por error automática incorporada, pero proporciona todas las primitivas de replicación necesarias para construir un clúster de alta disponibilidad. Patroni, un marco de HA de código abierto mantenido por Zalando, organiza esas primitivas en un sistema de conmutación por error de nivel de producción que ha sido probado a escala en miles de clústeres PostgreSQL en todo el mundo.

Este artículo es una guía de ingeniería detallada. Cubriremos la replicación de transmisión de PostgreSQL (síncrona y asíncrona), la arquitectura y configuración de Patroni, etc. como un almacén de configuración distribuido, HAProxy para enrutamiento de conexiones con división de lectura y escritura, PgBouncer para agrupación de conexiones, archivado WAL y recuperación de un punto en el tiempo, replicación lógica para sincronización selectiva de datos, pg_basebackup para aprovisionamiento de espera inicial, repmgr como una alternativa a Patroni, patrones de implementación específicos de la nube para AWS, Azure y GCP, implementación básica de k3s con Rancher y Longhorn, monitoreo con pg_stat_replication y Prometheus/Grafana, procedimientos de conmutación versus conmutación por error, prevención de cerebro dividido, ajuste de producción e ingeniería del caos para la validación de la conmutación por error.

PostgreSQL Fundamentos de replicación de streaming

La replicación de streaming

es la columna vertebral de la alta disponibilidad de PostgreSQL. Funciona enviando continuamente registros de registro de escritura anticipada (WAL) desde un servidor principal a uno o más servidores en espera. El standby aplica esos registros WAL en tiempo real, manteniendo una copia casi idéntica de los datos del primario. Este mecanismo se introdujo en PostgreSQL 9.0 y se ha perfeccionado en cada versión posterior.

Hay dos modos de replicación de streaming:asíncrono,ysíncrono,. En modo asíncrono, el primario no espera a que los standby confirmen la recepción de los registros WAL antes de confirmar una transacción. Esto proporciona el máximo rendimiento de escritura, pero introduce una ventana de posible pérdida de datos: si el primario falla antes de que un standby haya recibido el WAL más reciente, esas transacciones se pierden. En modo síncrono, el principal espera al menos un modo de espera para confirmar que los registros WAL se han escrito en un almacenamiento duradero antes de informar una transacción como confirmada. Esto elimina la pérdida de datos a costa de una mayor latencia de confirmación, ya que cada escritura debe pasar de ida y vuelta a un modo de espera.

La elección entre replicación síncrona y asíncrona no es binaria. PostgreSQL admitesynchronous_commita nivel de sesión, por lo que las cargas de trabajo sensibles a la latencia pueden optar por confirmaciones asincrónicas, mientras que las transacciones financieras críticas utilizan confirmaciones sincrónicas dentro del mismo clúster.

Configuración del primario para replicación

El servidor primario debe configurarse para generar registros WAL a un nivel suficiente para la replicación y permitir conexiones en espera. Las siguientes configuraciones depostgresql.confson esenciales.

# postgresql.conf on the primary
wal_level = replica                    # minimum for streaming replication
max_wal_senders = 10                   # max concurrent replication connections
max_replication_slots = 10             # prevent WAL removal before standby consumption
wal_keep_size = 2GB                    # retain WAL as fallback if slots are unused
hot_standby = on                       # allow read queries on standbys
synchronous_commit = on                # 'on' for sync, 'off' for pure async
synchronous_standby_names = 'ANY 1 (standby1, standby2)'  # sync replication targets
archive_mode = on                      # enable WAL archiving for PITR
archive_command = 'test ! -f /archive/%f && cp %p /archive/%f'
listening_addresses = '*'
port = 5432

La autenticación para conexiones de replicación se maneja enpg_hba.conf. Las conexiones de replicación utilizan un tipo de conexión dedicada.

# pg_hba.conf — replication entries
# TYPE   DATABASE        USER            ADDRESS              METHOD
host     replication     replicator      10.0.1.0/24          scram-sha-256
host     replication     replicator      10.0.2.0/24          scram-sha-256
host     all             all             10.0.0.0/16          scram-sha-256

Cree el usuario de replicación en el principal.

CREATE ROLE replicator WITH REPLICATION LOGIN PASSWORD 'strong_replication_password';

Aprovisionamiento de un modo de espera con pg_basebackup

La utilidadpg_basebackupcrea una copia física del directorio de datos del primario, que se convierte en el punto de partida para un nuevo modo de espera. Maneja la copia de seguridad base y la transmisión WAL de forma atómica, por lo que la copia resultante es consistente.

# On the standby server
pg_basebackup -h primary-host -U replicator -D /var/lib/postgresql/16/main \
  -Fp -Xs -P -R

# -Fp: plain format
# -Xs: stream WAL during backup
# -P:  show progress
# -R:  create standby.signal and configure primary_conninfo in postgresql.auto.conf

El indicador-Res crítico: escribeprimary_conninfoenpostgresql.auto.confy creastandby.signal, lo que le indica a PostgreSQL que se inicie en modo de espera. En PostgreSQL 12 y posteriores,recovery.confse reemplaza por estos dos mecanismos.

# postgresql.auto.conf (generated by pg_basebackup -R)
primary_conninfo = 'host=primary-host port=5432 user=replicator password=strong_replication_password application_name=standby1'
primary_slot_name = 'standby1_slot'

Cree la ranura de replicación en el principal antes de iniciar el modo de espera, para evitar que WAL se limpie antes de que el modo de espera pueda consumirlo.

SELECT pg_create_physical_replication_slot('standby1_slot');
SELECT pg_create_physical_replication_slot('standby2_slot');
Patrón

: Orquestación HA automatizada

La replicación de Streaming

le brinda redundancia de datos, pero no le brinda conmutación por error automática. Si el primario falla, alguien (un operador humano o un sistema de automatización) debe promover un respaldo a primario, reconfigurar los respaldos restantes para que sigan el nuevo primario y actualizar el enrutamiento de la conexión. Patroni automatiza todo esto.

Patroni es un demonio Python que se ejecuta junto con cada instancia PostgreSQL. Utiliza un almacén de configuración distribuida (DCS), normalmente etcd, pero también ZooKeeper o Consul, para coordinar la elección del líder y el estado del clúster. Cada nodo Patroni escribe continuamente su estado de salud en el DCS. Cuando el líder (primario) no puede renovar su clave DCS dentro del TTL configurado, Patroni inicia una elección de líder entre los recursos en espera sanos. El ganador asciende a primario y los nodos restantes se reconfiguran como reservas del nuevo primario, todo automáticamente, generalmente en 10 a 30 segundos.

ArquitecturaPatroni HA: clúster PostgreSQL de 3 nodosClientes de aplicacionesEquilibrador de carga HAProxypuerto 5000 (RW) · puerto 5001 (RO)Primario (Líder)PostgreSQL 16 + Patroninodo1 — 10.0.1.10:5432En espera 1 (Sincronización)PostgreSQL 16 + Patroninodo2 — 10.0.1.11:5432En espera 2 (Asíncrono)PostgreSQL 16 + Patronesnodo3 — 10.0.1.12:5432transmisión de sincronizacióntransmisión asíncronaClúster etcd (DCS)3 nodos: elección de líder y control. almacén de configuraciónPrimarioEn esperaetc. DCSHAProxy

Patrón YAML Configuración

Patroni se configura a través de un archivo YAML que define la conexión DCS, los parámetros PostgreSQL, el comportamiento de replicación y la configuración de arranque. La siguiente es una configuración de nivel de producción para el nodo principal.

# /etc/patroni/patroni.yml — Node 1 (Primary)
scope: pg-ha-cluster
namespace: /postgresql-ha/
name: node1

restapi:
  listen: 0.0.0.0:8008
  connect_address: 10.0.1.10:8008

etcd3:
  hosts:
    - 10.0.2.10:2379
    - 10.0.2.11:2379
    - 10.0.2.12:2379

bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576  # 1MB — only promote standbys within this lag
    synchronous_mode: true
    synchronous_mode_strict: false
    postgresql:
      use_pg_rewind: true
      use_slots: true
      parameters:
        wal_level: replica
        hot_standby: 'on'
        max_connections: 200
        max_wal_senders: 10
        max_replication_slots: 10
        wal_keep_size: 2GB
        synchronous_commit: 'on'
        archive_mode: 'on'
        archive_command: 'test ! -f /archive/%f && cp %p /archive/%f'
        archive_timeout: 60
        wal_log_hints: 'on'
        shared_preload_libraries: 'pg_stat_statements'
        track_commit_timestamp: 'on'
      pg_hba:
        - host replication replicator 10.0.0.0/16 scram-sha-256
        - host all all 10.0.0.0/16 scram-sha-256
        - host all all 0.0.0.0/0 scram-sha-256

  initdb:
    - encoding: UTF8
    - data-checksums

  users:
    admin:
      password: 'admin_secure_password'
      options:
        - createrole
        - createdb
    replicator:
      password: 'repl_secure_password'
      options:
        - replication

postgresql:
  listen: 0.0.0.0:5432
  connect_address: 10.0.1.10:5432
  data_dir: /var/lib/postgresql/16/main
  bin_dir: /usr/lib/postgresql/16/bin
  config_dir: /var/lib/postgresql/16/main
  pgpass: /tmp/pgpass0
  authentication:
    superuser:
      username: postgres
      password: 'postgres_secure_password'
    replication:
      username: replicator
      password: 'repl_secure_password'
    rewind:
      username: postgres
      password: 'postgres_secure_password'
  parameters:
    unix_socket_directories: '/var/run/postgresql'
  create_replica_methods:
    - basebackup
  basebackup:
    max-rate: 100M
    checkpoint: fast

tags:
  nofailover: false
  noloadbalance: false
  clonefrom: false
  nosync: false

Los nodos en espera utilizan una configuración idéntica con sus propios valoresname,connect_addressylisten. Patroni se encarga del resto: detecta si un nodo debe ser el líder o una réplica según el estado del DCS y configura PostgreSQL en consecuencia.

etcd como almacén de configuración distribuida

etcd es el sistema nervioso de un grupo Patroni. Almacena la identidad del líder actual, la topología del clúster, la configuración deseada y el estado de salud de cada nodo. Un clúster etcd de tres nodos es el mínimo para la producción, ya que tolera la falla de un nodo mientras se mantiene el quórum.

# Install and configure etcd on three dedicated nodes
# /etc/etcd/etcd.conf.yml — Node etcd1 (10.0.2.10)
name: etcd1
data-dir: /var/lib/etcd
listen-client-urls: http://0.0.0.0:2379
listen-peer-urls: http://0.0.0.0:2380
advertise-client-urls: http://10.0.2.10:2379
initial-advertise-peer-urls: http://10.0.2.10:2380
initial-cluster: etcd1=http://10.0.2.10:2380,etcd2=http://10.0.2.11:2380,etcd3=http://10.0.2.12:2380
initial-cluster-state: new
initial-cluster-token: patroni-etcd-cluster

# Start etcd
systemctl enable --now etcd

# Verify cluster health
etcdctl endpoint health --cluster \
  --endpoints=http://10.0.2.10:2379,http://10.0.2.11:2379,http://10.0.2.12:2379

Para implementaciones de producción, habilite TLS entre pares de etcd y entre clientes de etcd y Patroni. El tráfico etcd no cifrado expone las credenciales y la configuración del clúster a atacantes a nivel de red.

HAProxy para enrutamiento de conexión

Patroni expone un REST API en cada nodo (puerto 8008 de forma predeterminada) que informa si el nodo es el líder actual o una réplica. HAProxy utiliza estos puntos finales de verificación de estado para enrutar el tráfico: las escrituras van al líder, las lecturas van a réplicas saludables. Esto le brinda una división automática de lectura y escritura sin ningún cambio a nivel de aplicación.

# /etc/haproxy/haproxy.cfg
global
    maxconn 2000
    log /dev/log local0
    stats socket /var/run/haproxy.sock mode 660 level admin

defaults
    mode tcp
    log global
    retries 3
    timeout client 30m
    timeout connect 4s
    timeout server 30m
    timeout check 5s
    maxconn 1000

listen pg_write
    bind *:5000
    option httpchk GET /primary
    http-check expect status 200
    default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
    server node1 10.0.1.10:5432 check port 8008
    server node2 10.0.1.11:5432 check port 8008
    server node3 10.0.1.12:5432 check port 8008

listen pg_read
    bind *:5001
    balance roundrobin
    option httpchk GET /replica
    http-check expect status 200
    default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
    server node1 10.0.1.10:5432 check port 8008
    server node2 10.0.1.11:5432 check port 8008
    server node3 10.0.1.12:5432 check port 8008

listen stats
    bind *:7000
    mode http
    stats enable
    stats uri /
    stats refresh 10s

El punto final/primarydevuelve HTTP 200 solo en el líder Patroni actual. El terminal/replicadevuelve 200 en espera en buen estado. Cuando se produce una conmutación por error, el nuevo primario comienza a devolver 200 en/primaryy HAProxy redirige automáticamente el tráfico de escritura, generalmente dentro de un único intervalo de verificación de estado (3 segundos). La directivaon-marked-down shutdown-sessionsfinaliza inmediatamente las conexiones existentes a un primario fallido, lo que obliga a los clientes a volver a conectarse al nuevo líder.

PgBouncer para agrupación de conexiones

PostgreSQL crea un nuevo proceso de backend para cada conexión de cliente. A escala (cientos o miles de microservicios, cada uno de los cuales mantiene grupos de conexiones), la sobrecarga de la creación de procesos y el consumo de memoria se vuelve significativa. PgBouncer se encuentra entre la aplicación y PostgreSQL, manteniendo un grupo de conexiones del lado del servidor y multiplexando conexiones de clientes en ellas.

# /etc/pgbouncer/pgbouncer.ini
[databases]
* = host=127.0.0.1 port=5432 dbname=appdb

[pgbouncer]
listen_addr = 0.0.0.0
listen_port = 6432
auth_type = scram-sha-256
auth_file = /etc/pgbouncer/userlist.txt

pool_mode = transaction
max_client_conn = 1000
default_pool_size = 50
min_pool_size = 10
reserve_pool_size = 10
reserve_pool_timeout = 3
server_lifetime = 3600
server_idle_timeout = 600
server_connect_timeout = 5
server_login_retry = 3

log_connections = 1
log_disconnections = 1
stats_period = 60

Cuando se usa con Patroni, PgBouncer generalmente se ubica en cada nodo PostgreSQL o en los nodos HAProxy. El modo de grupotransactiones la mejor opción para la mayoría de las cargas de trabajo: asigna una conexión de servidor durante la duración de una transacción y la devuelve al grupo entre transacciones. Esto es mucho más eficiente que el modosession, que mantiene una conexión para toda la sesión del cliente.

Archivado WAL y recuperación en un momento dado

La replicación de streaming

protege contra fallas del servidor, pero no protege contra errores lógicos: unDROP TABLEaccidental o una migración de aplicación incorrecta se replica en todos los dispositivos en espera de inmediato. El archivado WAL combinado con la recuperación en un momento dado (PITR) le permite restaurar a cualquier momento antes de que ocurriera el error.

El archivado WAL

copia segmentos WAL completos en un archivo duradero, generalmente un depósito S3, un montaje NFS o un servidor de respaldo dedicado. Herramientas comopgBackRestyWAL-Gmanejan el archivado de manera eficiente con compresión, cifrado y transferencia paralela.

# pgBackRest configuration — /etc/pgbackrest/pgbackrest.conf
[global]
repo1-type=s3
repo1-s3-bucket=pg-wal-archive
repo1-s3-endpoint=s3.eu-west-1.amazonaws.com
repo1-s3-region=eu-west-1
repo1-s3-key=AKIAIOSFODNN7EXAMPLE
repo1-s3-key-secret=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
repo1-path=/pgbackrest
repo1-retention-full=4
repo1-retention-diff=7
repo1-cipher-type=aes-256-cbc
repo1-cipher-pass=strong_encryption_passphrase
compress-type=zst
compress-level=3
process-max=4

[pg-ha-cluster]
pg1-path=/var/lib/postgresql/16/main
pg1-port=5432

# In postgresql.conf
archive_command = 'pgbackrest --stanza=pg-ha-cluster archive-push %p'
restore_command = 'pgbackrest --stanza=pg-ha-cluster archive-get %f "%p"'

Para realizar una recuperación en un momento dado, especifique una marca de tiempo de destino.

# Restore to a specific point in time
pgbackrest --stanza=pg-ha-cluster --type=time \
  --target="2026-04-12 11:25:00" \
  --target-action=promote \
  restore

Replicación lógica para sincronización selectiva de datos

Mientras que la replicación de transmisión crea una copia física exacta de todo el clúster de base de datos, la replicación lógica opera a nivel de tabla, replicando tablas individuales o subconjuntos de datos entre instancias PostgreSQL independientes. Esto es útil para actualizaciones de versiones principales sin tiempo de inactividad, réplicas de lectura entre regiones que solo necesitan tablas específicas, alimentación de almacenes de datos y distribución de datos multiinquilino.

# On the publisher (source database)
wal_level = logical  # must be 'logical' — higher than 'replica'

CREATE PUBLICATION app_pub FOR TABLE orders, customers, products;

# On the subscriber (target database)
CREATE SUBSCRIPTION app_sub
  CONNECTION 'host=publisher-host port=5432 dbname=appdb user=replicator password=pass'
  PUBLICATION app_pub;

La replicación lógica se puede ejecutar junto con la replicación de transmisión. Un patrón común es utilizar replicación de streaming para HA (conmutación por error física rápida) y replicación lógica para réplicas de análisis entre regiones que solo necesitan un subconjunto de tablas.

Replicación de streaming multirregional

Para recuperación ante desastres y rendimiento de lectura global, los clústeres PostgreSQL pueden abarcar varias regiones. El patrón estándar es la replicación sincrónica dentro de una región (para una pérdida de datos cero en la conmutación por error local) y la replicación asincrónica entre regiones (para evitar penalizaciones de latencia entre regiones en cada escritura). Cada región tiene su propio HAProxy para enrutamiento de lectura local.

Replicación de transmisión PostgreSQL multirregionalRegión 1 — AWS eu-west-1Primariopg-nodo1 (RW)Sincronización en esperapg-nodo2 (RO)sincronizaciónHAProxy (local)Región 2 — Azure Europa occidentalAsíncrono en esperapg-nodo3 (RO)Asíncrono en esperapg-nodo4 (RO)SincronizaciónHAProxy (local)Región 3 — GCP Europa-Oeste1Asíncrono en esperapg-nodo5 (RO)Asíncrono en esperapg-nodo6 (RO)SincronizaciónHAProxy (local)asíncrono WALenvío WAL asíncronoArchivo WAL compartido (S3 / Blob / GCS)pgBackRest o WAL-G: PITRentre regionesGlobal DNS (Route53 / Administrador de tráfico / Nube DNS)Leyenda:Replicación de sincronización (dentro de la región)Replicación asíncrona (entre regiones)Archivado WAL en almacenamiento de objetosPrimarioEn espera

Procedimientos de conmutación y conmutación por error

Es fundamental comprender la diferencia entre conmutación por error y conmutación. Una conmutación por error dees una promoción no planificada provocada por el error del servidor primario actual. Un cambio deaes un cambio de función planificado y elegante, que normalmente se realiza antes del mantenimiento. Patroni apoya a ambos.

Conmutación planificada

# List cluster members
patronictlctl -c /etc/patroni/patroni.yml list

# Perform switchover to a specific node
patronictlctl -c /etc/patroni/patroni.yml switchover \
  --master node1 --candidate node2 --force

# Or use the Patroni REST API
curl -s http://10.0.1.10:8008/switchover -XPOST \
  -d '{"leader": "node1", "candidate": "node2"}'

Durante un cambio, Patroni degrada el principal actual a un candidato de reserva, promueve al candidato objetivo y reconfigura todos los demás candidatos para seguir a la nueva primaria. El proceso dura entre 5 y 15 segundos. HAProxy detecta el cambio mediante comprobaciones de estado y redirige el tráfico automáticamente.

Secuencia de conmutación por error automática

Cuando el primario falla inesperadamente, Patroni sigue una secuencia precisa para restaurar el servicio. El siguiente diagrama ilustra los pasos.

Secuencia de conmutación por error automática Patroni1falla primariaFallo, partición de red oFallo del discoen el nodo 12Patroni detecta mediante DCSEl TTL de la clave líder caduca en etcd(TTL predeterminado de 30 s)3Elección de líderStandbys compite para adquirirbloqueo líder en etcd4En espera promocionadoEl ganador deejecuta pg_ctl para promocionary se convierte en el nuevoprimario5Actualizaciones de HAProxyLas comprobaciones de estado detectan un nuevoprimario/primario devuelve 200 en el nuevo líder6ClientesreconectadosLas aplicacionesse vuelven a conectar a través de HAProxyal nuevo primario de forma transparenteTiempo total típico de conmutación por errorCaducidad de TTL de DCS de: ~15-30 sElección: ~2-5sHADetección de proxy: ~3-10 sVuelva a conectar≈ 20-45 segundos en totalParámetros clave deque afectan la velocidad de conmutación por error:• ttl (predeterminado 30 s): cuánto tiempo antes de que caduque la clave líder en DCS• loop_wait (predeterminado 10s): con qué frecuencia Patroni verifica el estado del clúster• retry_timeout (predeterminado 10 s): tiempo de espera para operaciones DCS y PostgreSQL• Maximum_lag_on_failover (1 MB): solo promueve los modos de espera dentro de este retraso de replicación

Prevención de cerebro dividido

El cerebro dividido, donde dos nodos creen simultáneamente que son el principal, es el modo de falla más peligroso en cualquier sistema HA. Patroni previene la división del cerebro mediante varios mecanismos:

  1. Bloqueo líder basado en DCS:Solo un nodo puede contener la clave líder en etcd en cualquier momento. La clave tiene un TTL y el líder debe renovarla continuamente. Si una partición de red aísla al líder de etcd, la clave caduca y el líder se degrada a sí mismo.
  2. Watchdog:Patroni puede configurar un dispositivo de vigilancia Linux (/dev/watchdog). Si Patroni pierde el acceso al DCS y no puede confirmar que debe seguir siendo líder, el organismo de control reiniciará o apagará el nodo, un mecanismo de protección estricto que garantiza que la antigua primaria no siga aceptando escrituras.
  3. pg_rewind:Cuando un antiguo primario vuelve a estar en línea, es posible que tenga registros WAL que nunca se replicaron.pg_rewindrebobina la línea de tiempo hasta el punto de divergencia, lo que permite que el nodo se reincorpore como modo de espera sin una copia de seguridad completa de la base. La configuraciónuse_pg_rewind: truede Patroni automatiza esto.
# Enable watchdog in Patroni config
bootstrap:
  dcs:
    postgresql:
      use_pg_rewind: true
      parameters:
        wal_log_hints: 'on'  # required for pg_rewind

# Watchdog configuration
watchdog:
  mode: required        # 'off', 'automatic', or 'required'
  device: /dev/watchdog
  safety_margin: 5      # seconds before TTL expiry to trigger watchdog

repmgr como alternativa a Patroni

repmgres otra herramienta HA popular para PostgreSQL. Proporciona capacidades de gestión de espera, conmutación por error automática y conmutación. Sin embargo, adopta un enfoque fundamentalmente diferente al de Patroni. repmgr utiliza un nodo testigo y un demonio (repmgrd) para la detección de fallas en lugar de un almacén de consenso distribuido. Esto hace que sea más sencillo de implementar, pero más susceptible a la división del cerebro en escenarios complejos de partición de red.

# repmgr.conf on the primary
node_id=1
node_name='node1'
conninfo='host=10.0.1.10 user=repmgr dbname=repmgr connect_timeout=2'
data_directory='/var/lib/postgresql/16/main'
failover=automatic
promote_command='repmgr standby promote -f /etc/repmgr.conf --log-to-file'
follow_command='repmgr standby follow -f /etc/repmgr.conf --log-to-file --upstream-node-id=%n'
monitoring_history=yes
monitor_interval_secs=5
reconnect_attempts=6
reconnect_interval=10

Para nuevas implementaciones, Patroni es la opción recomendada debido a sus mayores garantías de prevención de cerebro dividido y su comunidad de desarrollo más activa. repmgr sigue siendo una opción razonable para configuraciones más simples u organizaciones que ya han invertido en la herramienta.

Patrones de implementación en la nube

Implementación de

AWS: EC2, EBS y Route53

En AWS, implemente cada nodo PostgreSQL + Patroni en una instancia EC2 con volúmenes EBS gp3 o io2. Utilice instancias independientes en varias zonas de disponibilidad para HA. Los nodos etcd también deben abarcar las AZ.

# Terraform sketch for PostgreSQL HA on AWS
resource "aws_instance" "pg_node" {
  count                = 3
  ami                  = "ami-0abcdef1234567890"  # Ubuntu 22.04
  instance_type        = "r6g.2xlarge"             # 8 vCPU, 64GB RAM
  subnet_id            = aws_subnet.private[count.index].id
  vpc_security_group_ids = [aws_security_group.pg_sg.id]
  availability_zone    = element(["eu-west-1a", "eu-west-1b", "eu-west-1c"], count.index)

  root_block_device {
    volume_size = 50
    volume_type = "gp3"
  }

  tags = {
    Name = "pg-node-${count.index + 1}"
    Role = "patroni"
  }
}

resource "aws_ebs_volume" "pg_data" {
  count             = 3
  availability_zone = element(["eu-west-1a", "eu-west-1b", "eu-west-1c"], count.index)
  size              = 500
  type              = "gp3"
  iops              = 6000
  throughput        = 250
  encrypted         = true

  tags = {
    Name = "pg-data-${count.index + 1}"
  }
}

resource "aws_route53_health_check" "pg_primary" {
  count             = 3
  ip_address        = aws_instance.pg_node[count.index].private_ip
  port              = 8008
  type              = "HTTP"
  resource_path     = "/primary"
  failure_threshold = 3
  request_interval  = 10
}

Utilice un equilibrador de carga de red (NLB) en lugar de HAProxy si prefiere una solución administrada por AWS. El NLB puede utilizar comprobaciones de estado del grupo objetivo en comparación con Patroni REST API para enrutar el tráfico al principal actual.

Implementación de

Azure: máquinas virtuales, discos administrados y Azure LB

En Azure, utilice máquinas virtuales Standard_E8s_v5 (optimizadas para memoria) con discos administrados SSD Premium para volúmenes de datos. Implemente en zonas de disponibilidad. Azure Load Balancer proporciona el equivalente de HAProxy con sondas de estado contra Patroni REST API.

# Azure CLI — create PostgreSQL VM with Managed Disk
az vm create \
  --resource-group pg-ha-rg \
  --name pg-node-1 \
  --image Canonical:0001-com-ubuntu-server-jammy:22_04-lts:latest \
  --size Standard_E8s_v5 \
  --zone 1 \
  --vnet-name pg-vnet \
  --subnet pg-subnet \
  --nsg pg-nsg \
  --admin-username pgadmin \
  --ssh-key-value ~/.ssh/id_rsa.pub

az disk create \
  --resource-group pg-ha-rg \
  --name pg-data-1 \
  --size-gb 512 \
  --sku Premium_LRS \
  --zone 1

az vm disk attach \
  --resource-group pg-ha-rg \
  --vm-name pg-node-1 \
  --name pg-data-1

# Azure Load Balancer health probe for Patroni
az network lb probe create \
  --resource-group pg-ha-rg \
  --lb-name pg-lb \
  --name patroni-primary-probe \
  --protocol Http \
  --port 8008 \
  --path /primary \
  --interval 5 \
  --threshold 3
Implementación de

GCP: Compute Engine y equilibrio de carga en la nube

En GCP, use instancias n2-highmem-8 (8 vCPU, 64 GB de RAM) con discos persistentes SSD. Distribuir entre zonas dentro de una región. Utilice un equilibrador de carga TCP/UDP interno con comprobaciones de estado de Patroni.

# GCP — create instance and persistent disk
gcloud compute instances create pg-node-1 \
  --zone=europe-west1-b \
  --machine-type=n2-highmem-8 \
  --image-family=ubuntu-2204-lts \
  --image-project=ubuntu-os-cloud \
  --boot-disk-size=50GB \
  --network=pg-network \
  --subnet=pg-subnet

gcloud compute disks create pg-data-1 \
  --zone=europe-west1-b \
  --size=500GB \
  --type=pd-ssd

gcloud compute instances attach-disk pg-node-1 \
  --disk=pg-data-1 \
  --zone=europe-west1-b

# Health check for Patroni primary endpoint
gcloud compute health-checks create http patroni-primary-check \
  --port=8008 \
  --request-path=/primary \
  --check-interval=5s \
  --timeout=5s \
  --unhealthy-threshold=3 \
  --healthy-threshold=2
Implementación de

Bare Metal k3s con Rancher y Longhorn

Para las organizaciones que operan su propio hardware, la implementación de PostgreSQL HA en bare metal con k3s, Rancher y Longhorn proporciona una infraestructura totalmente de código abierto e independiente de la nube. k3s es una distribución Kubernetes liviana que se ejecuta de manera eficiente en servidores bare metal sin la sobrecarga de una distribución Kubernetes completa.

Metal desnudo k3s HA — PostgreSQL con PatroniIP virtual(VRRP mantenido) — 10.0.0.100VIP flotante para HAProxy activo/en esperaHAProxy (activo)metal desnudo-lb1HAProxy (en espera)metal desnudo-lb2Clústerk3s (administrado por Rancher)k3s Nodo 1 (servidor)PostgreSQL PrimarioPatrones+ PgBouncerVolumen de bocina larga (500 GB)SSD NVMe: srv1 de metal desnudok3s Nodo 2 (servidor)PostgreSQL En espera 1Patroni+ PgBouncerVolumen de bocina larga (500 GB)SSD NVMe: srv2 de metal desnudok3s Nodo 3 (servidor)PostgreSQL En espera 2Patroni+ PgBouncerVolumen de bocina larga (500 GB)SSD NVMe: srv3 de metal desnudoClúster etcd externo (3 nodos dedicados)etcd1 (10.0.3.10) · etcd2 (10.0.3.11) · etcd3 (10.0.3.12)Gestión de ganaderosUI + ciclo de vida del clústerPrimarioEn esperaetcéteraBocina largaHAProxyReplicación de streaming mostrada como flechas verdes discontinuas

k3s y configuración de Longhorn

# Install k3s on the first server node
curl -sfL https://get.k3s.io | K3S_TOKEN=my-cluster-token \
  INSTALL_K3S_EXEC="server --cluster-init --disable traefik --disable servicelb" sh -

# Join additional server nodes
curl -sfL https://get.k3s.io | K3S_TOKEN=my-cluster-token \
  K3S_URL=https://10.0.0.1:6443 \
  INSTALL_K3S_EXEC="server" sh -

# Install Longhorn for distributed block storage
helm repo add longhorn https://charts.longhorn.io
helm install longhorn longhorn/longhorn \
  --namespace longhorn-system --create-namespace \
  --set defaultSettings.defaultDataPath=/mnt/longhorn \
  --set defaultSettings.replicaCount=3 \
  --set defaultSettings.storageMinimalAvailablePercentage=15

# Deploy PostgreSQL with Patroni using the Zalando Postgres Operator
helm repo add postgres-operator-charts https://opensource.zalando.com/postgres-operator/charts/postgres-operator
helm install postgres-operator postgres-operator-charts/postgres-operator \
  --namespace postgres-system --create-namespace
# PostgreSQL cluster manifest for the Zalando Postgres Operator
apiVersion: acid.zalan.do/v1
kind: postgresql
metadata:
  name: pg-ha-cluster
  namespace: production
spec:
  teamId: "platform"
  numberOfInstances: 3
  volume:
    size: 500Gi
    storageClass: longhorn
  users:
    appuser:
      - superuser
      - createdb
    replicator: []
  databases:
    appdb: appuser
  postgresql:
    version: "16"
    parameters:
      shared_buffers: "16GB"
      effective_cache_size: "48GB"
      work_mem: "256MB"
      maintenance_work_mem: "2GB"
      max_connections: "200"
      max_wal_senders: "10"
      wal_level: replica
      synchronous_commit: "on"
      wal_keep_size: "2GB"
      archive_mode: "on"
      track_commit_timestamp: "on"
  patroni:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576
    synchronous_mode: true
  resources:
    requests:
      cpu: "4"
      memory: 32Gi
    limits:
      cpu: "8"
      memory: 64Gi

Keepalived para HAProxy VIP

# /etc/keepalived/keepalived.conf on lb1
vrrp_script chk_haproxy {
    script "killall -0 haproxy"
    interval 2
    weight 2
}

vrrp_instance VI_PG {
    state MASTER
    interface eth0
    virtual_router_id 52
    priority 100
    advert_int 1
    authentication {
        auth_type PASS
        auth_pass pgha_vip_pass
    }
    virtual_ipaddress {
        10.0.0.100/24
    }
    track_script {
        chk_haproxy
    }
}

Monitoreo PostgreSQL Replicación

La supervisión del estado de la replicación no es negociable en producción. PostgreSQL proporciona varias vistas integradas para este propósito, y Prometheus con Grafana proporciona la visibilidad y las alertas a largo plazo que necesita.

Consultas de monitoreo integradas

-- Check replication status on the primary
SELECT
    client_addr,
    application_name,
    state,
    sync_state,
    sent_lsn,
    write_lsn,
    flush_lsn,
    replay_lsn,
    (sent_lsn - replay_lsn) AS replication_lag_bytes,
    write_lag,
    flush_lag,
    replay_lag
FROM pg_stat_replication;

-- Check replication slot status
SELECT
    slot_name,
    slot_type,
    active,
    wal_status,
    pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS slot_lag
FROM pg_replication_slots;

-- Check standby recovery status (run on standby)
SELECT
    pg_is_in_recovery() AS is_standby,
    pg_last_wal_receive_lsn() AS last_received,
    pg_last_wal_replay_lsn() AS last_replayed,
    pg_last_xact_replay_timestamp() AS last_replayed_timestamp,
    EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()))::int AS replay_lag_seconds;

-- Monitor WAL generation rate
SELECT
    pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), '0/0')) AS total_wal_generated,
    pg_size_pretty(sum(size)) AS wal_directory_size
FROM pg_ls_waldir();

-- Check for long-running queries that could block replication
SELECT
    pid,
    now() - pg_stat_activity.query_start AS duration,
    query,
    state
FROM pg_stat_activity
WHERE (now() - pg_stat_activity.query_start) > interval '5 minutes'
  AND state != 'idle'
ORDER BY duration DESC;

Pila Prometheus y Grafana

Elpostgres_exporterexpone métricas PostgreSQL en formato Prometheus. Combinado conpatroni_exporter, obtiene visibilidad completa tanto del rendimiento de la base de datos como del estado del clúster HA.

# Deploy postgres_exporter as a sidecar or standalone
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts

# Custom queries for postgres_exporter
# /etc/postgres_exporter/queries.yaml
pg_replication_lag:
  query: |
    SELECT
      CASE WHEN pg_is_in_recovery() THEN
        EXTRACT(EPOCH FROM (now() - pg_last_xact_replay_timestamp()))::float
      ELSE 0 END AS lag_seconds
  master: true
  metrics:
    - lag_seconds:
        usage: "GAUGE"
        description: "Replication lag in seconds"

pg_replication_slots:
  query: |
    SELECT
      slot_name,
      active::int AS active,
      pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)::float AS slot_lag_bytes
    FROM pg_replication_slots
  master: true
  metrics:
    - slot_name:
        usage: "LABEL"
    - active:
        usage: "GAUGE"
        description: "Whether the slot is active"
    - slot_lag_bytes:
        usage: "GAUGE"
        description: "Slot lag in bytes"
# PrometheusRule for PostgreSQL HA alerts
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: postgresql-ha-alerts
  namespace: monitoring
spec:
  groups:
    - name: postgresql-replication
      rules:
        - alert: PostgreSQLReplicationLagHigh
          expr: pg_replication_lag_seconds > 30
          for: 5m
          labels:
            severity: warning
          annotations:
            summary: "PostgreSQL replication lag exceeds 30s on {{ $labels.instance }}"

        - alert: PostgreSQLReplicationSlotInactive
          expr: pg_replication_slots_active == 0
          for: 5m
          labels:
            severity: critical
          annotations:
            summary: "Replication slot {{ $labels.slot_name }} is inactive"

        - alert: PostgreSQLReplicationSlotLagHigh
          expr: pg_replication_slots_slot_lag_bytes > 1073741824
          for: 10m
          labels:
            severity: warning
          annotations:
            summary: "Replication slot lag exceeds 1GB on {{ $labels.slot_name }}"

        - alert: PatroniClusterUnhealthy
          expr: patroni_cluster_members_count < 3
          for: 2m
          labels:
            severity: critical
          annotations:
            summary: "Patroni cluster has fewer than 3 members"
Parámetros de ajuste de producción de

La configuración predeterminada de

PostgreSQL es conservadora y está adaptada a un entorno de alojamiento compartido pequeño. Los clústeres de alta disponibilidad de producción requieren un ajuste cuidadoso de los parámetros de replicación, memoria y WAL. La siguiente tabla resume las configuraciones más importantes para un servidor de 64 GB de RAM con almacenamiento NVMe.

# postgresql.conf — Production HA tuning

# === Replication ===
wal_level = replica
max_wal_senders = 10
max_replication_slots = 10
wal_keep_size = 4GB
synchronous_commit = on
synchronous_standby_names = 'ANY 1 (standby1, standby2)'
track_commit_timestamp = on
wal_log_hints = on

# === WAL ===
min_wal_size = 1GB
max_wal_size = 8GB
wal_buffers = 64MB
wal_compression = zstd
archive_mode = on
archive_timeout = 300
checkpoint_completion_target = 0.9
checkpoint_timeout = 15min

# === Memory ===
shared_buffers = 16GB              # 25% of RAM
effective_cache_size = 48GB        # 75% of RAM
work_mem = 256MB                   # per-operation sort/hash memory
maintenance_work_mem = 2GB         # for VACUUM, CREATE INDEX
huge_pages = try

# === Connections ===
max_connections = 200              # use PgBouncer for higher client counts
superuser_reserved_connections = 5

# === Query Performance ===
random_page_cost = 1.1             # SSD storage
effective_io_concurrency = 200     # NVMe SSD
default_statistics_target = 500
jit = on

# === Logging ===
log_min_duration_statement = 500   # log queries > 500ms
log_checkpoints = on
log_connections = on
log_disconnections = on
log_lock_waits = on
log_temp_files = 0
log_autovacuum_min_duration = 0

# === Autovacuum ===
autovacuum_max_workers = 4
autovacuum_naptime = 30s
autovacuum_vacuum_cost_limit = 2000
autovacuum_vacuum_scale_factor = 0.05
autovacuum_analyze_scale_factor = 0.02

Sintonización de parámetros Patroni DCS

La relación entre los parámetrosttl,loop_waityretry_timeoutde Patroni afecta directamente la velocidad de conmutación por error y el riesgo de falsos positivos. Un TTL más corto significa una detección de conmutación por error más rápida, pero aumenta el riesgo de conmutaciones por error innecesarias durante breves interrupciones de la red.

# Conservative (production default)
ttl: 30
loop_wait: 10
retry_timeout: 10
# Failover detection: ~30-40 seconds

# Aggressive (low-latency failover)
ttl: 15
loop_wait: 5
retry_timeout: 5
# Failover detection: ~15-20 seconds
# Warning: Higher risk of false failovers in unstable networks

Ingeniería del caos y pruebas de conmutación por error

Un sistema de conmutación por error que nunca ha sido probado es un sistema que no funciona. La ingeniería del caos aplica fallas controladas para validar que su configuración de HA se comporta correctamente en condiciones de falla reales. Cada clúster de Patroni debe someterse a simulacros de conmutación por error periódicamente.

Guía de prueba de conmutación por error

# 1. Verify cluster health before testing
patronictlctl -c /etc/patroni/patroni.yml list
+----------+---------+---------+----+-----------+
| Member   | Host    | Role    | TL | Lag in MB |
+----------+---------+---------+----+-----------+
| node1    | 10.0.1.10| Leader |  5 |           |
| node2    | 10.0.1.11| Replica |  5 |         0 |
| node3    | 10.0.1.12| Replica |  5 |         0 |
+----------+---------+---------+----+-----------+

# 2. Simulate primary crash (on node1)
sudo systemctl stop patroni
# Or more aggressive: sudo kill -9 $(pgrep -f patroni)

# 3. Monitor failover (from any node with patronictl)
watch -n 1 'patronictl -c /etc/patroni/patroni.yml list'

# 4. Verify new leader is elected (within 30-45 seconds)
# Expected: node2 or node3 promoted to Leader

# 5. Test write availability through HAProxy
PGPASSWORD=app_password psql -h haproxy-host -p 5000 -U appuser -d appdb \
  -c "INSERT INTO health_check (ts) VALUES (now()) RETURNING *;"

# 6. Restart the former primary
sudo systemctl start patroni
# Patroni will use pg_rewind to rejoin as a replica

# 7. Verify the former primary rejoins as replica
patronictlctl -c /etc/patroni/patroni.yml list

Prueba de partición de red

# Simulate network partition on the primary using iptables
# Block all traffic to etcd from the primary
sudo iptables -A OUTPUT -d 10.0.2.10 -j DROP
sudo iptables -A OUTPUT -d 10.0.2.11 -j DROP
sudo iptables -A OUTPUT -d 10.0.2.12 -j DROP

# Expected behaviour:
# 1. Primary loses DCS access
# 2. Leader key TTL expires
# 3. Primary demotes itself (with watchdog, node may reboot)
# 4. Standby acquires leader lock and promotes
# 5. After clearing iptables rules, former primary rejoins as replica

# Clean up
sudo iptables -D OUTPUT -d 10.0.2.10 -j DROP
sudo iptables -D OUTPUT -d 10.0.2.11 -j DROP
sudo iptables -D OUTPUT -d 10.0.2.12 -j DROP

Pruebas de caos automatizadas con Toxiproxy

# Run Toxiproxy alongside your Patroni cluster
# Create proxies for etcd and replication connections
toxiproxy-cli create etcd_proxy -l 0.0.0.0:12379 -u 10.0.2.10:2379
toxiproxy-cli create pg_repl_proxy -l 0.0.0.0:15432 -u 10.0.1.10:5432

# Add latency to etcd connections (simulates degraded network)
toxiproxy-cli toxic add etcd_proxy -t latency -a latency=500 -a jitter=200

# Add bandwidth limit to replication (simulates WAN replication)
toxiproxy-cli toxic add pg_repl_proxy -t bandwidth -a rate=1024

# Completely sever the connection (simulates network partition)
toxiproxy-cli toxic add etcd_proxy -t timeout -a timeout=0

# Monitor Patroni behaviour and verify correct failover
watch -n 2 'curl -s http://10.0.1.10:8008/patroni | python3 -m json.tool'

Script de validación continua

#!/bin/bash
# continuous_ha_check.sh — Run during chaos tests to measure availability

HAPROXY_HOST="10.0.0.100"
WRITE_PORT=5000
READ_PORT=5001
DATABASE="appdb"
USER="appuser"
LOGFILE="/var/log/ha_test_$(date +%Y%m%d_%H%M%S).log"

write_count=0
write_fail=0
read_count=0
read_fail=0

while true; do
    ts=$(date '+%Y-%m-%d %H:%M:%S.%3N')

    # Test write path
    if PGPASSWORD=app_password psql -h $HAPROXY_HOST -p $WRITE_PORT \
       -U $USER -d $DATABASE -c "SELECT 1" &>/dev/null; then
        ((write_count++))
    else
        ((write_fail++))
        echo "$ts WRITE_FAIL total_fails=$write_fail" >> $LOGFILE
    fi

    # Test read path
    if PGPASSWORD=app_password psql -h $HAPROXY_HOST -p $READ_PORT \
       -U $USER -d $DATABASE -c "SELECT 1" &>/dev/null; then
        ((read_count++))
    else
        ((read_fail++))
        echo "$ts READ_FAIL total_fails=$read_fail" >> $LOGFILE
    fi

    total=$((write_count + write_fail))
    if (( total % 100 == 0 )); then
        write_avail=$(echo "scale=2; $write_count * 100 / $total" | bc)
        read_total=$((read_count + read_fail))
        read_avail=$(echo "scale=2; $read_count * 100 / $read_total" | bc)
        echo "$ts Writes: ${write_avail}% ($write_count/$total) Reads: ${read_avail}% ($read_count/$read_total)"
    fi

    sleep 0.5
done

Avanzado: Replicación en cascada y esperas retardadas

Para clústeres grandes, la replicación en cascada reduce la carga en el principal. En lugar de que todos los recursos en espera se repliquen directamente desde el principal, algunos recursos en espera se replican desde otros recursos en espera. Esto crea una topología de árbol donde el primario alimenta dos recursos en espera y esos recursos en espera alimentan a recursos en espera descendentes adicionales.

# postgresql.auto.conf on a cascading standby
primary_conninfo = 'host=standby1-host port=5432 user=replicator application_name=cascade1'
primary_slot_name = 'cascade1_slot'

Un modo de espera retardado.aplica intencionalmente registros WAL con un retraso de tiempo, generalmente de 1 a 4 horas. Esto proporciona una defensa contra errores lógicos (eliminaciones accidentales, migraciones incorrectas) que se replican inmediatamente en modos de espera sincrónicos. Si ocurre un desastre, puede detener la reproducción de WAL en el modo de espera retrasado y recuperar los datos anteriores al error.

# postgresql.conf on delayed standby
recovery_min_apply_delay = '1h'

Estrategias de cadena de conexión

Las aplicaciones que se conectan a un clúster administrado por Patroni siempre deben conectarse a través de HAProxy o usar la cadena de conexión de múltiples hosts incorporada de PostgreSQL contarget_session_attrs. Esto proporciona conmutación por error del lado del cliente sin depender de un equilibrador de carga.

# Multi-host connection string with target_session_attrs
# The client tries each host in order and connects to the one matching the target attribute
postgresql://appuser:password@node1:5432,node2:5432,node3:5432/appdb?target_session_attrs=read-write&sslmode=require

# For read-only connections
postgresql://appuser:password@node1:5432,node2:5432,node3:5432/appdb?target_session_attrs=prefer-standby&sslmode=require

Este enfoque funciona bien para aplicaciones que no se pueden reconfigurar fácilmente para que apunten a un HAProxy VIP. La biblioteca cliente PostgreSQL (libpq) maneja la conmutación por error de forma transparente.

Refuerzo de seguridad

Un clúster PostgreSQL HA de producción debe aplicar el cifrado en tránsito y en reposo, utilizar una autenticación sólida y limitar la exposición de la red.

# Enable TLS in postgresql.conf
ssl = on
ssl_cert_file = '/etc/postgresql/certs/server.crt'
ssl_key_file = '/etc/postgresql/certs/server.key'
ssl_ca_file = '/etc/postgresql/certs/ca.crt'
ssl_min_protocol_version = 'TLSv1.3'

# Require TLS for all connections in pg_hba.conf
hostssl replication replicator 10.0.0.0/16 scram-sha-256
hostssl all         all        10.0.0.0/16 scram-sha-256

# etcd TLS
# In Patroni config
etcd3:
  hosts:
    - 10.0.2.10:2379
    - 10.0.2.11:2379
    - 10.0.2.12:2379
  protocol: https
  cacert: /etc/patroni/certs/etcd-ca.crt
  cert: /etc/patroni/certs/etcd-client.crt
  key: /etc/patroni/certs/etcd-client.key
Estrategia de respaldo

para clústeres HA

Una estrategia de copia de seguridad integral para los clústeres de Patroni debe incluir archivado WAL continuo, copias de seguridad completas periódicas y copias de seguridad diferenciales o incrementales entre copias de seguridad completas. pgBackRest es la herramienta recomendada para la gestión de copias de seguridad de producción PostgreSQL.

# Schedule backups via cron
# Full backup weekly (Sunday 2 AM)
0 2 * * 0 pgbackrest --stanza=pg-ha-cluster --type=full backup

# Differential backup daily (2 AM, Mon-Sat)
0 2 * * 1-6 pgbackrest --stanza=pg-ha-cluster --type=diff backup

# Verify backup integrity
pgbackrest --stanza=pg-ha-cluster --set=latest info

# Verify backup can be restored (dry run)
pgbackrest --stanza=pg-ha-cluster --set=latest verify

# List all backups
pgbackrest --stanza=pg-ha-cluster info
            full backup: 20260412-020000F
                timestamp: 2026-04-12 02:00:00 +0000
                wal start/stop: 000000050000000000000040 / 000000050000000000000042
                database size: 150GB, backup size: 150GB
                repository size: 45GB (compressed)
            diff backup: 20260412-020000F_20260413-020000D
                timestamp: 2026-04-13 02:00:00 +0000
                database size: 151GB, backup size: 2.1GB
                repository size: 650MB (compressed)
Resumen del runbook operativo

Cada equipo que ejecuta un clúster Patroni debe mantener un runbook que cubra los siguientes escenarios. Tener procedimientos documentados y probados transforma una interrupción estresante en una operación de rutina.

# === Quick Reference Commands ===

# Cluster status
patronictlctl -c /etc/patroni/patroni.yml list
patronictlctl -c /etc/patroni/patroni.yml history

# Planned switchover
patronictlctl -c /etc/patroni/patroni.yml switchover --master node1 --candidate node2

# Restart PostgreSQL on a specific node (rolling restart)
patronictlctl -c /etc/patroni/patroni.yml restart pg-ha-cluster node2

# Reload PostgreSQL configuration without restart
patronictlctl -c /etc/patroni/patroni.yml reload pg-ha-cluster

# Pause automatic failover (during maintenance)
patronictlctl -c /etc/patroni/patroni.yml pause

# Resume automatic failover
patronictlctl -c /etc/patroni/patroni.yml resume

# Edit DCS configuration (applies to all nodes)
patronictlctl -c /etc/patroni/patroni.yml edit-config

# Reinitialise a failed replica
patronictlctl -c /etc/patroni/patroni.yml reinit pg-ha-cluster node3

# Check Patroni REST API directly
curl -s http://10.0.1.10:8008/patroni | python3 -m json.tool
curl -s http://10.0.1.10:8008/cluster | python3 -m json.tool

Evaluación comparativa de rendimiento

Antes de pasar a producción, compare su clúster HA para establecer el rendimiento de referencia y verificar que la latencia de replicación sincrónica sea aceptable para su carga de trabajo.

# Benchmark with pgbench — initialise test data
pgbench -i -s 100 -h haproxy-host -p 5000 -U appuser appdb

# Run write-heavy benchmark (measures sync replication impact)
pgbench -h haproxy-host -p 5000 -U appuser -c 32 -j 8 -T 300 appdb
# Compare with async: temporarily set synchronous_commit = off

# Run read-only benchmark through read replica port
pgbench -h haproxy-host -p 5001 -U appuser -c 64 -j 16 -T 300 -S appdb

# Measure failover impact on transactions
# Run pgbench in background, then trigger a failover
pgbench -h haproxy-host -p 5000 -U appuser -c 8 -j 4 -T 600 appdb &
sleep 60 && patronictl switchover --master node1 --candidate node2 --force

Conclusión

La alta disponibilidad nativa de

PostgreSQL con Patroni no es una solución de herramienta única: es un sistema integrado de replicación de transmisión, consenso distribuido, enrutamiento de conexiones, agrupación de conexiones, archivo WAL, monitoreo y disciplina operativa. Cada capa aborda un modo de falla específico: la replicación de transmisión maneja la redundancia de datos, Patroni maneja la coordinación automática de conmutación por error, etcd proporciona el consenso distribuido necesario para la elección del líder sin dividir el cerebro, HAProxy enruta las conexiones al líder correcto, PgBouncer administra la sobrecarga de la conexión a escala y el archivado WAL con pgBackRest proporciona la última línea de defensa contra errores lógicos y recuperación ante desastres.

Los patrones de implementación varían según el entorno: AWS con NLB y Route53, Azure con zonas de disponibilidad y Azure Load Balancer, GCP con grupos de instancias administrados regionales o bare metal con k3s, Longhorn y Keepalived, pero la arquitectura central sigue siendo la misma. Tres o más nodos PostgreSQL administrados por Patroni, respaldados por un clúster etcd de tres nodos, encabezado por un equilibrador de carga que sigue los puntos finales de verificación de estado de Patroni.

La inversión más importante que puede hacer no es la configuración, sino las pruebas. Realice simulacros de conmutación por error mensualmente. Inyectar particiones de red. Mata procesos inesperadamente. Mida el tiempo de recuperación y la pérdida de datos. Cree paneles que muestren el retraso de replicación, la tasa de generación de WAL, la saturación del grupo de conexiones y el estado de DCS en tiempo real. La confianza que se obtiene con las pruebas sistemáticas es lo que separa a un clúster que sobrevive a su primera interrupción real de uno que convierte una falla del servidor en un incidente que afecta el negocio.

PostgreSQL le brinda todas las primitivas de replicación. Patroni te pone la orquestación. etcd te da el consenso. Su trabajo es conectarlos correctamente, ajustarlos a su carga de trabajo y validarlos continuamente. Esta guía le ha proporcionado los planos: ahora construya, pruebe y opere con confianza.