DEV Community

Mehdi Pourfar
Mehdi Pourfar

Posted on

Backup and replicate Postgresql 12 using pgBackRest in Ubuntu 20.04

In this post, I will guide you through the process of setting up a continuous backup system and a replication server using pgBackRest.

For this guide, we need to have 3 servers: pg-master, pg-replica and pg-backup.

On all of these servers, we need to add these lines to /etc/hosts file and put the correct ips there:

{master_server_ip} pg-master {replica_server_ip} pg-replica {backup_server_ip} pg-backup 

On pg-master:

sudo apt install postgresql-12 pgbackrest 

On pg-replica:

sudo apt install postgresql-12 pgbackrest 

On pg-backup:

sudo apt install pgbackrest 

Since our servers should communicate with each other using ssh connection, we create ssh key pairs on each of them:

On pg-master, pg-replica and pg-backup run these commands:

sudo su postgres ssh-keygen -t rsa -b 4096 -N "" 

And then share all of the public keys inside /var/lib/postgresql/.ssh/authorized_keys file on each server. Then we need to check that all connections can be established without any problem:

On pg-master:

sudo -u postgres ssh postgres@pg-backup [exit] sudo -u postgres ssh postgres@pg-replica [exit] 

On pg-replica:

sudo -u postgres ssh postgres@pg-backup [exit] sudo -u postgres ssh postgres@pg-master [exit] 

On pg-backup:

sudo -u postgres ssh postgres@pg-master [exit] sudo -u postgres ssh postgres@pg-replica [exit] 

If everything works correctly, it's time to configure pgBackRest.

On pg-master, change the content of /etc/pgbackrest.conf with these lines:

[my_cluster] pg1-path=/var/lib/postgresql/12/main [global] repo1-host=pg-backup repo1-host-user=postgres [global:archive-push] compress-level=3 

And then, open /etc/postgresql/12/main/postgresql.conf and change these variables:

archive_command = 'pgbackrest --stanza=my_cluster archive-push %p' archive_mode = on listen_addresses = '*' max_wal_senders = 3 wal_level = replica 

And then restart postgresql:

sudo systemctl restart postgresql 

After that, we will create some test data:

sudo -u postgres psql psql (12.4 (Ubuntu 12.4-1.pgdg18.04+1)) Type "help" for help. postgres=# CREATE DATABASE my_db; CREATE DATABASE postgres=# \c my_db You are now connected to database "my_db" as user "postgres". my_db=# CREATE TABLE nums(val int); CREATE TABLE my_db=# INSERT INTO nums VALUES(1); INSERT 0 1 my_db=# INSERT INTO nums VALUES(2); INSERT 0 1 my_db=# INSERT INTO nums VALUES(3); INSERT 0 1 

Now we have a database named my_db with a table named nums with three values.

It's time to create our backup on pg-backup server. First edit /etc/pgbackrest.conf on pg-backup as below:

[my_cluster] pg1-host=pg-master pg1-host-user=postgres pg1-path=/var/lib/postgresql/12/main [global] process-max=2 repo1-path=/var/lib/pgbackrest repo1-retention-full=2 repo1-retention-diff=1 repo1-host-user=postgres start-fast=y 

Then run this command to create a backup stanza on pg-backup server:

sudo -u postgres pgbackrest --stanza=my_cluster --log-level-console=info stanza-create 

Then, run this command on both pg-master and pg-backup to check everything is okay:

sudo -u postgres pgbackrest --stanza=my_cluster --log-level-console=info check 

If everything works good, it's time to perform our first backup on pg-backup server:

sudo -u postgres pgbackrest --stanza=my_cluster --log-level-console=info backup 

By default, pgBackRest works by copying new archive files to backup server but if we let it be like that, the hard disk will be full very soon. So we need to create new backups based on some routines and pgBackRest will remove old backups for us based on retention policies that we have defined above. To do this, we will use Cronjob.

On pg-backup server:

sudo -u postgres crontab -e 

And add these lines at the end of the file and press enter to create a new line. Then save and exit.

30 06 * * 0 pgbackrest --type=full --stanza=my_cluster backup 30 06 * * 1-6 pgbackrest --type=diff --stanza=my_cluster backup 

You can read more about full backup, diff backup and retention policies in pgBackRest documentation.

Now that our backup server has been configured correctly, it's time to configure our replication server. Since we want to have a streaming replication, we should first create a replication user on pg-master:

sudo -u postgres psql CREATE USER replicator PASSWORD '123123' REPLICATION"; 

On pg-master, open /etc/postgresql/12/main/pg_hba.conf and add this line and change pg_replicate_ip to the ip of pg-replica server:

host replication replicator {pg_replicate_ip}/32 md5 

And then restart postgresql

systemctl restart postgresql 

Now, on pg-replica open the file /etc/pgbackrest.conf and change the content with these lines:

[my_cluster] pg1-path=/var/lib/postgresql/12/main recovery-option=primary_conninfo=host=pg-master port=5432 user=replicator password=123123 application_name=replica1 [global] repo1-host=pg-backup repo1-host-user=postgres 

Don't worry if you don't know what application_name is. We will talk about it later.
On pg-replica, run these commands to fetch master database data:

systemctl stop postgresql sudo -u postgres pgbackrest --stanza=my_cluster --delta --type=standby --log-level-console=info restore systemctl start postgresql 

To check that everything works correctly, on pg-replica go to psql and check that my_db database exists:

sudo -u postgres psql -d my_db SELCET * FROM nums; 

You should see these values as result:

 val ----- 1 2 3 (3 rows) 

Now, we add some data on pg-master to check changes will be reflected on replica:

sudo -u postgres psql -d my_db INSERT INTO nums VALUES (4); 

On, pg-replica:

SELECT * FROM nums; 

Now you should see these values as result:

 val ----- 1 2 3 4 (3 rows) 

If you don't see 4 values, look at the pg-replica's log file to find out the problem:

tail /var/log/postgresql/postgresql-12-main.log 

As you saw earlier, we have set application_name=replica1 in our connection info, but what is that? By default, Postgresql will use asynchronous replication, meaning that, replication will be done with a lag (usually just a few milliseconds) but if you want to have synchronous replication (meaning that commits will be blocked until replication is done) then you can set this application_name in pg-master's postgresql.conf.
If you want to do this, on pg-master, open the file /ect/postgresql/12/main/postgresql.conf and change this value:

synchronous_standby_names = 'replica1' 

And then restart postgresql. Now the replication should be synchronous. To test it, on pg-master go to sql shell and add a new row:

sudo -u postgres psql -d my_db INSERT INTO nums VALUES(5); 

If it doesn't hang, that means everything is okay. Buy if you stop postgresql replica server, command will hang and client will be blocked.

On pg-replica:

systemctl stop postgresql 

On pg-master:

INSERT INTO nums VALUES(6); 

Now as you see, pg-master's psql client is hanged but as soon as you start pg-replica postgresql server, it will be okay.

systemctl start postgresql 

Now it's time to test recovery process. For the test purpose, we truncate nums table and recover the data.
On pg-master, run the command below and copy the time value:

sudo -u postgres psql -Atc "select current_timestamp" 2020-09-24 14:17:23.105194+03:30 

Open psql and truncate nums table:

sudo -u postgres psql -d my_db TRUNCATE nums; SELECT * FROM nums; val ----- (0 rows) 

Stop Postgresql servers on pg-master and pg-replica

systemctl stop postgresql 

On pg-master run the command below:

sudo -u postgres pgbackrest --stanza=my_cluster --delta --type=time "--target=2020-09-24 14:17:23.105194+03:30" --target-action=promote restore 

And then start postgresql server:

systemctl start postgresql 

Check the nums table:

sudo -u postgres psql -d my_db val ----- 1 2 3 4 5 6 (6 rows) 

As you can see, we have restored our truncated table on pg-master. Now we need to restore it on pg-replica. First, go to pg-backup server and get a new backup:

sudo -u postgres pgbackrest --stanza=my_cluster --log-level-console=info backup 

Then, on pg-replica server, restore the data:

sudo -u postgres pgbackrest --stanza=my_cluster --delta --type=standby restore systemctl start postgresql 

Now for testing that everything works correctly add a value to nums table in pg-master and check that it will reflect on pg-replica.

That's all.

Top comments (1)

Collapse
 
sentadoensilla profile image
sentadoensilla

Hello. Great article to read. Later apply using VPS. But I have a question:
I can setting up in servers like these:
Master: 24.04 postgres 15
Replica: 22.04 postgres 13
Backup: 20.04 postgres 15
??