Deploy PostgreSQL streaming replication between two ECS instances for read/write splitting, data redundancy, and manual failover.
How it works
Replication workflow
-
WAL generation: The primary node processes write transactions and records changes to the WAL.
-
WAL transmission: The
walsenderprocess on the primary streams WAL records in real time to thewalreceiverprocess on the secondary. -
Data synchronization: The
walreceiveron the secondary receives the WAL. The recovery process replays WAL records to keep the secondary in sync with the primary. -
Read-only service: The secondary serves read-only queries while synchronizing.
Procedure
Step 1: Prepare ECS instances
Create two Elastic Compute Service (ECS) instances as the primary and secondary nodes:
-
Specifications: ecs.c7.large (2 vCPU, 4 GiB) or higher.
-
Image: Alibaba Cloud Linux 3.2104 LTS 64-bit, CentOS 8.x 64-bit, or Ubuntu 22.04 64-bit.
-
Network: Both instances must be in the same VPC, region, and zone to minimize network latency. They also need public network access to download installation packages.
The secondary node acts as a data replica for failover.
-
Security group: Assign both instances to the same security group.
Example private IP addresses used in this tutorial:
-
Primary node:
192.168.1.10 -
Secondary node:
192.168.1.20
Step 2: Configure the primary node
Alibaba Cloud Linux 3/CentOS 8
The following steps use PostgreSQL 18.
Log on to an ECS instance.
Go to ECS console - Instances. In the top-left corner, select the region and resource group for the target instance.
Navigate to the details page of the target instance. Click Connect and select Workbench. Follow the on-screen prompts to access the terminal.
-
Install PostgreSQL 18.
# Check the OS type. If it is CentOS 8, disable the default PostgreSQL module. if [ -f /etc/os-release ]; then . /etc/os-release if [ "$ID" = "centos" ] && [ "${VERSION_ID%%.*}" = "8" ]; then sudo dnf --assumeyes module disable postgresql fi fi # Add the official PostgreSQL YUM repository. sudo rpm -Uvh http://mirrors.cloud.aliyuncs.com/postgresql/repos/yum/reporpms/EL-8-x86_64/pgdg-redhat-repo-latest.noarch.rpm # Replace the repository URL with an Alibaba Cloud mirror to speed up downloads. sudo sed -i "s@https://download.postgresql.org/pub@http://mirrors.cloud.aliyuncs.com/postgresql@g" /etc/yum.repos.d/pgdg-redhat-all.repo sudo sed -i "s@\$releasever@8@g" /etc/yum.repos.d/pgdg-redhat-all.repo # Install the PostgreSQL 18 server. sudo dnf install -y postgresql18-server -
Initialize the database. This creates the data directory
/var/lib/pgsql/18/data/and default configuration files.sudo /usr/pgsql-18/bin/postgresql-18-setup initdb -
Edit
/var/lib/pgsql/18/data/postgresql.confto configure replication parameters.# Listen for connections from all network interfaces. listen_addresses = '*' # Set the WAL level to replica. wal_level = replica # Set the maximum number of streaming replication connections. This should be greater than or equal to the number of secondary nodes. max_wal_senders = 3 # Enable WAL archiving. If a secondary node is offline for a long time and the primary node cleans up old WALs, the secondary node can automatically recover from the archive. archive_mode = on # Configure the archiving scheme. This example archives to /mnt/server/archivedir/. archive_command = 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f' -
Start the service, create a replication user, and create a replication slot.
-
Start PostgreSQL and enable it on boot.
sudo systemctl enable postgresql-18.service sudo systemctl start postgresql-18.service -
Create a PostgreSQL user with
REPLICATIONpermissions.sudo -u postgres psql -c "CREATE ROLE replica_user WITH REPLICATION LOGIN PASSWORD 'YOUR_SECURE_PASSWORD';" -
Create a physical replication slot. This prevents the primary from removing WAL logs before the secondary receives them, allowing a disconnected secondary to resume without a full re-clone.
sudo -u postgres psql -c "SELECT pg_create_physical_replication_slot('secondary_slot');"
-
-
Add a replication rule to the
pg_hba.conffile (/var/lib/pgsql/18/data/pg_hba.conf) to allow the secondary node to connect.# TYPE DATABASE USER ADDRESS METHOD host replication replica_user 192.168.1.20/32 scram-sha-256-
replica_user: The replication username. -
192.168.1.20: Secondary node private IP address.
-
-
Restart PostgreSQL to apply the changes.
sudo systemctl restart postgresql-18.service
Ubuntu/Debian
Applies to Ubuntu 22.04+ and Debian 11+. The steps use PostgreSQL 18.
Log on to an ECS instance.
Go to ECS console - Instances. In the top-left corner, select the region and resource group for the target instance.
Navigate to the details page of the target instance. Click Connect and select Workbench. Follow the on-screen prompts to access the terminal.
-
Install PostgreSQL 18.
# Add the official PostgreSQL APT repository and use an Alibaba Cloud mirror. sudo sh -c 'echo "deb [signed-by=/etc/apt/trusted.gpg.d/postgresql.gpg] http://mirrors.cloud.aliyuncs.com/postgresql/repos/apt/ $(lsb_release -sc)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' # Import the repository signature key. wget -qO - http://mirrors.cloud.aliyuncs.com/postgresql/repos/apt/ACCC4CF8.asc | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg # Update the package list and install. sudo apt-get update sudo apt-get install -y postgresql-18 -
Edit
/etc/postgresql/18/main/postgresql.confto configure replication parameters.# Listen for connections from all network interfaces. listen_addresses = '*' # Set the WAL level to replica. wal_level = replica # Set the maximum number of streaming replication connections. This should be greater than or equal to the number of secondary nodes. max_wal_senders = 3 # Enable WAL archiving. If a secondary node is offline for a long time and the primary node cleans up old WALs, the secondary node can automatically recover from the archive. archive_mode = on # Configure the archiving scheme. This example archives to /mnt/server/archivedir/. archive_command = 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f' -
Start the service, create a replication user, and create a replication slot.
-
Start PostgreSQL and enable it on boot.
sudo systemctl enable postgresql.service sudo systemctl start postgresql.service -
Create a PostgreSQL user with
REPLICATIONpermissions.sudo -u postgres psql -c "CREATE ROLE replica_user WITH REPLICATION LOGIN PASSWORD 'YOUR_SECURE_PASSWORD';" -
Create a physical replication slot. This prevents the primary from removing WAL logs before the secondary receives them, allowing a disconnected secondary to resume without a full re-clone.
sudo -u postgres psql -c "SELECT pg_create_physical_replication_slot('secondary_slot');"
-
-
Add a replication rule to the
pg_hba.conffile (/etc/postgresql/18/main/pg_hba.conf) to allow the secondary node to connect.# TYPE DATABASE USER ADDRESS METHOD host replication replica_user 192.168.1.20/32 scram-sha-256-
replica_user: The replication username. -
192.168.1.20: Secondary node private IP address.
-
-
Restart PostgreSQL to apply the changes.
sudo systemctl restart postgresql.service
Alibaba Cloud Linux 2/CentOS 7
The following steps use PostgreSQL 15.
Log on to an ECS instance.
Go to ECS console - Instances. In the top-left corner, select the region and resource group for the target instance.
Navigate to the details page of the target instance. Click Connect and select Workbench. Follow the on-screen prompts to access the terminal.
-
Install PostgreSQL 15.
# Add the official PostgreSQL YUM repository. sudo rpm -Uvh http://mirrors.cloud.aliyuncs.com/postgresql/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm # Replace the repository URL with an Alibaba Cloud mirror to speed up downloads. sudo sed -i "s@https://download.postgresql.org/pub@http://mirrors.cloud.aliyuncs.com/postgresql@g" /etc/yum.repos.d/pgdg-redhat-all.repo sudo sed -i "s@\$releasever@7@g" /etc/yum.repos.d/pgdg-redhat-all.repo # Install the PostgreSQL 15 server. sudo yum install -y postgresql15-server -
Initialize the database. This creates the data directory
/var/lib/pgsql/15/data/and default configuration files.sudo /usr/pgsql-15/bin/postgresql-15-setup initdb -
Edit
/var/lib/pgsql/15/data/postgresql.confto configure replication parameters.# Listen for connections from all network interfaces. listen_addresses = '*' # Set the WAL level to replica. wal_level = replica # Set the maximum number of streaming replication connections. This should be greater than or equal to the number of secondary nodes. max_wal_senders = 3 # Enable WAL archiving. If a secondary node is offline for a long time and the primary node cleans up old WALs, the secondary node can automatically recover from the archive. archive_mode = on # Configure the archiving scheme. This example archives to /mnt/server/archivedir/. archive_command = 'test ! -f /mnt/server/archivedir/%f && cp %p /mnt/server/archivedir/%f' -
Start the service, create a replication user, and create a replication slot.
-
Start PostgreSQL and enable it on boot.
sudo systemctl enable postgresql-15.service sudo systemctl start postgresql-15.service -
Create a PostgreSQL user with
REPLICATIONpermissions.sudo -u postgres psql -c "CREATE ROLE replica_user WITH REPLICATION LOGIN PASSWORD 'YOUR_SECURE_PASSWORD';" -
Create a physical replication slot. This prevents the primary from removing WAL logs before the secondary receives them, allowing a disconnected secondary to resume without a full re-clone.
sudo -u postgres psql -c "SELECT pg_create_physical_replication_slot('secondary_slot');"
-
-
Add a replication rule to the
pg_hba.conffile (/var/lib/pgsql/15/data/pg_hba.conf) to allow the secondary node to connect.# TYPE DATABASE USER ADDRESS METHOD host replication replica_user 192.168.1.20/32 scram-sha-256-
replica_user: The replication username. -
192.168.1.20: Secondary node private IP address. -
scram-sha-256: A password authentication method more secure thanmd5.
-
-
Restart PostgreSQL to apply the changes.
sudo systemctl restart postgresql-15.service
Step 3: Configure the secondary node
Alibaba Cloud Linux 3/CentOS 8
-
Install PostgreSQL 18.
# Check the OS type. If it is CentOS 8, disable the default PostgreSQL module. if [ -f /etc/os-release ]; then . /etc/os-release if [ "$ID" = "centos" ] && [ "${VERSION_ID%%.*}" = "8" ]; then sudo dnf --assumeyes module disable postgresql fi fi # Add the official PostgreSQL YUM repository. sudo rpm -Uvh http://mirrors.cloud.aliyuncs.com/postgresql/repos/yum/reporpms/EL-8-x86_64/pgdg-redhat-repo-latest.noarch.rpm # Replace the repository URL with an Alibaba Cloud mirror to speed up downloads. sudo sed -i "s@https://download.postgresql.org/pub@http://mirrors.cloud.aliyuncs.com/postgresql@g" /etc/yum.repos.d/pgdg-redhat-all.repo sudo sed -i "s@\$releasever@8@g" /etc/yum.repos.d/pgdg-redhat-all.repo # Install the PostgreSQL 18 server. sudo dnf install -y postgresql18-server -
Create a
.pgpassfile for thepostgresuser to store the replication password.-
Switch to the
postgresuser.sudo su - postgres -
Create and configure the
.pgpassfile.echo "192.168.1.10:5432:replication:replica_user:YOUR_SECURE_PASSWORD" > ~/.pgpass chmod 600 ~/.pgpass -
Exit the
postgresuser session.exit
-
-
Clone data from the primary with
pg_basebackup.ImportantThis overwrites the data directory
/var/lib/pgsql/18/data/. Ensure it is empty.# Perform the base backup as the postgres user. sudo -u postgres pg_basebackup -h 192.168.1.10 -D /var/lib/pgsql/18/data/ -U replica_user -P -v --wal-method=stream-
-h: Primary node IP address. -
-D: Secondary node data directory. -
-U: Replication username.
-
-
Create a
standby.signalfile to enable standby mode.sudo -u postgres touch /var/lib/pgsql/18/data/standby.signal -
Configure replication in
/var/lib/pgsql/18/data/postgresql.conf:The password is not required in
primary_conninfo. PostgreSQL reads it from the.pgpassfile.# Primary node connection information for streaming replication. # The application_name must match the replication slot name created on the primary node. primary_conninfo = 'host=192.168.1.10 port=5432 user=replica_user application_name=secondary_node1' # Specify the replication slot name. It must match the name of the slot created on the primary node. primary_slot_name = 'secondary_slot' # Enable hot standby mode to allow read-only queries during synchronization. hot_standby = on -
Start the secondary node.
sudo systemctl enable postgresql-18.service sudo systemctl start postgresql-18.service
Ubuntu/Debian
-
Install PostgreSQL 18.
# Add the official PostgreSQL APT repository and use an Alibaba Cloud mirror. sudo sh -c 'echo "deb [signed-by=/etc/apt/trusted.gpg.d/postgresql.gpg] http://mirrors.cloud.aliyuncs.com/postgresql/repos/apt/ $(lsb_release -sc)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' # Import the repository signature key. wget -qO - http://mirrors.cloud.aliyuncs.com/postgresql/repos/apt/ACCC4CF8.asc | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/postgresql.gpg # Update the package list and install. sudo apt-get update sudo apt-get install -y postgresql-18 -
Create a
.pgpassfile for thepostgresuser to store the replication password.-
Switch to the
postgresuser.sudo su - postgres -
Create and configure the
.pgpassfile.echo "192.168.1.10:5432:replication:replica_user:YOUR_SECURE_PASSWORD" > ~/.pgpass chmod 600 ~/.pgpass -
Exit the
postgresuser session.exit
-
-
Clone data from the primary with
pg_basebackup.ImportantThis overwrites the data directory
/var/lib/postgresql/18/main/. Ensure it is empty.# Perform the base backup as the postgres user. sudo -u postgres pg_basebackup -h 192.168.1.10 -D /var/lib/postgresql/18/main/ -U replica_user -P -v --wal-method=stream-
-h: Primary node IP address. -
-D: Secondary node data directory. -
-U: Replication username.
-
-
Create a
standby.signalfile to enable standby mode.sudo -u postgres touch /var/lib/postgresql/18/main/standby.signal -
Configure replication in
/etc/postgresql/18/main/postgresql.conf:The password is not required in
primary_conninfo. PostgreSQL reads it from the.pgpassfile.# Primary node connection information for streaming replication. # The application_name must match the replication slot name created on the primary node. primary_conninfo = 'host=192.168.1.10 port=5432 user=replica_user application_name=secondary_node1' # Specify the replication slot name. It must match the name of the slot created on the primary node. primary_slot_name = 'secondary_slot' # Enable hot standby mode to allow read-only queries during synchronization. hot_standby = on -
Start the secondary node.
sudo systemctl enable postgresql.service sudo systemctl start postgresql.service
Alibaba Cloud Linux 2/CentOS 7
-
Install PostgreSQL 15.
# Add the official PostgreSQL YUM repository. sudo rpm -Uvh http://mirrors.cloud.aliyuncs.com/postgresql/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm # Replace the repository URL with an Alibaba Cloud mirror to speed up downloads. sudo sed -i "s@https://download.postgresql.org/pub@http://mirrors.cloud.aliyuncs.com/postgresql@g" /etc/yum.repos.d/pgdg-redhat-all.repo sudo sed -i "s@\$releasever@7@g" /etc/yum.repos.d/pgdg-redhat-all.repo # Install the PostgreSQL 15 server. sudo yum install -y postgresql15-server -
Create a
.pgpassfile for thepostgresuser to store the replication password.-
Switch to the
postgresuser.sudo su - postgres -
Create and configure the
.pgpassfile.echo "192.168.1.10:5432:replication:replica_user:YOUR_SECURE_PASSWORD" > ~/.pgpass chmod 600 ~/.pgpass -
Exit the
postgresuser session.exit
-
-
Clone data from the primary with
pg_basebackup.ImportantThis overwrites the data directory
/var/lib/pgsql/15/data/. Ensure it is empty.# Perform the base backup as the postgres user. sudo -u postgres pg_basebackup -h 192.168.1.10 -D /var/lib/pgsql/15/data/ -U replica_user -P -v --wal-method=stream-
-h: Primary node IP address. -
-D: Secondary node data directory. -
-U: Replication username.
-
-
Create a
standby.signalfile to enable standby mode.sudo -u postgres touch /var/lib/pgsql/15/data/standby.signal -
Configure replication in
/var/lib/pgsql/15/data/postgresql.conf:The password is not required in
primary_conninfo. PostgreSQL reads it from the.pgpassfile.# Primary node connection information for streaming replication. # The application_name must match the replication slot name created on the primary node. primary_conninfo = 'host=192.168.1.10 port=5432 user=replica_user application_name=secondary_node1' # Specify the replication slot name. It must match the name of the slot created on the primary node. primary_slot_name = 'secondary_slot' # Enable hot standby mode to allow read-only queries during synchronization. hot_standby = on -
Start the secondary node.
sudo systemctl enable postgresql-15.service sudo systemctl start postgresql-15.service
Step 4: Verify replication
-
Check replication processes.
The
walsender(primary) andwalreceiver(secondary) processes handle data synchronization. Running processes indicate an active replication connection.-
On the primary, check for the
walsenderprocess:ps aux | grep "walsender.*streaming"Expected output:
postgres: walsender replica_user 192.168.1.20(xxxxx) streaming. -
On the secondary, check for the
walreceiverprocess:ps aux | grep "walreceiver.*streaming"Expected output:
postgres: walreceiver streaming.
-
-
Test data synchronization.
Write data to the primary and verify it appears on the secondary.
-
On the primary, create a test table and insert data.
sudo -u postgres psql -c "CREATE TABLE replication_test (id serial primary key, test_data text, created_at timestamptz default now());" sudo -u postgres psql -c "INSERT INTO replication_test (test_data) VALUES ('hello replication');" -
On the secondary, query the table to verify synchronization.
# Primary-secondary synchronization usually has some delay. Wait a few seconds before you run the query. sudo -u postgres psql -c "SELECT * FROM replication_test;"If the query returns the inserted data, replication works correctly.
-