From b6969924eda677a459372162ba448801fc9d48ef Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Thu, 20 Nov 2025 13:01:19 -0800 Subject: [PATCH 1/3] Replica lag docs --- docs/configuration/pgdog.toml/general.md | 20 +++++ .../load-balancer/replication-failover.md | 69 ++++++++++++++++++ docs/images/failover.png | Bin 0 -> 62715 bytes 3 files changed, 89 insertions(+) create mode 100644 docs/features/load-balancer/replication-failover.md create mode 100644 docs/images/failover.png diff --git a/docs/configuration/pgdog.toml/general.md b/docs/configuration/pgdog.toml/general.md index cf48c86..9b522b7 100644 --- a/docs/configuration/pgdog.toml/general.md +++ b/docs/configuration/pgdog.toml/general.md @@ -424,3 +424,23 @@ Default: **`15_000`** (15s) Overrides the TTL set on DNS records received from DNS servers. Allows for faster failover when the primary/replica hostnames are changed by the database hosting provider. Default: **none** (disabled) + +## Replication + +### `lsn_check_delay` + +For how long to delay checking for [replication delay](../../features/replication-failover.md). + +Default: **`infinity`** (disabled) + +### `lsn_check_interval` + +How frequently to run the [replication delay](../../features/replication-failover.md) check. + +Default: **`5_000`** (5s) + +### `lsn_check_timeout` + +Maximum amount of time allowed for the [replication delay](../../features/replication-failover.md) query to return a result. + +Default: **`5_000`** (5s) diff --git a/docs/features/load-balancer/replication-failover.md b/docs/features/load-balancer/replication-failover.md new file mode 100644 index 0000000..3f2a909 --- /dev/null +++ b/docs/features/load-balancer/replication-failover.md @@ -0,0 +1,69 @@ +--- +icon: material/chart-timeline-variant +--- + +# Replication and failover + +!!! note "Experimental feature" + This feature is new and experimental. Make sure to test it before deploying + to production. + +PgDog has built-in functionality for monitoring the state of Postgres replica databases. If configured, it can also automatically detect when a replica is promoted, and redirecting write queries to the new primary. + +## Replication + +When enabled, PgDog will periodically query all databases configured in [`pgdog.toml`](../../configuration/pgdog.toml/databases.md) to fetch the following information: + +1. Logical sequence number (LSN) +2. Value returned by [`pg_is_in_recovery()`](#pg_is_in_recovery) +3. Timestamp of the last transaction + +This information can be viewed in real-time by querying the [admin](../../administration/index.md) database with the `SHOW REPLICATION` command. + +### Replication lag + +In addition to fetching raw metrics, PgDog can calculate the replication lag (also known as "replication delay") between the primary and each replica. The lag is calculated in milliseconds and uses the following formula: + +| Step | Description | +|-|-| +| Primary LSN | Get the LSN from the primary using `pg_current_wal_lsn()`. | +| Replica LSN | Get the LSN from each replica using `pg_last_wal_replay_lsn()` or `pg_last_wal_receive_lsn()`. | +| LSN check | If the two LSNs are identical, replication lag is 0. | +| Calculate lag | If the two LSNs are different, replication lag is `now() - pg_last_xact_replay_timestamp()`. | + +This formula assumes that when the replica's LSN is behind the primary, the primary is still receiving write requests. While this is not always the case, it will show replication lag growing over time if the replication stream is falling behind or is broken. + +### Configuration + +By default, PgDog will not query databases for its replication status. To enable this feature, configure it in [`pgdog.toml`](../../configuration/pgdog.toml/general.md#replication): + +```toml +[general] +# Start running the LSN check immediately. +lsn_check_delay = 0 + +# Run LSN check every second. +lsn_check_interval = 1_000 +``` + +| Setting | Description | +|-|-| +| `lsn_check_delay` | For how long to delay fetching replication status on PgDog launch. By default, this is set to infinity, so the feature is disabled. | +| `lsn_check_interval` | How frequently to re-fetch the replication status. The query is cheap to run, so you can set it to run frequently. | + +## Failover + +
+ Failover +
+ +If `pg_is_in_recovery()` returns `true`, PgDog will assume that the database is the primary and will start sending it write query traffic. The old primary is demoted to the replica role. + +!!! warning "Failover trigger" + PgDog does not detect primary failure and **will not** call `pg_promote()`. It is expected that the databases are managed externally by another tool, like Patroni or AWS RDS, which handle replica promotion. + +### `pg_is_in_recovery()` + +The `pg_is_in_recovery()` function returns `true` if the database is configured as a standby. It can only serve read queries (e.g. `SELECT`) and is expected to be reasonably up-to-date with the primary database. + +Replica databases can be _promoted_ to serve write queries. If that happens, `pg_is_in_recovery()` will return `false`. You can read more about this in the [PostgreSQL documentation](https://www.postgresql.org/docs/18/functions-admin.html#FUNCTIONS-RECOVERY-CONTROL). diff --git a/docs/images/failover.png b/docs/images/failover.png new file mode 100644 index 0000000000000000000000000000000000000000..6ab253cf5f8c9fd104164e33db8f81ea1a4fdf8a GIT binary patch literal 62715 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%0A>^TEO?e6nGAXQ5ld^ZQrXGAK$!h3f2t1J8pYAs@ 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 Date: Thu, 20 Nov 2025 13:03:14 -0800 Subject: [PATCH 2/3] fixes --- docs/features/load-balancer/replication-failover.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/features/load-balancer/replication-failover.md b/docs/features/load-balancer/replication-failover.md index 3f2a909..77717ca 100644 --- a/docs/features/load-balancer/replication-failover.md +++ b/docs/features/load-balancer/replication-failover.md @@ -8,7 +8,7 @@ icon: material/chart-timeline-variant This feature is new and experimental. Make sure to test it before deploying to production. -PgDog has built-in functionality for monitoring the state of Postgres replica databases. If configured, it can also automatically detect when a replica is promoted, and redirecting write queries to the new primary. +PgDog has built-in functionality for monitoring the state of Postgres replica databases. If configured, it can also automatically detect when a replica is promoted and redirect write queries to the new primary. ## Replication @@ -57,7 +57,7 @@ lsn_check_interval = 1_000 Failover -If `pg_is_in_recovery()` returns `true`, PgDog will assume that the database is the primary and will start sending it write query traffic. The old primary is demoted to the replica role. +If `pg_is_in_recovery()` returns `false`, PgDog will assume that the database is the primary and will start sending it write query traffic. The old primary is demoted to the replica role. !!! warning "Failover trigger" PgDog does not detect primary failure and **will not** call `pg_promote()`. It is expected that the databases are managed externally by another tool, like Patroni or AWS RDS, which handle replica promotion. From e6f37deddda369ceffdb3631ceb3191cad8551a9 Mon Sep 17 00:00:00 2001 From: Lev Kokotov Date: Thu, 20 Nov 2025 14:05:59 -0800 Subject: [PATCH 3/3] Docs --- docs/administration/index.md | 1 + docs/administration/replication.md | 25 ++++++++ docs/configuration/pgdog.toml/databases.md | 3 +- docs/configuration/pgdog.toml/general.md | 6 +- .../load-balancer/replication-failover.md | 59 ++++++++++++++++--- 5 files changed, 80 insertions(+), 14 deletions(-) create mode 100644 docs/administration/replication.md diff --git a/docs/administration/index.md b/docs/administration/index.md index dd06263..1d3e9a0 100644 --- a/docs/administration/index.md +++ b/docs/administration/index.md @@ -27,6 +27,7 @@ The admin database name is [configurable](../configuration/pgdog.toml/admin.md). | `SHOW PREPARED` | List prepared statements currently in the cache. | | `SHOW QUERY_CACHE` | List statements currently in the AST cache used for query routing. | | [`MAINTENANCE`](maintenance_mode.md) | Pause all queries to synchronize configuration changes across multiple instances of PgDog. | +| [`SHOW REPLICATION`](replication.md) | Show the status of PostgreSQL replication for each database, including replica lag. | ## Shutting down PgDog diff --git a/docs/administration/replication.md b/docs/administration/replication.md new file mode 100644 index 0000000..3681a03 --- /dev/null +++ b/docs/administration/replication.md @@ -0,0 +1,25 @@ +# Replication + +PgDog provides a real time view into PostgreSQL replication for the purposes of monitoring [replication delay](../features/load-balancer/replication-failover.md#replication) and performing query traffic [failover](../features/load-balancer/replication-failover.md#failover). + +You can view this data by connecting to the [admin](index.md) database and running this query: + +``` +SHOW REPLICATION; +``` + +The following information is returned for each database: + +| Name | Description | Example | +|------|-------------|---------| +| `id` | Connection pool identifier matching pools in [`SHOW POOLS`](pools.md). | `4` | +| `database` | Name of the PostgreSQL database. | `postgres` | +| `user` | User used to connect to the database. | `postgres` | +| `addr` | IP address or DNS name of the server. | `127.0.0.1` | +| `port` | TCP port of the server. | `45001` | +| `shard` | Shard number of the database. | `0` | +| `role` | Database role, either `primary` or `replica`. | `replica` | +| `replica_lag` | Replication lag in milliseconds. | `0` | +| `pg_lsn` | Current LSN (Log Sequence Number) of the database. | `0/21000168` | +| `lsn_age` | Time since the last transaction in milliseconds. | `2245` | +| `pg_is_in_recovery` | Whether the database is in recovery mode (`t` = true, `f` = false). | `t` | diff --git a/docs/configuration/pgdog.toml/databases.md b/docs/configuration/pgdog.toml/databases.md index f49a38a..67f7d9e 100644 --- a/docs/configuration/pgdog.toml/databases.md +++ b/docs/configuration/pgdog.toml/databases.md @@ -48,8 +48,7 @@ Default: **`5432`** ### `role` -Type of role this host performs in your database cluster. This can be either `primary` for primary databases that serve writes (and reads), -and `replica` for PostgreSQL replicas that can only serve reads. +Type of role this host performs in your database cluster. This can be `primary` for primary databases that serve writes (and reads), `replica` for PostgreSQL replicas that can only serve reads, or `auto` to let PgDog decide (see [failover](../../features/load-balancer/replication-failover.md#failover) for more details). Default: **`primary`** diff --git a/docs/configuration/pgdog.toml/general.md b/docs/configuration/pgdog.toml/general.md index 9b522b7..2225aab 100644 --- a/docs/configuration/pgdog.toml/general.md +++ b/docs/configuration/pgdog.toml/general.md @@ -429,18 +429,18 @@ Default: **none** (disabled) ### `lsn_check_delay` -For how long to delay checking for [replication delay](../../features/replication-failover.md). +For how long to delay checking for [replication delay](../../features/load-balancer/replication-failover.md). Default: **`infinity`** (disabled) ### `lsn_check_interval` -How frequently to run the [replication delay](../../features/replication-failover.md) check. +How frequently to run the [replication delay](../../features/load-balancer/replication-failover.md) check. Default: **`5_000`** (5s) ### `lsn_check_timeout` -Maximum amount of time allowed for the [replication delay](../../features/replication-failover.md) query to return a result. +Maximum amount of time allowed for the [replication delay](../../features/load-balancer/replication-failover.md) query to return a result. Default: **`5_000`** (5s) diff --git a/docs/features/load-balancer/replication-failover.md b/docs/features/load-balancer/replication-failover.md index 77717ca..e626612 100644 --- a/docs/features/load-balancer/replication-failover.md +++ b/docs/features/load-balancer/replication-failover.md @@ -14,11 +14,11 @@ PgDog has built-in functionality for monitoring the state of Postgres replica da When enabled, PgDog will periodically query all databases configured in [`pgdog.toml`](../../configuration/pgdog.toml/databases.md) to fetch the following information: -1. Logical sequence number (LSN) -2. Value returned by [`pg_is_in_recovery()`](#pg_is_in_recovery) +1. Log Sequence Number (LSN) +2. Value returned by [`pg_is_in_recovery()`](https://www.postgresql.org/docs/18/functions-admin.html#FUNCTIONS-RECOVERY-CONTROL) 3. Timestamp of the last transaction -This information can be viewed in real-time by querying the [admin](../../administration/index.md) database with the `SHOW REPLICATION` command. +This information can be viewed in real-time by querying the [admin](../../administration/index.md) database with the [`SHOW REPLICATION`](../../administration/replication.md) command. ### Replication lag @@ -33,9 +33,15 @@ In addition to fetching raw metrics, PgDog can calculate the replication lag (al This formula assumes that when the replica's LSN is behind the primary, the primary is still receiving write requests. While this is not always the case, it will show replication lag growing over time if the replication stream is falling behind or is broken. +!!! note "Formula accuracy" + It is possible to calculate the exact replication delay in bytes by subtracting a replica LSN from the primary LSN. While this provides an exact measurement, + that metric isn't very useful: it's hard to translate bytes into a measurement of how stale the data on the replica truly is. + + Approximating the lag in milliseconds is more informative and will be reasonably accurate the majority of the time. + ### Configuration -By default, PgDog will not query databases for its replication status. To enable this feature, configure it in [`pgdog.toml`](../../configuration/pgdog.toml/general.md#replication): +By default, PgDog will not query databases for their replication status. To enable this feature, configure it in [`pgdog.toml`](../../configuration/pgdog.toml/general.md#replication): ```toml [general] @@ -49,7 +55,11 @@ lsn_check_interval = 1_000 | Setting | Description | |-|-| | `lsn_check_delay` | For how long to delay fetching replication status on PgDog launch. By default, this is set to infinity, so the feature is disabled. | -| `lsn_check_interval` | How frequently to re-fetch the replication status. The query is cheap to run, so you can set it to run frequently. | +| `lsn_check_interval` | How frequently to re-fetch the replication status. The query used is fast, so you can configure it to run frequently. | + +Decreasing the value of `lsn_check_interval` will produce more accurate statistics, at the cost of running additional queries through the same connection pool used by normal client connections. + +It's common for PgDog deployments to be serving upwards of 30,000-50,000 queries per second per pooler process, so you can run the LSN check query quite frequently without noticeable impact on system latency. ## Failover @@ -57,13 +67,44 @@ lsn_check_interval = 1_000 Failover -If `pg_is_in_recovery()` returns `false`, PgDog will assume that the database is the primary and will start sending it write query traffic. The old primary is demoted to the replica role. +If the `pg_is_in_recovery()` function returns `true`, the database is configured as a standby. It can only serve read queries (e.g. `SELECT`) and is expected to be reasonably up-to-date with the primary database. + +Replica databases can be promoted to serve write queries. If that happens, `pg_is_in_recovery()` will start returning `false`. You can read more about this in the [PostgreSQL documentation](https://www.postgresql.org/docs/18/functions-admin.html#FUNCTIONS-RECOVERY-CONTROL). !!! warning "Failover trigger" PgDog does not detect primary failure and **will not** call `pg_promote()`. It is expected that the databases are managed externally by another tool, like Patroni or AWS RDS, which handle replica promotion. -### `pg_is_in_recovery()` +If the `pg_is_in_recovery()` function returns `false`, PgDog will assume that the database is the primary and will start sending it write query traffic. The old primary is demoted to the replica role. + +### Configuration + +Failover is disabled by default. To enable it, change all configured databases in [`pgdog.toml`](../../configuration/pgdog.toml/databases.md) to use the `"auto"` role, for example: + +```toml +[[databases]] +name = "prod" +host = "10.0.0.1" +role = "auto" + +[[databases]] +name = "prod" +host = "10.0.0.2" +role = "auto" +``` + +On startup, PgDog will connect to each database, find out if they are in recovery, and automatically reload its configuration with the determined roles. + +### Split brain + +If a replica is promoted while the existing primary is alive and serving queries, write queries can be routed to either database, causing data loss. This type of error is called "split brain", indicating that the database cluster no longer has an authoritative source of data it's managing. + +PgDog doesn't currently protect against this condition: it solely relies on the value returned by `pg_is_in_recovery()` to make its routing decisions. + +To avoid causing split-brain failures, make sure to use tools like Patroni or managed offerings like AWS RDS, Aurora and others, which correctly orchestrate failovers. If managing replicas manually, make sure to **shut down** the primary _before_ calling `pg_promote()` on a replica. + +!!! note "Rewinding" + Since PgDog doesn't trigger failovers, it doesn't decide which (most up-to-date) replica should be the failover candidate. It exclusively relies on the value of `pg_is_in_recovery()` to update its routing tables. -The `pg_is_in_recovery()` function returns `true` if the database is configured as a standby. It can only serve read queries (e.g. `SELECT`) and is expected to be reasonably up-to-date with the primary database. +### Logical replication -Replica databases can be _promoted_ to serve write queries. If that happens, `pg_is_in_recovery()` will return `false`. You can read more about this in the [PostgreSQL documentation](https://www.postgresql.org/docs/18/functions-admin.html#FUNCTIONS-RECOVERY-CONTROL). +Replica databases that use [logical replication](https://www.postgresql.org/docs/current/logical-replication.html) to synchronize data are, underneath, regular primaries. PgDog is currently unable to detect which database in a logically replicated cluster is the primary and which are replicas.