Aller au contenu

API REST Patroni

Référence des points de terminaison de l’API REST de Patroni et de leurs comportements opérationnels.

Patroni dispose d’une API REST riche, utilisée par Patroni lui-même lors de la course au leader, par l’outil patronictl afin d’effectuer des basculements, des basculements planifiés, des réinitialisations, des redémarrages ou des rechargements, par HAProxy ou tout autre équilibreur de charge pour effectuer des vérifications de santé HTTP, et bien entendu également utilisée pour la surveillance. Ci-dessous figure la liste des points de terminaison de l’API REST de Patroni.


Points de terminaison de vérification de santé

Pour toutes les requêtes de vérification de santé GET, Patroni renvoie un document JSON indiquant l’état du nœud, accompagné du code d’état HTTP. Si vous ne souhaitez pas ou n’avez pas besoin du document JSON, vous pouvez envisager d’utiliser la méthode HEAD ou OPTIONS au lieu de GET.

  • Les requêtes suivantes vers l’API REST de Patroni renvoient le code d’état HTTP 200 uniquement lorsque le nœud Patroni fonctionne en tant que primaire avec verrou de leader :

    • GET /
    • GET /primary
    • GET /read-write
  • GET /standby-leader : renvoie le code d’état HTTP 200 uniquement lorsque le nœud Patroni est en cours d’exécution en tant que leader dans un cluster de secours .

  • GET /leader : renvoie le code d’état HTTP 200 lorsque le nœud Patroni détient le verrou leader. Contrairement à GET /primary et à GET /standby-leader, cette vérification ne dépend pas du fait que PostgreSQL s’exécute en tant que primary ou standby_leader.

  • GET /replica : point de terminaison de vérification de santé de la réplique. Il renvoie le code d’état HTTP 200 uniquement lorsque le nœud Patroni est dans l’état running, que son rôle est replica et que l’étiquette noloadbalance n’est pas définie.

  • GET /replica?replication_state=<required state> : point de contrôle de réplique. En plus des vérifications effectuées par replica, il vérifie également que l’état de réplication correspond à celui requis. Principalement utile avec replication_state=streaming, afin d’exclure les répliques encore en cours de rattrapage lors d’une récupération depuis les archives.

  • GET /replica?lag=<max-lag> : point de contrôle de réplique. En plus des vérifications effectuées par replica, il vérifie également le retard de réplication et renvoie le code d’état 200 uniquement lorsque ce retard est inférieur à la valeur spécifiée. La clé cluster.last_leader_operation provenant du DCS est utilisée pour la position WAL du leader et le calcul du retard sur la réplique, pour des raisons de performance. max-lag peut être spécifié en octets (entier) ou sous forme lisible par l’humain, par exemple 16kB, 64MB, 1GB.

    • GET /replica?lag=1048576
    • GET /replica?lag=1024kB
    • GET /replica?lag=10MB
    • GET /replica?lag=1GB
  • GET /replica?tag_key1=value1&tag_key2=value2 : point de contrôle de réplique. En outre, il vérifie également les étiquettes définies par l’utilisateur key1 et key2 ainsi que leurs valeurs respectives dans la section tags de la configuration YAML. Si une étiquette n’est pas définie pour une instance, ou si la valeur dans la configuration YAML ne correspond pas à la valeur demandée, le code d’état HTTP 503 est renvoyé.

    Dans les requêtes suivantes, comme nous vérifions l’état de leader ou de standby-leader, Patroni ne prend pas en compte les étiquettes définies par l’utilisateur, qui seront ignorées.

    • GET /?tag_key1=value1&tag_key2=value2
    • GET /leader?tag_key1=value1&tag_key2=value2
    • GET /primary?tag_key1=value1&tag_key2=value2
    • GET /read-write?tag_key1=value1&tag_key2=value2
    • GET /standby_leader?tag_key1=value1&tag_key2=value2
    • GET /standby-leader?tag_key1=value1&tag_key2=value2
  • GET /read-only : comme le point de terminaison précédent, mais inclut également le primaire.

  • GET /synchronous ou GET /sync : renvoie le code d’état HTTP 200 uniquement lorsque le nœud Patroni fonctionne en réplique synchrone.

  • GET /read-only-sync : comme le point de terminaison précédent, mais inclut également le primaire.

  • GET /quorum : renvoie le code d’état HTTP 200 uniquement lorsque ce nœud Patroni est répertorié comme nœud de quorum dans synchronous_standby_names sur le primaire.

  • GET /read-only-quorum : comme le point de terminaison précédent, mais inclut également le primaire.

  • GET /asynchronous ou GET /async : renvoie le code d’état HTTP 200 uniquement lorsque le nœud Patroni fonctionne en réplique asynchrone.

  • GET /asynchronous?lag=<max-lag> ou GET /async?lag=<max-lag> : point de contrôle de réplique asynchrone. En plus des vérifications effectuées par asynchronous ou async, il vérifie également le retard de réplication et renvoie le code d’état 200 uniquement lorsque ce retard est inférieur à la valeur spécifiée. La clé cluster.last_leader_operation provenant du DCS est utilisée pour la position WAL du leader et le calcul du retard sur la réplique, pour des raisons de performance. max-lag peut être spécifié en octets (entier) ou sous forme lisible par l’humain, par exemple 16kB, 64MB, 1GB.

    • GET /async?lag=1048576
    • GET /async?lag=1024kB
    • GET /async?lag=10MB
    • GET /async?lag=1GB
  • GET /health : renvoie le code d’état HTTP 200 uniquement lorsque PostgreSQL est en cours d’exécution.

  • GET /liveness : renvoie le code d’état HTTP 200 si la boucle de battement de cœur Patroni fonctionne correctement, et 503 si la dernière exécution remonte à plus de ttl secondes sur le serveur primaire ou à plus de 2*ttl secondes sur la réplique. Peut être utilisé pour livenessProbe.

  • GET /readiness?lag=<max-lag>&mode=apply|write : renvoie le code d’état HTTP 200 lorsque le nœud Patroni fonctionne en tant que leader ou lorsque PostgreSQL est actif, en réplication et pas trop en retard par rapport au leader. Le paramètre lag définit le retard maximal autorisé pour une réplique, avec une valeur par défaut de maximum_lag_on_failover. Le retard peut être spécifié en octets ou en valeurs lisibles par l’humain, par exemple 16kB, 64MB ou 1GB. Le paramètre mode indique si le WAL doit être rejoué (apply) ou simplement reçu (write). La valeur par défaut est apply.

Lorsqu’il est utilisé comme Kubernetes readinessProbe, il garantit que les nouveaux pods démarrés ne deviennent prêts qu’après avoir rattrapé le leader. Cela, combiné à un PodDisruptionBudget, protège contre une terminaison prématurée du leader lors d’un redémarrage progressif des nœuds. Il garantit également que les répliques incapables de suivre la réplication ne traitent pas le trafic en lecture seule. Ce point de terminaison peut être utilisé pour readinessProbe lorsque l’utilisation des endpoints Kubernetes pour les élections de leader n’est pas possible (OpenShift).

Le point de terminaison liveness est très léger et n’exécute aucune requête SQL. Les sondes devraient être configurées de manière à commencer à échouer environ au moment où la clé leader expire. Avec la valeur par défaut de ttl, qui est 30s, les sondes devraient ressembler à l’exemple suivant :

readinessProbe:
  httpGet:
    scheme: HTTP
    path: /readiness
    port: 8008
  initialDelaySeconds: 3
  periodSeconds: 10
  timeoutSeconds: 5
  successThreshold: 1
  failureThreshold: 3
livenessProbe:
  httpGet:
    scheme: HTTP
    path: /liveness
    port: 8008
  initialDelaySeconds: 3
  periodSeconds: 10
  timeoutSeconds: 5
  successThreshold: 1
  failureThreshold: 3

Point de terminaison de surveillance

Le GET /patroni est utilisé par Patroni lors de la course au leader. Il peut également être utilisé par votre système de surveillance. Le document JSON produit par ce point de terminaison a la même structure que le JSON produit par les points de terminaison de vérification de santé.

Exemple : un cluster sain

$ curl -s http://localhost:8008/patroni | jq .
{
  "state": "running",
  "postmaster_start_time": "2024-08-28 19:39:26.352526+00:00",
  "role": "primary",
  "server_version": 160004,
  "xlog": {
    "location": 67395656
  },
  "timeline": 1,
  "replication": [
    {
      "usename": "replicator",
      "application_name": "patroni2",
      "client_addr": "10.89.0.6",
      "state": "streaming",
      "sync_state": "async",
      "sync_priority": 0
    },
    {
      "usename": "replicator",
      "application_name": "patroni3",
      "client_addr": "10.89.0.2",
      "state": "streaming",
      "sync_state": "async",
      "sync_priority": 0
    }
  ],
  "dcs_last_seen": 1692356718,
  "tags": {
    "clonefrom": true
  },
  "database_system_identifier": "7268616322854375442",
  "patroni": {
    "version": "4.0.0",
    "scope": "demo",
    "name": "patroni1"
  }
}

Exemple : un cluster déverrouillé

$ curl -s http://localhost:8008/patroni  | jq .
{
  "state": "running",
  "postmaster_start_time": "2024-08-28 19:39:26.352526+00:00",
  "role": "replica",
  "server_version": 160004,
  "xlog": {
    "received_location": 67419744,
    "replayed_location": 67419744,
    "replayed_timestamp": null,
    "paused": false
  },
  "timeline": 1,
  "replication": [
    {
      "usename": "replicator",
      "application_name": "patroni2",
      "client_addr": "10.89.0.6",
      "state": "streaming",
      "sync_state": "async",
      "sync_priority": 0
    },
    {
      "usename": "replicator",
      "application_name": "patroni3",
      "client_addr": "10.89.0.2",
      "state": "streaming",
      "sync_state": "async",
      "sync_priority": 0
    }
  ],
  "cluster_unlocked": true,
  "dcs_last_seen": 1692356928,
  "tags": {
    "clonefrom": true
  },
  "database_system_identifier": "7268616322854375442",
  "patroni": {
    "version": "4.0.0",
    "scope": "demo",
    "name": "patroni1"
  }
}

Exemple : Un cluster déverrouillé avec le mode failsafe du DCS activé

$ curl -s http://localhost:8008/patroni  | jq .
{
  "state": "running",
  "postmaster_start_time": "2024-08-28 19:39:26.352526+00:00",
  "role": "replica",
  "server_version": 160004,
  "xlog": {
    "location": 67420024
  },
  "timeline": 1,
  "replication": [
    {
      "usename": "replicator",
      "application_name": "patroni2",
      "client_addr": "10.89.0.6",
      "state": "streaming",
      "sync_state": "async",
      "sync_priority": 0
    },
    {
      "usename": "replicator",
      "application_name": "patroni3",
      "client_addr": "10.89.0.2",
      "state": "streaming",
      "sync_state": "async",
      "sync_priority": 0
    }
  ],
  "cluster_unlocked": true,
  "failsafe_mode_is_active": true,
  "dcs_last_seen": 1692356928,
  "tags": {
    "clonefrom": true
  },
  "database_system_identifier": "7268616322854375442",
  "patroni": {
    "version": "4.0.0",
    "scope": "demo",
    "name": "patroni1"
  }
}

Exemple : Un cluster avec le mode pause activé

$ curl -s http://localhost:8008/patroni  | jq .
{
  "state": "running",
  "postmaster_start_time": "2024-08-28 19:39:26.352526+00:00",
  "role": "replica",
  "server_version": 160004,
  "xlog": {
    "location": 67420024
  },
  "timeline": 1,
  "replication": [
    {
      "usename": "replicator",
      "application_name": "patroni2",
      "client_addr": "10.89.0.6",
      "state": "streaming",
      "sync_state": "async",
      "sync_priority": 0
    },
    {
      "usename": "replicator",
      "application_name": "patroni3",
      "client_addr": "10.89.0.2",
      "state": "streaming",
      "sync_state": "async",
      "sync_priority": 0
    }
  ],
  "pause": true,
  "dcs_last_seen": 1724874295,
  "tags": {
    "clonefrom": true
  },
  "database_system_identifier": "7268616322854375442",
  "patroni": {
    "version": "4.0.0",
    "scope": "demo",
    "name": "patroni1"
  }
}

Récupérez les métriques Patroni au format Prometheus via le point de terminaison GET /metrics.

$ curl http://localhost:8008/metrics

# HELP patroni_version Patroni semver without periods. \
# TYPE patroni_version gauge
patroni_version{scope="batman",name="patroni1"} 040000
# HELP patroni_postgres_running Value is 1 if Postgres is running, 0 otherwise.
# TYPE patroni_postgres_running gauge
patroni_postgres_running{scope="batman",name="patroni1"} 1
# HELP patroni_postmaster_start_time Epoch seconds since Postgres started.
# TYPE patroni_postmaster_start_time gauge
patroni_postmaster_start_time{scope="batman",name="patroni1"} 1724873966.352526
# HELP patroni_primary Value is 1 if this node is the leader, 0 otherwise.
# TYPE patroni_primary gauge
patroni_primary{scope="batman",name="patroni1"} 1
# HELP patroni_xlog_location Current location of the Postgres transaction log, 0 if this node is not the leader.
# TYPE patroni_xlog_location counter
patroni_xlog_location{scope="batman",name="patroni1"} 22320573386952
# HELP patroni_standby_leader Value is 1 if this node is the standby_leader, 0 otherwise.
# TYPE patroni_standby_leader gauge
patroni_standby_leader{scope="batman",name="patroni1"} 0
# HELP patroni_replica Value is 1 if this node is a replica, 0 otherwise.
# TYPE patroni_replica gauge
patroni_replica{scope="batman",name="patroni1"} 0
# HELP patroni_sync_standby Value is 1 if this node is a sync standby replica, 0 otherwise.
# TYPE patroni_sync_standby gauge
patroni_sync_standby{scope="batman",name="patroni1"} 0
# HELP patroni_quorum_standby Value is 1 if this node is a quorum standby replica, 0 otherwise.
# TYPE patroni_quorum_standby gauge
patroni_quorum_standby{scope="batman",name="patroni1"} 0
# HELP patroni_xlog_received_location Current location of the received Postgres transaction log, 0 if this node is not a replica.
# TYPE patroni_xlog_received_location counter
patroni_xlog_received_location{scope="batman",name="patroni1"} 0
# HELP patroni_xlog_replayed_location Current location of the replayed Postgres transaction log, 0 if this node is not a replica.
# TYPE patroni_xlog_replayed_location counter
patroni_xlog_replayed_location{scope="batman",name="patroni1"} 0
# HELP patroni_xlog_replayed_timestamp Current timestamp of the replayed Postgres transaction log, 0 if null.
# TYPE patroni_xlog_replayed_timestamp gauge
patroni_xlog_replayed_timestamp{scope="batman",name="patroni1"} 0
# HELP patroni_xlog_paused Value is 1 if the Postgres xlog is paused, 0 otherwise.
# TYPE patroni_xlog_paused gauge
patroni_xlog_paused{scope="batman",name="patroni1"} 0
# HELP patroni_postgres_streaming Value is 1 if Postgres is streaming, 0 otherwise.
# TYPE patroni_postgres_streaming gauge
patroni_postgres_streaming{scope="batman",name="patroni1"} 1
# HELP patroni_postgres_in_archive_recovery Value is 1 if Postgres is replicating from archive, 0 otherwise.
# TYPE patroni_postgres_in_archive_recovery gauge
patroni_postgres_in_archive_recovery{scope="batman",name="patroni1"} 0
# HELP patroni_postgres_server_version Version of Postgres (if running), 0 otherwise.
# TYPE patroni_postgres_server_version gauge
patroni_postgres_server_version{scope="batman",name="patroni1"} 160004
# HELP patroni_cluster_unlocked Value is 1 if the cluster is unlocked, 0 if locked.
# TYPE patroni_cluster_unlocked gauge
patroni_cluster_unlocked{scope="batman",name="patroni1"} 0
# HELP patroni_failsafe_mode_is_active Value is 1 if failsafe mode is active, 0 otherwise.
# TYPE patroni_failsafe_mode_is_active gauge
patroni_failsafe_mode_is_active{scope="batman",name="patroni1"} 0
# HELP patroni_failsafe_mode_enabled Value is 1 if failsafe_mode is enabled, 0 otherwise.
# TYPE patroni_failsafe_mode_enabled gauge
patroni_failsafe_mode_enabled{scope="batman",name="patroni1"} 0
# HELP patroni_failsafe_member Value is 1 if this node is a member of failsafe, 0 otherwise.
# TYPE patroni_failsafe_member gauge
patroni_failsafe_member{scope="batman",name="patroni1"} 0
# HELP patroni_postgres_timeline Postgres timeline of this node (if running), 0 otherwise.
# TYPE patroni_postgres_timeline gauge
patroni_postgres_timeline{scope="batman",name="patroni1"} 24
# HELP patroni_dcs_last_seen Epoch timestamp when DCS was last contacted successfully by Patroni.
# TYPE patroni_dcs_last_seen gauge
patroni_dcs_last_seen{scope="batman",name="patroni1"} 1724874235
# HELP patroni_pending_restart Value is 1 if the node needs a restart, 0 otherwise.
# TYPE patroni_pending_restart gauge
patroni_pending_restart{scope="batman",name="patroni1"} 1
# HELP patroni_is_paused Value is 1 if auto failover is disabled, 0 otherwise.
# TYPE patroni_is_paused gauge
patroni_is_paused{scope="batman",name="patroni1"} 1
# HELP patroni_postgres_state Numeric representation of Postgres state.
# Values: 0=initdb, 1=initdb_failed, 2=custom_bootstrap, 3=custom_bootstrap_failed, 4=creating_replica, 5=running, 6=starting, 7=bootstrap_starting, 8=start_failed, 9=restarting, 10=restart_failed, 11=stopping, 12=stopped, 13=stop_failed, 14=crashed
# TYPE patroni_postgres_state gauge
patroni_postgres_state{scope="batman",name="patroni1"} 5
# HELP patroni_failover_priority Failover priority of this node.
# TYPE patroni_failover_priority gauge
patroni_failover_priority{scope="batman",name="patroni1"} 1

Valeurs d’état PostgreSQL

La métrique patroni_postgres_state fournit une représentation numérique de l’état actuel de l’instance PostgreSQL. Cela est utile pour les systèmes de surveillance et d’alerte qui doivent suivre les changements d’état au fil du temps. Les valeurs numériques sont générées à l’aide de la méthode statique PostgresqlState.get_metrics_description().

Valeur Nom d’état Description
0 initdb Initialisation du nouveau cluster
1 initdb_failed Échec de l’initialisation du nouveau cluster
2 custom_bootstrap Exécution du script d’amorçage personnalisé
3 custom_bootstrap_failed Échec du script d’amorçage personnalisé
4 creating_replica Création d’une réplique à partir du primaire
5 running PostgreSQL fonctionne normalement
6 starting PostgreSQL démarre
7 bootstrap_starting Démarrage après l’amorçage personnalisé
8 start_failed Échec du démarrage de PostgreSQL
9 restarting PostgreSQL redémarre
10 restart_failed Échec du redémarrage de PostgreSQL
11 stopping PostgreSQL s’arrête
12 stopped PostgreSQL est arrêté
13 stop_failed Échec de l’arrêt de PostgreSQL
14 crashed PostgreSQL a planté

Valeurs d’état de PostgreSQL

Note

Ces valeurs numériques sont fixes et ne changeront jamais afin de préserver la rétrocompatibilité avec les systèmes de surveillance existants. Si de nouveaux états sont ajoutés à l’avenir, ils seront affectés à de nouvelles valeurs numériques sans modifier les valeurs existantes.


Points de terminaison d’état du cluster

  • Le point de terminaison GET /cluster génère un document JSON décrivant la topologie et l’état actuels du cluster :
$ curl -s http://localhost:8008/cluster | jq .
{
  "members": [
    {
      "name": "patroni1",
      "role": "leader",
      "state": "running",
      "api_url": "http://10.89.0.4:8008/patroni",
      "host": "10.89.0.4",
      "port": 5432,
      "timeline": 5,
      "tags": {
        "clonefrom": true
      }
    },
    {
      "name": "patroni2",
      "role": "replica",
      "state": "streaming",
      "api_url": "http://10.89.0.6:8008/patroni",
      "host": "10.89.0.6",
      "port": 5433,
      "timeline": 5,
      "tags": {
        "clonefrom": true
      },
      "receive_lag": 0,
      "receive_lsn": "0/4000060",
      "replay_lag": 0,
      "replay_lsn": "0/4000060",
      "lag": 0,
      "lsn": "0/4000060"
    }
  ],
  "scope": "demo",
  "scheduled_switchover": {
    "at": "2023-09-24T10:36:00+02:00",
    "from": "patroni1",
    "to": "patroni3"
  }
}
  • Le point de terminaison GET /history fournit une vue sur l’historique des basculements planifiés ou des basculements du cluster. Le format est très similaire au contenu des fichiers d’historique dans le répertoire pg_wal. La seule différence réside dans le champ horodatage, qui indique quand la nouvelle timeline a été créée.
$ curl -s http://localhost:8008/history | jq .
[
  [
    1,
    25623960,
    "no recovery target specified",
    "2019-09-23T16:57:57+02:00"
  ],
  [
    2,
    25624344,
    "no recovery target specified",
    "2019-09-24T09:22:33+02:00"
  ],
  [
    3,
    25624752,
    "no recovery target specified",
    "2019-09-24T09:26:15+02:00"
  ],
  [
    4,
    50331856,
    "no recovery target specified",
    "2019-09-24T09:35:52+02:00"
  ]
]


Point de terminaison de configuration

GET /config : Obtenir la version actuelle de la configuration dynamique :

$ curl -s http://localhost:8008/config | jq .
{
  "ttl": 30,
  "loop_wait": 10,
  "retry_timeout": 10,
  "maximum_lag_on_failover": 1048576,
  "postgresql": {
    "use_slots": true,
    "use_pg_rewind": true,
    "parameters": {
      "hot_standby": "on",
      "wal_level": "hot_standby",
      "max_wal_senders": 5,
      "max_replication_slots": 5,
      "max_connections": "100"
    }
  }
}

PATCH /config : Modifiez la configuration existante.

$ curl -s -XPATCH -d \
    '{"loop_wait":5,"ttl":20,"postgresql":{"parameters":{"max_connections":"101"}}}' \
    http://localhost:8008/config | jq .
{
  "ttl": 20,
  "loop_wait": 5,
  "maximum_lag_on_failover": 1048576,
  "retry_timeout": 10,
  "postgresql": {
    "use_slots": true,
    "use_pg_rewind": true,
    "parameters": {
      "hot_standby": "on",
      "wal_level": "hot_standby",
      "max_wal_senders": 5,
      "max_replication_slots": 5,
      "max_connections": "101"
    }
  }
}

L’appel d’API REST ci-dessus met à jour la configuration existante et renvoie la configuration mise à jour.

Vérifions que le nœud a bien appliqué cette configuration. Tout d’abord, il devrait commencer à afficher des lignes de journal toutes les 5 secondes (loop_wait=5). Le changement de “max_connections” nécessite un redémarrage, donc le drapeau “pending_restart” devrait être affiché :

$ curl -s http://localhost:8008/patroni | jq .
{
  "postmaster_start_time": "2024-08-28 19:39:26.352526+00:00",
  "xlog": {
    "location": 2197818976
  },
  "timeline": 1,
  "dcs_last_seen": 1724874545,
  "database_system_identifier": "7408277255830290455",
  "pending_restart": true,
  "pending_restart_reason": {
    "max_connections": {
      "old_value": "100",
      "new_value": "101"
    }
  },
  "patroni": {
    "version": "4.0.0",
    "scope": "batman",
    "name": "patroni1"
  },
  "state": "running",
  "role": "primary",
  "server_version": 160004
}

Suppression des paramètres :

Si vous souhaitez supprimer (réinitialiser) un paramètre, il suffit d’envoyer un PATCH avec la valeur null :

$ curl -s -XPATCH -d \
    '{"postgresql":{"parameters":{"max_connections":null}}}' \
    http://localhost:8008/config | jq .
{
  "ttl": 20,
  "loop_wait": 5,
  "retry_timeout": 10,
  "maximum_lag_on_failover": 1048576,
  "postgresql": {
    "use_slots": true,
    "use_pg_rewind": true,
    "parameters": {
      "hot_standby": "on",
      "unix_socket_directories": ".",
      "wal_level": "hot_standby",
      "max_wal_senders": 5,
      "max_replication_slots": 5
    }
  }
}

L’appel ci-dessus retire postgresql.parameters.max_connections de la configuration dynamique.

PUT /config : Il est également possible d’effectuer la réécriture complète d’une configuration dynamique existante de manière inconditionnelle :

$ curl -s -XPUT -d \
    '{"maximum_lag_on_failover":1048576,"retry_timeout":10,"postgresql":{"use_slots":true,"use_pg_rewind":true,"parameters":{"hot_standby":"on","wal_level":"hot_standby","unix_socket_directories":".","max_wal_senders":5}},"loop_wait":3,"ttl":20}' \
    http://localhost:8008/config | jq .
{
  "ttl": 20,
  "maximum_lag_on_failover": 1048576,
  "retry_timeout": 10,
  "postgresql": {
    "use_slots": true,
    "parameters": {
      "hot_standby": "on",
      "unix_socket_directories": ".",
      "wal_level": "hot_standby",
      "max_wal_senders": 5
    },
    "use_pg_rewind": true
  },
  "loop_wait": 3
}

Points de terminaison de basculement planifié et de basculement

Basculement planifié

Le point de terminaison /switchover ne fonctionne que lorsque le cluster est sain (un leader est présent). Il permet également de planifier l’exécution d’un basculement planifié à une heure donnée.

Lors de l’appel du point de terminaison /switchover, un candidat peut être spécifié mais n’est pas obligatoire, contrairement au point de terminaison /failover. Si aucun candidat n’est fourni, tous les nœuds éligibles du cluster participeront à la course au leader après la rétrogradation du leader.

Dans le corps JSON de la requête POST, vous devez spécifier le champ leader. Les champs candidate et scheduled_at sont facultatifs et peuvent être utilisés pour planifier l’exécution d’un basculement planifié à une heure précise.

Selon la situation, les requêtes peuvent renvoyer des codes d’état HTTP et des corps différents. Le code d’état 200 est retourné lorsque le basculement planifié ou le basculement s’est terminé avec succès. Si le basculement planifié a été correctement planifié, Patroni renvoie le code d’état HTTP 202. En cas d’erreur, un code d’état d’erreur (l’un des codes 400, 412 ou 503) est retourné, accompagné de détails dans le corps de la réponse.

DELETE /switchover peut être utilisé pour supprimer le basculement planifié actuellement prévu.

Exemple : effectuer un basculement planifié vers n’importe quelle réplique saine

$ curl -s http://localhost:8008/switchover -XPOST -d '{"leader":"postgresql1"}'
Successfully switched over to "postgresql2"

Exemple : effectuer un basculement planifié vers un nœud spécifique

$ curl -s http://localhost:8008/switchover -XPOST -d \
    '{"leader":"postgresql1","candidate":"postgresql2"}'
Successfully switched over to "postgresql2"

Exemple : planifier un basculement planifié du leader vers n’importe quelle autre réplique saine du cluster à une heure précise.

$ curl -s http://localhost:8008/switchover -XPOST -d \
    '{"leader":"postgresql0","scheduled_at":"2019-09-24T12:00+00"}'
Switchover scheduled

Basculement

Le point de terminaison /failover peut être utilisé pour effectuer un basculement manuel lorsque aucun nœud sain n’est disponible (par exemple, vers une réplique asynchrone si toutes les répliques synchrones ne sont pas suffisamment sains pour être promus). Toutefois, il n’existe aucune obligation pour un cluster de ne pas avoir de leader : le basculement peut également être exécuté sur un cluster sain.

Dans le corps JSON de la requête POST, vous devez spécifier le champ candidate. Si le champ leader est spécifié, un basculement planifié est déclenché à la place.

Exemple :

$ curl -s http://localhost:8008/failover -XPOST -d '{"candidate":"postgresql1"}'
Successfully failed over to "postgresql1"
Avertissement

Soyez très prudent lors de l’utilisation de ce point de terminaison, car cela peut entraîner une perte de données dans certaines situations. Dans la plupart des cas, le point de terminaison de basculement planifié répond aux besoins de l’administrateur.

Les points de terminaison POST /switchover et POST /failover sont utilisés par patronictl_switchover et patronictl_failover respectivement.

DELETE /switchover est utilisé par patronictl flush cluster-name switchover .

Basculement Basculement planifié
Nécessite un leader spécifié non oui
Nécessite un candidat spécifié oui non
Peut être exécuté en pause oui oui (uniquement vers un candidat spécifique)
Peut être planifié non oui (si non en pause)

Comparaison entre basculement et basculement planifié

Réplique de secours saine

Un membre d’un cluster devrait satisfaire plusieurs critères afin de pouvoir participer à la course au rôle de leader lors d’un basculement planifié ou de devenir leader en tant que candidat au basculement ou au basculement planifié :

  • être accessible via l’API Patroni ;
  • ne pas avoir l’étiquette nofailover définie sur true ;
  • avoir le watchdog entièrement fonctionnel (si requis par la configuration) ;
  • en cas de basculement planifié dans un cluster sain ou de basculement automatique, ne pas dépasser le retard maximal de réplication (maximum_lag_on_failover paramètre de configuration ) ;
  • en cas de basculement planifié dans un cluster sain ou de basculement automatique, ne pas avoir un numéro de timeline inférieur à celui du cluster si check_timeline paramètre de configuration est défini sur true ;
  • en mode synchrone :
    • En cas de basculement planifié (avec ou sans candidat) : être listé parmi les membres de la clé /sync ;
    • En cas de basculement dans des clusters sains ou défaillants, cette vérification est omise.
Avertissement

En cas de basculement manuel dans un cluster sans leader, un candidat sera autorisé à être promu même si :

  • il ne figure pas parmi les membres de la clé /sync lorsque le mode synchrone est activé ;
  • son retard dépasse le retard maximal de réplication autorisé ;
  • son numéro de timeline est inférieur au dernier numéro de timeline connu du cluster.


Point de terminaison de redémarrage

  • POST /restart : Vous pouvez redémarrer Postgres sur le nœud spécifique en effectuant l’appel POST /restart. Dans le corps JSON de la requête POST, il est possible de spécifier de manière optionnelle certaines conditions de redémarrage :
    • restart_pending : booléen, si défini à true, Patroni redémarrera PostgreSQL uniquement lorsque le redémarrage est en attente afin d’appliquer certaines modifications de configuration de PostgreSQL.
    • role : effectuer le redémarrage uniquement si le rôle actuel du nœud correspond au rôle fourni dans la requête POST.
    • postgres_version : effectuer le redémarrage uniquement si la version actuelle de PostgreSQL est inférieure à celle spécifiée dans la requête POST.
    • timeout : durée d’attente avant que PostgreSQL ne commence à accepter les connexions. Remplace primary_start_timeout.
    • schedule : horodatage avec fuseau horaire, planifier le redémarrage à une date future.
  • DELETE /restart : supprimer le redémarrage planifié

Les points de terminaison POST /restart et DELETE /restart sont utilisés par patronictl_restart et patronictl flush cluster-name restart respectivement.


Point de terminaison de rechargement

L’appel POST /reload ordonne à Patroni de relire et d’appliquer le fichier de configuration. Cela équivaut à envoyer le signal SIGHUP au processus Patroni. Si vous avez modifié certains paramètres de Postgres nécessitant un redémarrage (comme shared_buffers), vous devez toujours effectuer explicitement le redémarrage de Postgres en appelant le point de terminaison POST /restart ou à l’aide de patronictl_restart .

Le point de terminaison de rechargement est utilisé par patronictl_reload .


Point de terminaison de réinitialisation

POST /reinitialize : réinitialiser le répertoire de données PostgreSQL sur le nœud spécifié. Cette opération n’est autorisée que sur les répliques. Une fois appelée, elle supprime le répertoire de données et démarre pg_basebackup ou une autre méthode de création de réplique .

L’appel peut échouer si Patroni est en boucle de récupération (redémarrage) d’une instance Postgres défaillante. Pour contourner ce problème, il est possible de spécifier {"force":true} dans le corps de la requête.

Vous pouvez spécifier {“from-leader”:true} dans le corps de la requête pour obtenir directement un basebackup depuis le nœud leader. Cela est utile lors de l’exécution d’un reinit lorsque tous les nœuds répliques échouent.

Le point de terminaison de réinitialisation est utilisé par patronictl_reinit .