Implementing Streaming Replication
1. Understanding Streaming Replication
Property Detail
Granularity Physical WAL (byte-for-byte)
Standby Read-only (hot_standby)
Catch-up WAL streaming, optional cascading
Failover pg_promote / patroni / repmgr
2. Configuring Primary Server
# postgresql.conf
wal_level = replica
max_wal_senders = 10
hot_standby = on
listen_addresses = '*'
3. Setting max_wal_senders
ALTER SYSTEM SET max_wal_senders = 16 ;
SELECT pg_reload_conf();
4. Setting wal_keep_size
# PG 13+
wal_keep_size = 1GB # minimum WAL retained on primary
5. Creating Replication User
CREATE ROLE repl WITH REPLICATION LOGIN PASSWORD 'replPass' ;
6. Configuring pg_hba.conf
# pg_hba.conf
host replication repl 10.0.0.0/24 scram-sha-256
7. Creating Base Backup
pg_basebackup -h primary -U repl -D /var/lib/postgresql/standby \
-Fp -Xs -P -R -S standby_slot
Flag Meaning
-Fp Plain format
-Xs Stream WAL alongside backup
-R Write standby.signal + primary_conninfo
-S Use replication slot
8. Setting Up Standby Server
cd /var/lib/postgresql/standby
ls standby.signal # marker file present after -R
9. Configuring primary_conninfo
# postgresql.auto.conf (written by pg_basebackup -R)
primary_conninfo = 'host=primary port=5432 user=repl password=replPass application_name=standby1'
primary_slot_name = 'standby_slot'
10. Starting Standby Server
pg_ctl -D /var/lib/postgresql/standby start
psql -c "SELECT pg_is_in_recovery();" # → t
11. Monitoring Replication Lag
-- On primary
SELECT client_addr, state , sync_state,
pg_wal_lsn_diff(pg_current_wal_lsn(), sent_lsn) AS sent_lag,
pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS replay_lag
FROM pg_stat_replication;
-- On standby
SELECT now () - pg_last_xact_replay_timestamp() AS apply_lag;
12. Using Replication Slots
SELECT pg_create_physical_replication_slot( 'standby_slot' );
SELECT * FROM pg_replication_slots;
SELECT pg_promote(wait : = true, wait_seconds : = 60 );
-- or: pg_ctl promote -D /var/lib/postgresql/standby
14. Understanding Synchronous vs Asynchronous Replication
Mode COMMIT Returns When
async (default) Primary WAL flushed locally
remote_write Standby received (not fsynced)
on / remote_flush Standby fsynced WAL
remote_apply Standby applied (visible)
15. Configuring synchronous_commit and synchronous_standby_names
synchronous_commit = on
synchronous_standby_names = 'FIRST 1 (standby1, standby2)'
# or: 'ANY 2 (s1, s2, s3)'
Warning: With no standby connected, sync replication BLOCKS commits. Always have a fallback or use ANY-quorum.