High availability and architecture¶
This page explains how a keenPGO cluster is put together, how it survives failures, and how to configure it for the level of protection you need.
Who this page is for¶
- Platform engineers deciding how many instances to run and where to place them
- DBAs choosing between asynchronous and synchronous replication
- Application developers who need to know what happens to connections during a failover
Architecture overview¶
A keenPGO deployment has two layers: a control layer that manages desired state, and a data layer that serves your applications.
flowchart TB
subgraph control["Control layer"]
OP["keenPGO operator"]
CR["Cluster resource (desired state)"]
OP -- watches --> CR
end
subgraph data["Data layer"]
direction LR
P["Primary<br/>(read / write)"]
R1["Replica 1<br/>(read only)"]
R2["Replica 2<br/>(read only)"]
P -- replication --> R1
P -- replication --> R2
end
SVC["Primary service"]
APP["Applications"]
OP -- creates and updates --> data
APP --> SVC --> P
P -- backups and WAL --> STORE[("Backup storage")]
Components¶
| Component | Role |
|---|---|
| Operator | Watches cluster definitions and creates, updates and repairs the resources they describe. It does not sit in the data path. |
| Cluster resource | Your declaration of what you want: PostgreSQL version, number of instances, storage, placement rules. |
| Primary instance | The one instance that accepts writes. |
| Replica instances | Continuously copy changes from the primary and can be promoted if it fails. |
| Primary service | A stable address that always points at the current primary, so applications don't need to know which pod it is. |
| Backup storage | Object or volume storage holding base backups and archived write-ahead logs. |
Design principle: the operator is not a single point of failure¶
Once a cluster is running, patroni is responsible for failover. If the operator is down:
- Running clusters keep serving traffic
- Failover still happens
- Changes to cluster definitions wait until the operator returns
What keenPGO protects against¶
| Problem | What happens |
|---|---|
| Primary pod crashes | A replica is promoted automatically |
| Node hosting the primary fails | A replica on another node is promoted |
| A replica fails | The cluster keeps running and the replica is rebuilt |
| Operator unavailable | Existing clusters keep running, as described above |
| Planned maintenance | Handled one instance at a time, see Maintenance without downtime |
Limits of high availability
Replication protects against failures, not mistakes. A dropped table is dropped on every replica. Keep backups, and see disaster recovery for protection against loss of a whole site.
Availability is also bounded by the platform underneath. If Kubernetes itself or its storage layer fails, the database is affected too.
How failover works¶
sequenceDiagram
participant App as Application
participant P as Primary
participant R1 as Replica 1
participant R2 as Replica 2
P-xP: Primary fails
R1->>R1: Detects missing primary
R2->>R2: Detects missing primary
R1->>R2: Compare replication positions
Note over R1,R2: Replica with the most data wins
R1->>R1: Promote to primary
R2->>R1: Follow new primary
App->>R1: Reconnect via primary service
- Detection.
<How a failed primary is noticed and how long keenPGO waits before acting> - Selection.
<How the best replica is chosen, for example the most up-to-date one> - Promotion.
<How the replica becomes the primary> - Redirection. The primary service now points at the new primary, so applications reconnect to the same address.
- Recovery.
<What happens when the old primary returns: rewound, rebuilt, or rejoined as a replica>
Typical failover time: <value, and the conditions under which you measured it>.
Make applications failover-friendly
Connections drop during failover. Use a driver or connection pool that retries, set sensible connection timeouts, and keep transactions short. Done well, users never notice.
Choose a cluster layout¶
| Environment | Instances | Placement | Replication |
|---|---|---|---|
| Development | 1 | Any | Not applicable |
| Production | 3 | Separate nodes | Asynchronous |
Set the number of instances in the cluster resource:
spec:
instances:
- name: instance1
replicas: 3
minAvailable: 1
proxy:
pgBouncer:
replicas: 3
minAvailable: 1
Pod anti-affinity¶
Anti-affinity tells Kubernetes not to put all instances of the same cluster together. Which means we highly recommend to use different node for each instance of same cluster.
Node affinity¶
Node affinity places instances on nodes with particular labels. Typical uses:
- Fast local storage or high-memory nodes for the primary
- Keeping a replica in a specific nodesets
- Isolating databases from other workloads which means dedicated nodes for DB instance in production.
Tolerations¶
Kubernetes Tolerations can help with the scheduling of Pods to appropriate nodes. There are many reasons that a Kubernetes administrator may want to use tolerations, such as restricting the types of Pods that can be assigned to particular Nodes. Reasoning and strategy for using taints and tolerations is outside the scope of this documentation.
Maintenance without downtime¶
Rolling restarts¶
Some PostgreSQL settings only apply after a restart. Restarting everything at once would cause an outage, so keenPGO works through the cluster in order:
flowchart LR
A["Update replica 1"] --> B["Update replica 2"]
B --> C["Controlled switchover<br/>to an updated replica"]
C --> D["Update former primary"]
D --> E["Done: cluster fully updated"]
- Each replica is stopped cleanly, updated and restarted, and must be healthy before the next one begins.
- The primary role is handed to an updated replica in a planned switchover.
- The former primary is updated and rejoins as a replica.
Applications see one short reconnect, not an outage. keenPGO starts this process automatically when it detects a change that needs a restart.
Pod disruption budgets¶
When administrators drain nodes or upgrade Kubernetes, pods are evicted on purpose. A pod disruption budget (PDB) states how many database pods must stay available during such events.
Default behaviour: <explain the default for single-instance and multi-instance clusters>.
Warning
Don't set the minimum equal to your total instance count. Node maintenance would then be blocked indefinitely.
Test failover before you need it¶
Run this in a test environment first.
-
Find the current primary:
-
Delete that pod to simulate a crash:
-
Watch the cluster recover:
-
Confirm that a different pod is now the primary and your application reconnected and kept working.
If something doesn't behave as expected, see troubleshooting.
Production checklist¶
- At least three instances
- Instances on separate nodes, ideally in separate nodes
- Synchronous replication where data loss is unacceptable
- A pod disruption budget below your instance count
- Applications and connection pools retry after connection loss
- Failover tested at least once
- Backups configured and a restore tested
- Monitoring alerts on replica lag and failovers