Replication slots in PostgreSQL
Prior to the ninth version, PostgreSQL used WAL archiving to create a “warm” backup server. Version 9.0 introduced streaming replication with the ability to create a “hot” read-only server. The next version of PostgreSQL 9.4 will introduce new functionality for creating streaming replication called replication slots. Consider what it is and how it differs from previous methods.
The first release candidate is currently available. As a test bench, 2 virtual machines were selected for Ubuntu 14.04. The build and installation process is the same for the primary and backup servers. We put from the sources, after having pre-installed the necessary packages:
Download and unpack the archive from the repository:
We collect and install the package:
By default, binaries for working with DBMS are placed in / usr / local / pgsql /.
Add the postgres user to the system:
Create a directory for the cluster:
Next, we perform actions on the main server. We initialize the cluster:
In addition to the cluster structure, initdb will create default configs. Create the pg_log directory in the cluster, in which the logs will be stored:
Add entries to pg_hba.conf to connect users and so that the backup server can pick up WAL logs from the main one:
In postgresql.conf config rule parameters:
listen_addresses = '*' - listen for incoming connections on all interfaces
wal_level = hot_standby - Required Format WAL-logging for replication
max_wal_senders = 2 - number of simultaneous connections for replication
logging_collector = on - logs piled in pg_log
run our cluster:
We look at the status of the processes:
Create a replica user with replication rights:
Let's create a test database with data:
Set up a backup server.
Create a directory for the cluster:
Using the pg_basebackup utility, make a backup copy of the main server:
pg_basebackup copies the entire contents of the cluster, including configs, therefore we change the hot_standby parameter to the on state in postgresql.conf
Create a recovery.conf file in the cluster directory, in which we specify the parameters for connecting to the main server:
We start the cluster on the backup server:
After that, the wal_sender process should start on the main server, and on the standby wal_receiver:
You can view replication status through the pg_stat_replication view on the primary server
It can be seen that the primary and backup server are synchronized. Now we will generate some more test data and right after that we will look at replication status.
Here we observe that the backup server took all the WAL logs from the main one, but has not yet had time to use them all, so it lags behind the main one. By default, in postgres, replication occurs asynchronously using WAL logs; these are binary files of a fixed size of 16 MB, which are located in the pg_xlog directory. Their number can be changed using the checkpoint_segments and wal_keep_segments parameters. When the amount of changed data in the cluster exceeds the total size of the WAL logs, the checkpointer process is started, which dumps the WAL logs to the data files. After that, WAL-logs are recreated anew. In the current stable version of postgres, the primary server does not consider the status of the backup server. Therefore, if the backup is too “behind” the main, then on the main WAL-logs will be recreated before the backup takes them.
Temporarily disable the backup server from connecting to port 5432:
We will generate more data on the main server:
Let's reset the iptables rule and see the logs of the backup server, in which we observe such an unpleasant picture.
The main server deleted the WAL logs before the backup server managed to pick them up. Now you have to back up the main server again. The problem is that the primary server does not take into account the state of the backup. Therefore, if there are problems with the network or just a slow channel between the servers, then with intensive loading and / or changing data on the main server, there is a risk of replication failure. A partial solution is to increase the value of the wal_keep_segments parameter , and enable WAL archiving . But in version 9.4, replication slots will appear. Let's see how it works:
On the main server, create a replication slot:
On the backup, add the line
primary_slot_name = 'standby_slot' to the existing contents of the recovery.conf file .
After restarting the backup server, disconnect it from the main one again and generate test data on the main one that exceeds the volume of WAL logs:
Let's see the WAL log parameters in the system, and then the real number of log files in the pg_xlog directory:
To calculate the maximum number of WAL files in the system, use the formula : (2 + checkpoint_completion_target) * checkpoint_segments + 1.
However, the current number of WAL logs in the system is much higher. Replication slots store information about the number of downloaded WAL logs for each backup server. Now WAL-logs will be accumulated until the last standby server picks them up or until the replication slot is removed. As WAL logs download, the pg_xlog directory on the main server will decrease. Having dropped the iptables rule on the backup server, we see in the logs that replication has resumed.
Replication slots is a great tool for enhancing the reliability and convenience of replication in PostgreSQL.
Description of replication slots on the official PostgreSQL website: www.postgresql.org/docs/9.4/static/warm-standby.html#STREAMING-REPLICATION-SLOTS
The first release candidate is currently available. As a test bench, 2 virtual machines were selected for Ubuntu 14.04. The build and installation process is the same for the primary and backup servers. We put from the sources, after having pre-installed the necessary packages:
sudo apt-get update && sudo apt-get -y install make g++ checkinstall libreadline6-dev zlib1g-dev
Download and unpack the archive from the repository:
wget https://ftp.postgresql.org/pub/source/v9.4rc1/postgresql-9.4rc1.tar.gz
tar xzf postgresql-9.4rc1.tar.gz
We collect and install the package:
cd postgresql-9.4rc1/
./configure
make
sudo checkinstall
By default, binaries for working with DBMS are placed in / usr / local / pgsql /.
Add the postgres user to the system:
sudo useradd -M postgres
Create a directory for the cluster:
sudo mkdir -p /data/db
sudo chown postgres:postgres /data/db
sudo chmod 0700 /data/db
Next, we perform actions on the main server. We initialize the cluster:
sudo -u postgres /usr/local/pgsql/bin/initdb -D /data/db
In addition to the cluster structure, initdb will create default configs. Create the pg_log directory in the cluster, in which the logs will be stored:
sudo -u postgres mkdir /data/db/pg_log
sudo -u postgres chmod 0700 /data/db/pg_log
Add entries to pg_hba.conf to connect users and so that the backup server can pick up WAL logs from the main one:
host all all 192.168.1.0/24 md5
host replication replica 192.168.1.108/32 md5
In postgresql.conf config rule parameters:
listen_addresses = '*' - listen for incoming connections on all interfaces
wal_level = hot_standby - Required Format WAL-logging for replication
max_wal_senders = 2 - number of simultaneous connections for replication
logging_collector = on - logs piled in pg_log
run our cluster:
sudo -u postgres /usr/local/pgsql/bin/pg_ctl -D /data/db start
We look at the status of the processes:
ps aux | grep postgres
postgres 21295 0.0 0.0 23700 604 ? Ss 13:39 0:00 postgres: logger process
postgres 21297 0.0 13.6 170880 138408 ? Ss 13:39 0:01 postgres: checkpointer process
postgres 21298 0.0 5.0 170784 51076 ? Ss 13:39 0:00 postgres: writer process
postgres 21299 0.0 0.5 170648 5148? Ss 13:39 0:00 postgres: wal writer process
postgres 21300 0.0 0.1 171052 1836 ? Ss 13:39 0:00 postgres: autovacuum launcher process
postgres 21301 0.2 0.1 25924 1060 ? Ss 13:39 0:17 postgres: stats collector process
Create a replica user with replication rights:
/usr/local/pgsql/bin/psql -U postgres -c "create user replica with replication encrypted password '123'"
Let's create a test database with data:
/usr/local/pgsql/bin/createdb -U postgres testdb
/usr/local/pgsql/bin/psql -U postgres -d testdb -c "create table testtable (id serial, data text)"
/usr/local/pgsql/bin/psql -U postgres -d testdb -c "insert into testtable select nextval('testtable_id_seq'::regclass), md5(generate_series(1,1000000)::text)"
Set up a backup server.
Create a directory for the cluster:
sudo mkdir -p /data/db
sudo chmod 0700 /data/db
sudo chown postgres:postgres /data/db
Using the pg_basebackup utility, make a backup copy of the main server:
sudo -u postgres /usr/local/pgsql/bin/pg_basebackup -h 192.168.1.103 -U replica -D /data/db -X s
pg_basebackup copies the entire contents of the cluster, including configs, therefore we change the hot_standby parameter to the on state in postgresql.conf
Create a recovery.conf file in the cluster directory, in which we specify the parameters for connecting to the main server:
standby_mode='on'
primary_conninfo='host=192.168.1.103 port=5432 user=replica password=123'
We start the cluster on the backup server:
sudo -u postgres /usr/local/pgsql/bin/pg_ctl -D /data/db start
After that, the wal_sender process should start on the main server, and on the standby wal_receiver:
Hidden text
postgres 21295 0.0 0.0 23700 604 ? Ss 13:39 0:00 postgres: logger process
postgres 21297 0.0 0.2 170756 2312 ? Ss 13:39 0:00 postgres: checkpointer process
postgres 21298 0.0 0.2 170784 2252 ? Ss 13:39 0:00 postgres: writer process
postgres 21299 0.0 0.5 170648 5148 ? Ss 13:39 0:00 postgres: wal writer process
postgres 21300 0.0 0.1 171052 1804 ? Ss 13:39 0:00 postgres: autovacuum launcher process
postgres 21301 0.0 0.1 25924 1060 ? Ss 13:39 0:00 postgres: stats collector process
postgres 21323 0.0 0.2 171048 2108 ? Ss 13:46 0:00 postgres: wal sender process replica 192.168.1.108(56673) streaming 0/4E000210
postgres 15150 0.0 0.0 23700 612 ? Ss 13:46 0:00 postgres: logger process
postgres 15151 0.0 0.1 170788 1496 ? Ss 13:46 0:00 postgres: startup process recovering 00000001000000000000004E
postgres 15152 0.0 0.0 170680 944 ? Ss 13:46 0:00 postgres: checkpointer process
postgres 15153 0.0 0.1 170680 1204 ? Ss 13:46 0:00 postgres: writer process
postgres 15154 0.0 0.0 25792 648 ? Ss 13:46 0:00 postgres: stats collector process
postgres 15155 0.6 0.1 174956 1660 ? Ss 13:46 0:00 postgres: wal receiver process streaming 0/4E000138
You can view replication status through the pg_stat_replication view on the primary server
testdb=# select * from pg_stat_replication;
-[ RECORD 1 ]----+------------------------------
pid | 21987
usesysid | 16384
usename | replica
application_name | walreceiver
client_addr | 192.168.1.108
client_hostname |
client_port | 56674
backend_start | 2014-11-25 18:30:09.206434+03
backend_xmin |
state | streaming
sent_location | 0/5A2D8E60
write_location | 0/5A2D8E60
flush_location | 0/5A2D8E60
replay_location | 0/5A2D8E60
sync_priority | 0
sync_state | async
It can be seen that the primary and backup server are synchronized. Now we will generate some more test data and right after that we will look at replication status.
testdb=# insert into testtable select nextval('testtable_id_seq'::regclass), md5(generate_series(1,1000000)::text);
INSERT 0 1000000
testdb=# select * from pg_stat_replication;
-[ RECORD 1 ]----+------------------------------
pid | 21987
usesysid | 16384
usename | replica
application_name | walreceiver
client_addr | 192.168.1.108
client_hostname |
client_port | 56674
backend_start | 2014-11-25 18:30:09.206434+03
backend_xmin |
state | streaming
sent_location | 0/63800000
write_location | 0/63680000
flush_location | 0/63680000
replay_location | 0/6136E160
sync_priority | 0
sync_state | async
Here we observe that the backup server took all the WAL logs from the main one, but has not yet had time to use them all, so it lags behind the main one. By default, in postgres, replication occurs asynchronously using WAL logs; these are binary files of a fixed size of 16 MB, which are located in the pg_xlog directory. Their number can be changed using the checkpoint_segments and wal_keep_segments parameters. When the amount of changed data in the cluster exceeds the total size of the WAL logs, the checkpointer process is started, which dumps the WAL logs to the data files. After that, WAL-logs are recreated anew. In the current stable version of postgres, the primary server does not consider the status of the backup server. Therefore, if the backup is too “behind” the main, then on the main WAL-logs will be recreated before the backup takes them.
Temporarily disable the backup server from connecting to port 5432:
sudo iptables -A OUTPUT -m tcp -p tcp —dport 5432 -j DROP
We will generate more data on the main server:
testdb=# insert into testtable select nextval('testtable_id_seq'::regclass), md5(generate_series(1,1000000)::text);
INSERT 0 1000000
Let's reset the iptables rule and see the logs of the backup server, in which we observe such an unpleasant picture.
LOG: started streaming WAL from primary at 0/78000000 on timeline 1
FATAL: could not receive data from WAL stream: ERROR: requested WAL segment 000000010000000000000078 has already been removed
The main server deleted the WAL logs before the backup server managed to pick them up. Now you have to back up the main server again. The problem is that the primary server does not take into account the state of the backup. Therefore, if there are problems with the network or just a slow channel between the servers, then with intensive loading and / or changing data on the main server, there is a risk of replication failure. A partial solution is to increase the value of the wal_keep_segments parameter , and enable WAL archiving . But in version 9.4, replication slots will appear. Let's see how it works:
On the main server, create a replication slot:
testdb=# SELECT pg_create_physical_replication_slot('standby_slot');
-[ RECORD 1 ]-----------------------+----------------
pg_create_physical_replication_slot | (standby_slot,)
testdb=# select * from pg_replication_slots;
-[ RECORD 1 ]+-------------
slot_name | standby_slot
plugin |
slot_type | physical
datoid |
database |
active | f
xmin |
catalog_xmin |
restart_lsn |
On the backup, add the line
primary_slot_name = 'standby_slot' to the existing contents of the recovery.conf file .
After restarting the backup server, disconnect it from the main one again and generate test data on the main one that exceeds the volume of WAL logs:
testdb=# insert into testtable select nextval('testtable_id_seq'::regclass), md5(generate_series(1,10000000)::text);
Let's see the WAL log parameters in the system, and then the real number of log files in the pg_xlog directory:
testdb=# show checkpoint_segments;
-[ RECORD 1 ]-------+--
checkpoint_segments | 3
testdb=# show wal_keep_segments;
-[ RECORD 1 ]-----+--
wal_keep_segments | 0
testdb=#\! ls /data/db/pg_xlog | wc -l
50
To calculate the maximum number of WAL files in the system, use the formula : (2 + checkpoint_completion_target) * checkpoint_segments + 1.
However, the current number of WAL logs in the system is much higher. Replication slots store information about the number of downloaded WAL logs for each backup server. Now WAL-logs will be accumulated until the last standby server picks them up or until the replication slot is removed. As WAL logs download, the pg_xlog directory on the main server will decrease. Having dropped the iptables rule on the backup server, we see in the logs that replication has resumed.
testdb=#\! tail -f /data/db/pg_log/postgresql-2014-11-27_191036.log
Is the server running on host "192.168.1.103" and accepting TCP/IP connections on port 5432?
LOG: started streaming WAL from primary at 0/A0000000 on timeline 1
Replication slots is a great tool for enhancing the reliability and convenience of replication in PostgreSQL.
Description of replication slots on the official PostgreSQL website: www.postgresql.org/docs/9.4/static/warm-standby.html#STREAMING-REPLICATION-SLOTS