Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/architecture/comparison.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ PgDog aims to be the de facto PostgreSQL proxy and pooler. Below is a feature co

| Feature | PgBouncer | PgCat | PgDog |
|-|-|-|-|
| [Connection pooler](../features/transaction-mode.md) | :material-check-circle-outline: | :material-check-circle-outline: | :material-check-circle-outline: |
| [Connection pooler](../features/connection-pooler/transaction-mode.md) | :material-check-circle-outline: | :material-check-circle-outline: | :material-check-circle-outline: |
| Load balancer | Requires external TCP proxy | :material-check-circle-outline: | :material-check-circle-outline: |
| [Read/write separation](../features/load-balancer/index.md) | No | Basic support | Advanced support handling edge cases |
| [Failover](../features/load-balancer/healthchecks.md) | No | :material-check-circle-outline: | :material-check-circle-outline: |
Expand All @@ -19,7 +19,7 @@ PgDog aims to be the de facto PostgreSQL proxy and pooler. Below is a feature co
| [Metrics](../features/metrics.md) | Admin database only | OpenMetrics & admin database | OpenMetrics & admin database |
| [Mirroring](../features/mirroring.md) | No | Partial support | :material-check-circle-outline: |
| TLS | :material-check-circle-outline: | :material-check-circle-outline: | :material-check-circle-outline: |
| [Prepared statements](../features/prepared-statements.md) | :material-check-circle-outline: | Partial support | :material-check-circle-outline: |
| [Prepared statements](../features/connection-pooler/prepared-statements.md) | :material-check-circle-outline: | Partial support | :material-check-circle-outline: |
| [Plugins](../features/plugins/index.md) | No | Hardcoded in core | :material-check-circle-outline: |
| Session evariables in transaction mode | Partial support | Partial support | :material-check-circle-outline: |

Expand Down
2 changes: 1 addition & 1 deletion docs/client-drivers.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ We benchmarked this to be 5 times faster than normal `pg_query` parsing, which s

### Prisma

Prisma doesn't correctly use the `IN` clause with arrays, causing it to generate a very large number of unique prepared statements. This is not a big problem, but if left unchecked, can cause heavy memory usage in PgDog. Consider setting a lower prepared statements [cache limit](features/prepared-statements.md#cache-limit):
Prisma doesn't correctly use the `IN` clause with arrays, causing it to generate a very large number of unique prepared statements. This is not a big problem, but if left unchecked, can cause heavy memory usage in PgDog. Consider setting a lower prepared statements [cache limit](features/connection-pooler/prepared-statements.md#cache-limit):

=== "pgdog.toml"
```toml
Expand Down
10 changes: 5 additions & 5 deletions docs/configuration/pgdog.toml/general.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Available options:
- `statement`


See [transaction mode](../../features/transaction-mode.md) and [session mode](../../features/session-mode.md) for more details on each mode.
See [transaction mode](../../features/connection-pooler/transaction-mode.md) and [session mode](../../features/connection-pooler/session-mode.md) for more details on each mode.

Default: **`transaction`**

Expand Down Expand Up @@ -170,7 +170,7 @@ from abnormal conditions like hardware failure.

### `rollback_timeout`

How long to allow for `ROLLBACK` queries to run on server connections with unfinished transactions. See [transaction mode](../../features/transaction-mode.md) for more details.
How long to allow for `ROLLBACK` queries to run on server connections with unfinished transactions. See [transaction mode](../../features/connection-pooler/transaction-mode.md) for more details.

Default: **`5_000`** (5s)

Expand Down Expand Up @@ -379,7 +379,7 @@ Default: **`extended`**
### `prepared_statements_limit`

Number of prepared statements that will be allowed for each server connection. If this limit is reached, the least used statement is closed
and replaced with the newest one. Additionally, any unused statements in the [global cache](../../features/prepared-statements.md) above this
and replaced with the newest one. Additionally, any unused statements in the [global cache](../../features/connection-pooler/prepared-statements.md) above this
limit will be removed.

Default: **`none`** (unlimited)
Expand All @@ -388,7 +388,7 @@ Default: **`none`** (unlimited)

### `pub_sub_channel_size`

Enables support for [pub/sub](../../features/pub_sub.md) and configures the size of the background task queue.
Enables support for [pub/sub](../../features/connection-pooler/pub_sub.md) and configures the size of the background task queue.

Default: **`none`** (disabled)

Expand Down Expand Up @@ -476,7 +476,7 @@ Default: **`1_000`**
!!! warning "Deprecated setting"
This setting is deprecated. Use [`query_parser`](#query_parser) instead.

Force-enable query parsing to take advantage of its features in non-sharded databases, like [advisory locks](../../features/transaction-mode.md#advisory-locks) or managing [session state](../../features/transaction-mode.md#session-state).
Force-enable query parsing to take advantage of its features in non-sharded databases, like [advisory locks](../../features/connection-pooler/transaction-mode.md#advisory-locks) or managing [session state](../../features/connection-pooler/transaction-mode.md#session-state).

### `query_parser`

Expand Down
4 changes: 2 additions & 2 deletions docs/configuration/users.toml/users.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ Overrides [`min_pool_size`](../pgdog.toml/general.md#min_pool_size) for this use

### `pooler_mode`

Overrides [`pooler_mode`](../pgdog.toml/general.md) for this user. This allows users in [session mode](../../features/session-mode.md) to connect to the
same PgDog instance as users in [transaction mode](../../features/transaction-mode.md).
Overrides [`pooler_mode`](../pgdog.toml/general.md) for this user. This allows users in [session mode](../../features/connection-pooler/session-mode.md) to connect to the
same PgDog instance as users in [transaction mode](../../features/connection-pooler/transaction-mode.md).

Default: **none** (defaults to `pooler_mode` from `pgdog.toml`)

Expand Down
2 changes: 1 addition & 1 deletion docs/enterprise_edition/control_plane/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ helm repo add pgdogdev-ee https://helm-ee.pgdog.dev
helm install control pgdogdev-ee/pgdog-control
```

The chart has a few external requirements, [documented below](#requirements).
The chart has a few external requirements, [documented below](#dependencies).

## Dependencies

Expand Down
2 changes: 1 addition & 1 deletion docs/features/.pages
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
nav:
- 'index.md'
- 'connection-pooler'
- 'load-balancer'
- 'sharding'
- 'plugins'
- 'transaction-mode.md'
- '...'
- 'mirroring.md'
- 'multi-tenancy.md'
Expand Down
5 changes: 5 additions & 0 deletions docs/features/connection-pooler/.pages
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
nav:
- 'index.md'
- 'transaction-mode.md'
- 'pub_sub.md'
- '...'
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ icon: material/connection

# Connection recovery

PostgreSQL database connections are expensive to create so PgDog does its best not to close them unless absolutely necessary. In case a client disconnects before fully processing a query response, PgDog will attempt to preserve the connection using several recovery steps.
PostgreSQL database connections are expensive to create so PgDog does its best not to close them unless absolutely necessary. In case a client disconnects before fully processing a query response, PgDog will attempt to preserve the connection using several recovery methods.

## Abandoned transactions

Expand Down Expand Up @@ -69,7 +69,7 @@ Just like [abandoned transactions](#abandoned-transactions), this protects Postg

### Configuration

Connection recovery is an optional feature, enabled by default. You can change how it behaves through configuration:
Connection recovery is an optional feature, **enabled** by default. You can change how it behaves through configuration:

=== "pgdog.toml"
```toml
Expand All @@ -81,6 +81,8 @@ Connection recovery is an optional feature, enabled by default. You can change h
connectionRecovery: recover
```

The following connection recovery options are available:

| Configuration value | Description |
|-|-|
| `recover` | Attempt full connection recovery, including rollback and resynchronization. This is the default. |
Expand All @@ -103,7 +105,7 @@ To make sure abandoned server connections don't block normal operations, PgDog s

Just like server connections, PgDog can maintain client connections (application --> PgDog) during incidents. This helps preserve application-side connection pools and avoids re-creating thousands of connections unnecessarily.

While enabled by default, some applications don't behave well when their queries return errors instead of results. Therefore, this feature is configurable and can be disabled:
While **enabled** by default, some applications don't behave well when their queries return errors instead of results. Therefore, this feature is configurable and can be disabled:

=== "pgdog.toml"
```toml
Expand All @@ -115,6 +117,8 @@ While enabled by default, some applications don't behave well when their queries
clientConnectionRecovery: drop
```

The following client connection recovery options are available:

| Configuration value | Description |
|-|-|
| `recover` | Attempt to maintain client connections open after database-related errors, like `checkout timeout`. |
Expand Down
55 changes: 55 additions & 0 deletions docs/features/connection-pooler/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
icon: material/transit-connection-variant
---

# Connection pooler

PgDog is first and foremost a connection pooler. It can proxy thousands (even hundreds of thousands) of application connections with only a handful of actual PostgreSQL connections. This feature is essential to large and busy databases. Without connection pooling, it would be very difficult to use Postgres in production.

## PgDog vs. other poolers

The Postgres ecosystem has many other connection poolers, e.g., the ubiquitous PgBouncer, RDS Proxy, and others. So, why build PgDog and what makes it unique?

### Connection state

PgDog can handle `SET` commands and preserve connection state in [transaction mode](transaction-mode.md). For example, this command works without polluting the connection state for other clients:

```postgresql
SET application_name TO 'sidekiq';
```

PgDog preserves this and other session parameters in transaction mode, allowing multiple applications to use the same connection pool. This increases pool efficiency at the small cost of running a few extra `SET` commands.

Additionally, it's common to use GUC settings to temporarily change connection state, e.g., to work with RLS (row-level security) or to execute long queries without triggering a statement timeout. Applications using PgBouncer need to bypass it and connect to the database directly. With PgDog, it just works.

!!! note "Connection pinning"
Unlike RDS Proxy, PgDog doesn't pin sessions or have a query length limit that would trigger that behavior.

### Multithreading

PgDog is multithreaded and asynchronous. Under the hood, we use the popular [Tokio](https://tokio.rs) Rust async runtime. This allows PgDog to serve more queries per second on machines with multiple CPUs.

While it's possible to achieve a similar effect with PgBouncer in port reuse mode (i.e., `so_reuseport`), what sets PgDog apart is its ability to reuse the _same_ connection pool to serve more clients inside the same process. This improves pool utilization and allows PgDog to keep the number of connections to PostgreSQL low while serving more queries per second than PgBouncer.

Additionally, PgDog is easier to manage from an infrastructure/DevOps perspective, since a single multithreaded process will emit only one set of [metrics](../metrics.md).

### Pub/sub

If your application uses `LISTEN`/`NOTIFY`, e.g., [DBOS](https://dbos.dev) or another job queue, it would traditionally need to connect to Postgres directly. PgDog implements its own pub/sub queue and sends and receives `LISTEN`/`NOTIFY` messages for clients connected to it.

This allows applications to use `LISTEN`/`NOTIFY` in [transaction mode](pub_sub.md), just like any other Postgres feature.

### Connection recovery

Unlike other poolers, PgDog takes extra care not to close connections to Postgres unless absolutely necessary. It goes as far as to roll back abandoned transactions and drain abandoned queries. This protects the database against connection storms created by buggy applications.

You can read more about connection recovery methods [here](connection-recovery.md).

## Read more

{{ next_steps_links([
("Transaction mode", "/features/connection-pooler/transaction-mode/", "Multiplex PostgreSQL server connections across thousands of clients."),
("Pub/Sub", "/features/connection-pooler/pub_sub/", "Use LISTEN and NOTIFY through PgDog in transaction mode."),
("Connection recovery", "/features/connection-pooler/connection-recovery/", "Recover interrupted server connections if clients abruptly disconnect."),
("Prepared statements", "/features/connection-pooler/prepared-statements/", "Use named prepared statements efficiently in transaction mode."),
]) }}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@ entry and gives it a unique name.
The `Parse` message is then renamed and sent to Postgres. This way, multiple clients can send the same prepared
statement through PgDog without causing `"duplicate prepared statement"` errors.

<center>
<img src="/images/prepared-statements-1.png" width="100%" height="auto" alt="Prepared statements">
<center style="margin: 1rem 0">
<img src="/images/prepared-statements-1.png" class="theme-aware-image" width="95%" height="auto" alt="Prepared statements">
<p>Prepared statements flow</p>
</center>

While the global cache helps with statement reuse, each client keeps its own mapping of prepared statement names.
Expand All @@ -44,43 +45,51 @@ This limit is strictly enforced on server connections: if a prepared statement n

Since clients re-use prepared statements, this limit isn't enforced for clients: they can prepare as many statements as they wish (and you have memory for). Each statement keeps a counter of when it's used by a client. If the counter reaches zero, i.e., all clients either closed it explicitly or disconnected, the statement is removed from the global cache.

### Tracking used statements
## Tracking used statements

The number of prepared statements and what they are can be tracked by executing this command on the [admin database](../administration/index.md):
The number of prepared statements and what they are can be tracked by executing this command on the [admin database](../../administration/index.md):

```
SHOW PREPARED;
```
=== "Command"

Additionally, each server connection entry in [`SHOW SERVERS`](../administration/servers.md) will report the number of currently prepared statements.
```
SHOW PREPARED;
```
=== "Output"
```
name | statement | rewrite | used_by | memory_used
-----------+-------------------------------------------------------+---------+---------+-------------
__pgdog_1 | SELECT abalance FROM pgbench_accounts WHERE aid = $1; | | 4 | 144
(1 row)
```

Additionally, each server connection entry in the admin [`SHOW SERVERS`](../../administration/servers.md) view will report the number of currently prepared statements.

### Metrics

The number of prepared statements in the global cache, and for each connection pool, is reported in OTEL and OpenMetrics [exporters](../metrics.md).

## Simple protocol

While prepared statements are typically sent using the extended protocol (`Parse`, `Bind`, `Describe`), Postgres
While prepared statements are typically sent using the extended protocol (i.e., `Parse`, `Bind`, `Describe` messages), Postgres
supports preparing statements using the `PREPARE` command, and executing them using the `EXECUTE` command.

PgDog supports rewriting these prepared statements to make sure their names are globally unique, just like with the extended
protocol.

For example:

```postgresql
PREPARE test AS SELECT * FROM users;
```
protocol, for example:

will be rewritten by PgDog to:
=== "Original statement"
```postgresql
PREPARE test AS SELECT * FROM users;
```

```postgresql
PREPARE __pgdog_1 AS SELECT * FROM users;
```
=== "Rewritten statement"
```postgresql
PREPARE __pgdog_1 AS SELECT * FROM users;
```

Statements sent over the simple protocol are not checked against the global cache. Each new statement is given a unique
global name. Since this requires PgDog to parse _each_ incoming query, and that's computationally expensive, this feature is **disabled** by default.

!!! note
`full` extends `extended`: it rewrites named extended-protocol statements in addition to simple-protocol `PREPARE`/`EXECUTE`.

You can enable it in [`pgdog.toml`](../configuration/pgdog.toml/general.md#prepared_statements):
You can enable simple statement rewrites in [`pgdog.toml`](../../configuration/pgdog.toml/general.md#prepared_statements):

=== "pgdog.toml"
```toml
Expand All @@ -95,22 +104,9 @@ You can enable it in [`pgdog.toml`](../configuration/pgdog.toml/general.md#prepa
Statements prepared using this method can be executed normally with `Bind` and `Execute` messages. Result data types can be inspected with `Describe`, just
like a regular prepared statement.

!!! note "Sharding support"
Currently, `EXECUTE` of prepared statements requiring [sharding](sharding/index.md) isn't supported. By default, the statement
will be sent to all shards.
!!! warning "Sharding support"
Currently, `EXECUTE` command for [sharded](../sharding/index.md) prepared statements is not supported. Such commands will be sent to all shards.

## Unnamed statements

By default, unnamed (or anonymous) prepared statements are not cached and are sent to Postgres as-is. This works fine for most client drivers because they send the entire query in a single request. However, some drivers, like `go/pq` do not.

To make those drivers work, consider caching and rewriting unnamed prepared statements, like so:

=== "pgdog.toml"
```toml
[general]
prepared_statements = "extended_anonymous"
```
=== "Helm chart"
```yaml
preparedStatements: extended_anonymous
```
Unnamed (aka anonymous) prepared statements are not cached and are sent to Postgres connections as-is.
Loading
Loading