Saltar a contenido

Resolución de problemas del clúster de PostgreSQL

Info

Todo el procedimiento debe realizarse como root. Para elevar sus privilegios a root, puede utilizar el comando su -.

Atención

Para seguir este procedimiento, es necesario haber realizado las configuraciones adicionales para patronictl.

Los errores de conexión a la base de datos del clúster de PostgreSQL de CyberElements Bastion pueden tener diversas causas. Esta sección presenta una metodología general de resolución de problemas, que debe adaptarse a su caso.

Comprobar el estado del clúster

Info

Comprobar el estado del clúster permite localizar rápidamente el nodo o los nodos que fallan.

Puede comprobar el estado del clúster con el siguiente comando, que debe ejecutarse en cada uno de los nodos del clúster de PostgreSQL:

1
patronictl -c /etc/patroni/config.yml topology
Ejemplo de resultado en una plataforma que funciona

1
2
3
4
5
6
7
+ Cluster: 15-cleanroomvault5 ------+---------+---------+----+-----------+
| Member           | Host           | Role    | State   | TL | Lag in MB |
+------------------+----------------+---------+---------+----+-----------+
| PSQL_3           | psql_3         | Leader  | running | 2  |           |
| + PSQL_1         | psql_1         | Replica | running | 2  |         0 |
| + PSQL_2         | psql_2         | Replica | running | 2  |         0 |
+------------------+----------------+---------+---------+----+-----------+
En el resultado anterior, todo indica que el clúster de PostgreSQL funciona correctamente: el lag es de 0 MB en todos los nodos Replica, y todos los nodos figuran en la lista con el estado running. Es necesario obtener este resultado en todos los nodos para validar el funcionamiento de patroni y de etcd.

Ejemplo de resultado cuando hay un problema de comunicación entre los nodos

1
2
3
4
5
6
7
+ Cluster: 15-cleanroomvault5 ------+---------+---------+----+-----------+
| Member           | Host           | Role    | State   | TL | Lag in MB |
+------------------+----------------+---------+---------+----+-----------+
| PSQL_3           | psql_3         | Leader  | running | 2  |           |
| + PSQL_1         | psql_1         | Replica | running | 2  |       230 |
| + PSQL_2         | psql_2         | Replica | running | 2  |         0 |
+------------------+----------------+---------+---------+----+-----------+
En el resultado anterior, el lag de 230 MB es anómalo: podría indicar un problema de comunicación entre el nodo 3 y el nodo 1.
Si el problema persiste tras varias horas de espera, esto lo confirma.

Ejemplo de resultado cuando un nodo no se ha iniciado o detenido correctamente

1
2
3
4
5
6
7
+ Cluster: 15-cleanroomvault5 ------+---------+---------+----+-----------+
| Member           | Host           | Role    | State   | TL | Lag in MB |
+------------------+----------------+---------+---------+----+-----------+
| PSQL_3           | psql_3         | Leader  | running | 2  |           |
| + PSQL_1         | psql_1         | Replica | started | 2  |   unknown |
| + PSQL_2         | psql_2         | Replica | stopped | 2  |   unknown |
+------------------+----------------+---------+---------+----+-----------+
En el resultado anterior, el estado (columna State) indica que el nodo 1 se está iniciando. Si el estado started persiste varios minutos, o incluso varias horas, puede haber un problema con patroni o etcd en ese nodo.
El nodo 2 está en el estado stopped: está detenido. En caso de fallo de un nodo del clúster, esta información solo se muestra temporalmente, antes de que el nodo se retire de la lista.

Ejemplo de resultado cuando etcd falla en el nodo actual

1
2
3
2026-04-09 16:21:39,482 - WARNING - Retrying (Retry(total=1, connect=None, read=None, redirect=0, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7fcaa1618390>: Failed to establish a new connection: [Errno 111] Connection refused')': /version
2026-04-09 16:21:39,482 - WARNING - Retrying (Retry(total=0, connect=None, read=None, redirect=0, status=None)) after connection broken by 'NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7fcaa1618c10>: Failed to establish a new connection: [Errno 111] Connection refused')': /version
2026-04-09 16:21:39,483 - ERROR - Failed to get list of machines from https://PSQL_3:2379/v2: MaxRetryError("HTTPSConnectionPool(host='psql_3', port=2379): Max retries exceeded with url: /version (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7fcaa1619490>: Failed to establish a new connection: [Errno 111] Connection refused'))")
El resultado anterior indica un error de conexión a etcd, que impide obtener el estado del clúster de PostgreSQL.

Comprobar el estado de los servicios

Una vez identificado el nodo que falla, hay que identificar el servicio que no funciona. Los dos servicios principales del clúster de PostgreSQL son patroni y etcd.

Info

El servicio patroni depende del servicio etcd: si etcd no funciona, patroni tampoco funcionará.

Para identificar el servicio que falla, puede ejecutar los siguientes comandos:

1
2
systemctl status etcd
systemctl status patroni

Estos comandos muestran el estado del servicio, así como sus 10 últimas líneas de logs.

Atención

Un servicio con el estado active (running) no funciona necesariamente: puede estar en ejecución y escribir logs de error. Por eso es importante leer los logs del servicio para entender su estado real.

Ejemplo de resultado para etcd cuando el servicio funciona
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
● etcd.service - etcd - highly-available key value store
   Loaded: loaded (/lib/systemd/system/etcd.service; enabled; preset: enabled)
   Active: active (running) since Thu 2026-04-09 16:40:01 CEST; 21h ago
   Docs: https://etcd.io/docs
           man:etcd
Main PID: 283425 (etcd)
   Tasks: 7 (limit: 2227)
   Memory: 73.2M
       CPU: 51min 9.223s
   CGroup: /system.slice/etcd.service
           └─283425 /usr/bin/etcd

Apr 10 09:26:31 PSQL_1 etcd[283425]: store.index: compact 1624026
Apr 10 09:26:31 PSQL_1 etcd[283425]: finished scheduled compaction at 1624026 (took 325.098µs)
Apr 10 10:26:31 PSQL_1 etcd[283425]: store.index: compact 1624386
Apr 10 10:26:31 PSQL_1 etcd[283425]: finished scheduled compaction at 1624386 (took 417.797µs)
Apr 10 11:26:31 PSQL_1 etcd[283425]: store.index: compact 1624746
Apr 10 11:26:31 PSQL_1 etcd[283425]: finished scheduled compaction at 1624746 (took 1.706489ms)
Apr 10 12:26:31 PSQL_1 etcd[283425]: store.index: compact 1625106
Apr 10 12:26:31 PSQL_1 etcd[283425]: finished scheduled compaction at 1625106 (took 300.098µs)
Apr 10 13:26:31 PSQL_1 etcd[283425]: store.index: compact 1625466
Apr 10 13:26:31 PSQL_1 etcd[283425]: finished scheduled compaction at 1625466 (took 311.398µs)
Ejemplo de resultado para etcd cuando el servicio está en error

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
× etcd.service - etcd - highly-available key value store
    Loaded: loaded (/lib/systemd/system/etcd.service; enabled; preset: enabled)
    Active: failed (Result: exit-code) since Fri 2026-04-10 14:15:26 CEST; 5s ago
Duration: 21h 35min 20.382s
    Docs: https://etcd.io/docs
            man:etcd
    Process: 454701 ExecStart=/usr/bin/etcd $DAEMON_ARGS (code=exited, status=1/FAILURE)
Main PID: 454701 (code=exited, status=1/FAILURE)
        CPU: 12ms

Apr 10 14:15:26 PSQL_1 etcd[454701]: [WARNING] Deprecated '--logger=capnslog' flag is set; use '--logger=zap' flag instead
Apr 10 14:15:26 PSQL_1 etcd[454701]: etcd Version: 3.4.23
Apr 10 14:15:26 PSQL_1 etcd[454701]: Git SHA: Not provided (use ./build instead of go build)
Apr 10 14:15:26 PSQL_1 etcd[454701]: Go Version: go1.19.8
Apr 10 14:15:26 PSQL_1 etcd[454701]: Go OS/Arch: linux/amd64
Apr 10 14:15:26 PSQL_1 etcd[454701]: setting maximum number of CPUs to 1, total number of available CPUs is 1
Apr 10 14:15:26 PSQL_1 etcd[454701]: error listing data dir: /var/lib/etcd/cleanroom
Apr 10 14:15:26 PSQL_1 systemd[1]: etcd.service: Main process exited, code=exited, status=1/FAILURE
Apr 10 14:15:26 PSQL_1 systemd[1]: etcd.service: Failed with result 'exit-code'.
Apr 10 14:15:26 PSQL_1 systemd[1]: Failed to start etcd.service - etcd - highly-available key value store.
En el resultado anterior, el servicio etcd tiene el estado failed, y el error que le impidió iniciarse es el de la línea 17: el servicio no consigue leer el contenido del directorio /var/lib/etcd/cleanroom. En ese caso, conviene ajustar los permisos del directorio.

Ejemplo de resultado para patroni cuando el servicio funciona
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
● patroni.service - Runners to orchestrate a high-availability PostgreSQL
   Loaded: loaded (/lib/systemd/system/patroni.service; enabled; preset: enabled)
   Drop-In: /etc/systemd/system/patroni.service.d
           └─local.conf
   Active: active (running) since Thu 2026-04-09 16:40:06 CEST; 22h ago
   Process: 283510 ExecStartPre=/usr/bin/testetcd.py (code=exited, status=0/SUCCESS)
Main PID: 283517 (patroni)
   Tasks: 13 (limit: 2227)
   Memory: 56.1M
       CPU: 26min 54.918s
   CGroup: /system.slice/patroni.service
           ├─283517 /usr/bin/python3 /usr/bin/patroni /etc/patroni/config.yml
           ├─283537 /usr/lib/postgresql/15/bin/postgres -D /var/lib/postgresql/15/cleanroomvault5 --config-file=/etc/postgresql/15/cleanroomvault5/postgresql.conf"--listen_addresses=*" --port=5432 --cluster_name=15-cleanroomvault5 --wal_level=replica --hot_standby=on --max_connections=100 --max_wal_senders=10--max_prepared_transactions=0 --max_locks_per_transaction=64 --track_commit_timestamp=off --max_replication_slots=10 --max_worker_processes=8 --wal_log_hints=on
          ├─283538 "postgres: 15-cleanroomvault5: logger "
          ├─283540 "postgres: 15-cleanroomvault5: checkpointer "
           ├─283541 "postgres: 15-cleanroomvault5: background writer "
          ├─283542 "postgres: 15-cleanroomvault5: startup recovering 00000003000000000000000F"
          ├─283545 "postgres: 15-cleanroomvault5: walreceiver "
          └─283547 "postgres: 15-cleanroomvault5: postgres postgres [local] idle"
Apr 10 14:51:07 PSQL_1 patroni[283517]: 2026-04-10 14:51:07,381 INFO: no action. I am (PSQL_1), a secondary, and following a leader (PSQL_2)
Apr 10 14:51:17 PSQL_1 patroni[283517]: 2026-04-10 14:51:17,428 INFO: no action. I am (PSQL_1), a secondary, and following a leader (PSQL_2)
Apr 10 14:51:27 PSQL_1 patroni[283517]: 2026-04-10 14:51:27,381 INFO: no action. I am (PSQL_1), a secondary, and following a leader (PSQL_2)
Apr 10 14:51:37 PSQL_1 patroni[283517]: 2026-04-10 14:51:37,428 INFO: no action. I am (PSQL_1), a secondary, and following a leader (PSQL_2)
Apr 10 14:51:47 PSQL_1 patroni[283517]: 2026-04-10 14:51:47,381 INFO: no action. I am (PSQL_1), a secondary, and following a leader (PSQL_2)
Apr 10 14:51:57 PSQL_1 patroni[283517]: 2026-04-10 14:51:57,428 INFO: no action. I am (PSQL_1), a secondary, and following a leader (PSQL_2)
Apr 10 14:52:07 PSQL_1 patroni[283517]: 2026-04-10 14:52:07,381 INFO: no action. I am (PSQL_1), a secondary, and following a leader (PSQL_2)
Apr 10 14:52:17 PSQL_1 patroni[283517]: 2026-04-10 14:52:17,428 INFO: no action. I am (PSQL_1), a secondary, and following a leader (PSQL_2)
Apr 10 14:52:27 PSQL_1 patroni[283517]: 2026-04-10 14:52:27,381 INFO: no action. I am (PSQL_1), a secondary, and following a leader (PSQL_2)
Apr 10 14:52:37 PSQL_1 patroni[283517]: 2026-04-10 14:52:37,474 INFO: no action. I am (PSQL_1), a secondary, and following a leader (PSQL_2)
Ejemplo de resultado para patroni cuando el servicio está en error

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
● patroni.service - Runners to orchestrate a high-availability PostgreSQL
    Loaded: loaded (/lib/systemd/system/patroni.service; enabled; preset: enabled)
    Drop-In: /etc/systemd/system/patroni.service.d
            └─local.conf
    Active: active (running) since Thu 2026-04-09 16:40:06 CEST; 23h ago
    Process: 283510 ExecStartPre=/usr/bin/testetcd.py (code=exited, status=0/SUCCESS)
Main PID: 283517 (patroni)
    Tasks: 12 (limit: 2227)
    Memory: 61.7M
        CPU: 28min 8.337s
    CGroup: /system.slice/patroni.service
            ├─283517 /usr/bin/python3 /usr/bin/patroni /etc/patroni/config.yml
            ├─283537 /usr/lib/postgresql/15/bin/postgres -D /var/lib/postgresql/15/cleanroomvault5 --config-file=/etc/postgresql/15/cleanroomvault5/postgresql.conf "--listen_addresses=*" --port=5432 --cluster_name=15-cleanroomvault5 --wal_level=replica --hot_standby=on --max_connections=100 --max_wal_senders=10 --max_prepared_transactions=0 --max_locks_per_transaction=64 --track_commit_timestamp=off --max_replication_slots=10 --max_worker_processes=8 --wal_log_hints=on
            ├─283538 "postgres: 15-cleanroomvault5: logger "
            ├─283540 "postgres: 15-cleanroomvault5: checkpointer "
            ├─283541 "postgres: 15-cleanroomvault5: background writer "
            ├─283542 "postgres: 15-cleanroomvault5: startup recovering 00000003000000000000000F"
            └─283547 "postgres: 15-cleanroomvault5: postgres postgres [local] idle"

Apr 10 15:52:37 PSQL_1 patroni[283517]: 2026-04-10 15:52:37,680 WARNING: Loop time exceeded, rescheduling immediately.
Apr 10 15:52:41 PSQL_1 patroni[283517]: 2026-04-10 15:52:37,681 INFO: Lock owner: PSQL_2; I am PSQL_1
Apr 10 15:52:41 PSQL_1 patroni[283517]: 2026-04-10 15:52:41,069 ERROR: Request to server https://PSQL_3:2379 failed: ReadTimeoutError("HTTPSConnectionPool(host='psql_3', port=2379): Read timed out. (read timeout=3.3331721344341836)")
Apr 10 15:52:41 PSQL_1 patroni[283517]: 2026-04-10 15:52:41,069 INFO: Reconnection allowed, looking for another server.
Apr 10 15:52:41 PSQL_1 patroni[283517]: 2026-04-10 15:52:41,069 INFO: Retrying on https://PSQL_1:2379
Apr 10 15:52:41 PSQL_1 patroni[283517]: 2026-04-10 15:52:41,073 ERROR: Request to server https://PSQL_1:2379 failed: MaxRetryError("HTTPSConnectionPool(host='psql_1', port=2379): Max retries exceeded with url: /v3/lease/keepalive (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7fd77c411090>: Failed to establish a new connection: [Errno 111] Connection refused'))")
Apr 10 15:52:41 PSQL_1 patroni[283517]: 2026-04-10 15:52:41,073 INFO: Reconnection allowed, looking for another server.
Apr 10 15:52:41 PSQL_1 patroni[283517]: 2026-04-10 15:52:41,073 INFO: Retrying on https://PSQL_2:2379
Apr 10 15:52:41 PSQL_1 patroni[283517]: 2026-04-10 15:52:41,074 ERROR: Request to server https://PSQL_2:2379 failed: MaxRetryError("HTTPSConnectionPool(host='psql_2', port=2379): Max retries exceeded with url: /v3/lease/keepalive (Caused by NewConnectionError('<urllib3.connection.HTTPSConnection object at 0x7fd77c411090>: Failed to establish a new connection: [Errno 111] Connection refused'))")
Apr 10 15:52:41 PSQL_1 patroni[283517]: 2026-04-10 15:52:41,074 INFO: Reconnection allowed, looking for another server.
En el caso anterior, el servicio tiene el estado active (running) sin funcionar realmente: los logs muestran diversos errores de conexión a etcd, que patroni necesita.
En este ejemplo, patroni no es necesariamente la causa: como depende de etcd, primero hay que resolver los problemas de etcd y después volver a comprobar el estado de patroni.

Procedimientos de resolución de problemas de los servicios

A continuación encontrará un procedimiento de resolución de problemas por servicio. Si tanto etcd como patroni fallan, empiece por etcd.