Replication v1
Physical replication is one of the strengths of PostgreSQL and one of the reasons why some of the largest organizations in the world have chosen it for the management of their data in business continuity contexts. Primarily used to achieve high availability, physical replication also allows scale-out of read-only workloads and offloading of some work from the primary.
Important
This section is about replication within the same Cluster
resource
managed in the same Kubernetes cluster. For information about how to
replicate with another Postgres Cluster
resource, even across different
Kubernetes clusters, please refer to the "Replica clusters"
section.
Application-level replication
Having contributed throughout the years to the replication feature in PostgreSQL, we have decided to build high availability in EDB Postgres for Kubernetes on top of the native physical replication technology, and integrate it directly in the Kubernetes API.
In Kubernetes terms, this is referred to as application-level replication, in contrast with storage-level replication.
A very mature technology
PostgreSQL has a very robust and mature native framework for replicating data from the primary instance to one or more replicas, built around the concept of transactional changes continuously stored in the WAL (Write Ahead Log).
Started as the evolution of crash recovery and point in time recovery technologies, physical replication was first introduced in PostgreSQL 8.2 (2006) through WAL shipping from the primary to a warm standby in continuous recovery.
PostgreSQL 9.0 (2010) introduced WAL streaming and read-only replicas through hot standby. In 2011, PostgreSQL 9.1 brought synchronous replication at the transaction level, supporting RPO=0 clusters. Cascading replication was added in PostgreSQL 9.2 (2012). The foundations for logical replication were established in PostgreSQL 9.4 (2014), and version 10 (2017) introduced native support for the publisher/subscriber pattern to replicate data from an origin to a destination. The table below summarizes these milestones.
Version | Year | Feature |
---|---|---|
8.2 | 2006 | Warm Standby with WAL shipping |
9.0 | 2010 | Hot Standby and physical streaming replication |
9.1 | 2011 | Synchronous replication (priority-based) |
9.2 | 2012 | Cascading replication |
9.4 | 2014 | Foundations of logical replication |
10 | 2017 | Logical publisher/subscriber and quorum-based synchronous replication |
This table highlights key PostgreSQL replication features and their respective versions.
Streaming replication support
At the moment, EDB Postgres for Kubernetes natively and transparently manages
physical streaming replicas within a cluster in a declarative way, based on
the number of provided instances
in the spec
:
Immediately after the initialization of a cluster, the operator creates a user
called streaming_replica
as follows:
Out of the box, the operator automatically sets up streaming replication within
the cluster over an encrypted channel and enforces TLS client certificate
authentication for the streaming_replica
user - as highlighted by the following
excerpt taken from pg_hba.conf
:
Certificates
For details on how EDB Postgres for Kubernetes manages certificates, please refer to the "Certificates" section in the documentation.
If configured, the operator manages replication slots for all the replicas in the HA cluster, ensuring that WAL files required by each standby are retained on the primary's storage, even after a failover or switchover.
Replication slots for High Availability
For details on how EDB Postgres for Kubernetes automatically manages replication slots for the High Availability replicas, please refer to the "Replication slots for High Availability" section below.
Continuous backup integration
In case continuous backup is configured in the cluster, EDB Postgres for Kubernetes
transparently configures replicas to take advantage of restore_command
when
in continuous recovery. As a result, PostgreSQL can use the WAL archive
as a fallback option whenever pulling WALs via streaming replication fails.
Synchronous Replication
EDB Postgres for Kubernetes supports both quorum-based and priority-based synchronous replication for PostgreSQL.
Warning
Please be aware that synchronous replication will halt your write operations if the required number of standby nodes to replicate WAL data for transaction commits is unavailable. In such cases, write operations for your applications will hang. This behavior differs from the previous implementation in EDB Postgres for Kubernetes but aligns with the expectations of a PostgreSQL DBA for this capability.
While direct configuration of the synchronous_standby_names
option is
prohibited, EDB Postgres for Kubernetes allows you to customize its content and extend
synchronous replication beyond the Cluster
resource through the
.spec.postgresql.synchronous
stanza.
Synchronous replication is disabled by default (the synchronous
stanza is not
defined). When defined, two options are mandatory:
method
: eitherany
(quorum) orfirst
(priority)number
: the number of synchronous standby servers that transactions must wait for responses from
Quorum-based Synchronous Replication
PostgreSQL's quorum-based synchronous replication makes transaction commits
wait until their WAL records are replicated to at least a certain number of
standbys. To use this method, set method
to any
.
Migrating from the Deprecated Synchronous Replication Implementation
This section provides instructions on migrating your existing quorum-based synchronous replication, defined using the deprecated form, to the new and more robust capability in EDB Postgres for Kubernetes.
Suppose you have the following manifest:
You can convert it to the new quorum-based format as follows:
Important
The primary difference with the new capability is that PostgreSQL will always prioritize data durability over high availability. Consequently, if no replica is available, write operations on the primary will be blocked. However, this behavior is consistent with the expectations of a PostgreSQL DBA for this capability.
Priority-based Synchronous Replication
PostgreSQL's priority-based synchronous replication makes transaction commits
wait until their WAL records are replicated to the requested number of
synchronous standbys chosen based on their priorities. Standbys listed earlier
in the synchronous_standby_names
option are given higher priority and
considered synchronous. If a current synchronous standby disconnects, it is
immediately replaced by the next-highest-priority standby. To use this method,
set method
to first
.
Important
Currently, this method is most useful when extending
synchronous replication beyond the current cluster using the
maxStandbyNamesFromCluster
, standbyNamesPre
, and standbyNamesPost
options explained below.
Controlling synchronous_standby_names
Content
By default, EDB Postgres for Kubernetes populates synchronous_standby_names
with the names
of local pods in a Cluster
resource, ensuring synchronous replication within
the PostgreSQL cluster. You can customize the content of
synchronous_standby_names
based on your requirements and replication method
(quorum or priority) using the following optional parameters in the
.spec.postgresql.synchronous
stanza:
maxStandbyNamesFromCluster
: the maximum number of pod names from the localCluster
object that can be automatically included in thesynchronous_standby_names
option in PostgreSQL.standbyNamesPre
: a list of standby names (specificallyapplication_name
) to be prepended to the list of local pod names automatically listed by the operator.standbyNamesPost
: a list of standby names (specificallyapplication_name
) to be appended to the list of local pod names automatically listed by the operator.
Warning
You are responsible for ensuring the correct names in standbyNamesPre
and
standbyNamesPost
. EDB Postgres for Kubernetes expects that you manage any standby with an
application_name
listed here, ensuring their high availability. Incorrect
entries can jeopardize your PostgreSQL database uptime.
Examples
Here are some examples, all based on a cluster-example
with three instances:
If you set: