Установка postgres-9.6. Настройка репликации master-slave

Thank you for reading this post, don't forget to subscribe!

Рас­смот­ри настрой­ку пото­ко­вой репли­ка­ции данных.
Когда вы изме­ня­е­те дан­ные в базе, все изме­не­ния пишут­ся во Write-Ahead Log, или WAL. После запи­си в WAL СУБД дела­ет систем­ный вызов fsync, бла­го­да­ря чему дан­ные попа­да­ют сра­зу на диск, а не висят в где-то в кэше фай­ло­вой систе­мы. Таким обра­зом, если взять и обес­то­чить сер­вер, при сле­ду­ю­щей загруз­ке СУБД про­чи­та­ет послед­ние запи­си из WAL и при­ме­нит к базе дан­ных соот­вет­ству­ю­щие изменения.

Пото­ко­вая репли­ка­ция (streaming replication) в сущ­но­сти явля­ет­ся пере­да­чей запи­сей из WAL от масте­ра к репли­кам. Писать при этом мож­но толь­ко в мастер, но читать мож­но как с масте­ра, так и с реплик. Если с репли­ки раз­ре­ше­но читать, она назы­ва­ет­ся hot standby, ина­че — warm standby. Посколь­ку во мно­гих при­ло­же­ни­ях 90% запро­сов явля­ют­ся запро­са­ми на чте­ние, репли­ка­ция поз­во­ля­ет мас­шта­би­ро­вать базу дан­ных гори­зон­таль­но. Пото­ко­вая репли­ка­ция быва­ет двух видов — син­хрон­ная и асинхронная.

При асин­хрон­ной репли­ка­ции запрос тут же выпол­ня­ет­ся на масте­ре, а соот­вет­ству­ю­щие дан­ные из WAL доез­жа­ют до реплик отдель­но, в фоне. Недо­ста­ток асин­хрон­ной репли­ка­ции заклю­ча­ет­ся в том, что при вне­зап­ном паде­нии масте­ра (напри­мер, из-за сго­рев­ше­го дис­ка) часть дан­ных будет поте­ря­на, так как они не успе­ли дое­хать до реплик.

При исполь­зо­ва­нии син­хрон­ной репли­ка­ции дан­ные сна­ча­ла запи­сы­ва­ют­ся в WAL как мини­мум одной репли­ки, после чего тран­зак­ция выпол­ня­ет­ся уже на масте­ре. Запро­сы на запись выпол­ня­ют­ся мед­лен­нее в резуль­та­те воз­ни­ка­ю­щих сете­вых задер­жек (кото­рые, одна­ко, внут­ри одно­го ДЦ обыч­но мень­ше типич­но­го вре­ме­ни пла­ни­ро­ва­ния запро­са). Кро­ме того, что­бы запро­сы на запись не вста­ли колом в резуль­та­те паде­ния одной из реплик, при исполь­зо­ва­нии син­хрон­ной репли­ка­ции реко­мен­ду­ет­ся исполь­зо­вать по край­ней мере две репли­ки. Зато поте­рять дан­ные ста­но­вит­ся намно­го сложнее.

Заметь­те, что син­хрон­ная репли­ка­ция не предот­вра­ща­ет воз­мож­но­сти счи­тать с репли­ки ста­рые дан­ные, так как пото­ко­вая репли­ка­ция — она толь­ко про пере­да­чу WAL, а не то, что вид­но в базе с точ­ки зре­ния поль­зо­ва­те­ля. По край­ней мере, так син­хрон­ная репли­ка­ция рабо­та­ет кон­крет­но в PostgreSQL.

В кон­тек­сте репли­ка­ции нель­зя так­же не отме­тить еще один инте­рес­ный тер­мин. Если одна из реплик в свою оче­редь явля­ет­ся масте­ром для дру­гой репли­ки, такую кон­фи­гу­ра­цию назы­ва­ют кас­кад­ной репли­ка­ци­ей.

Пото­ко­вая репли­ка­ция в PostgreSQL не рабо­та­ет меж­ду раз­ны­ми вер­си­я­ми PostgreSQL, а так­же если на сер­ве­рах исполь­зу­ет­ся раз­ная архи­тек­ту­ра CPU, напри­мер, x86 и x64. В част­но­сти, это озна­ча­ет, что обно­вить PostgreSQL до сле­ду­ю­щей вер­сии при исполь­зо­ва­нии пото­ко­вой репли­ка­ции без даун­тай­ма нельзя

 

Поми­мо пото­ко­вой репли­ка­ции в послед­нее вре­мя выде­ля­ют еще и так назы­ва­е­мую логи­че­скую репли­ка­цию (logical replication). Реа­ли­за­ций логи­че­ской репли­ка­ции в PostgreSQL суще­ству­ет несколь­ко, напри­мер, slony и pglogical. Пожа­луй, наи­бо­лее суще­ствен­ное отли­чие логи­че­ской репли­ка­ции от пото­ко­вой заклю­ча­ет­ся в воз­мож­но­сти реп­ли­ци­ро­вать часть баз дан­ных и таб­лиц на одни репли­ки, а часть — на дру­гие. Пла­тить за это при­хо­дит­ся ско­ро­стью. И хотя pglogical в плане ско­ро­сти выгля­дит мно­го­обе­ща­ю­ще, на момент напи­са­ния этих строк это очень моло­дое, сырое реше­ние. В рам­ках этой замет­ки логи­че­ская репли­ка­ция не рассматривается.

В PostgreSQL 10 доба­ви­ли логи­че­скую репли­ка­цию, теперь она есть из коробки.


Установка

име­ет­ся 2 сервера
192.168.1.170 - master

192.168.1.171 - slave

 

Отклю­ча­ем selinux
setenforce 0
sed -i 's/^SELINUX=.*/SELINUX=disabled/g' /etc/selinux/config

про­из­во­дим уста­нов­ку на оба сервера:

yum -y install https://download.postgresql.org/pub/repos/yum/9.6/redhat/rhel-7-x86_64/pgdg-centos96-9.6-3.noarch.rpm

или так

yum install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm

yum install postgresql96 postgresql96-server postgresql96-lib

 

Ини­ци­а­ли­зи­ру­ем базы:
/usr/pgsql-9.6/bin/postgresql96-setup initdb

 

Добав­ля­ем в авто­за­груз­ку и стартуем:
systemctl enable postgresql-9.6

systemctl start postgresql-9.6

 

Ста­вим пароль на поль­зо­ва­те­ля postgres

[root@master ~]# su - postgres
-bash-4.2$ psql
psql (9.6.13)
Type "help" for help.

postgres=# \password
Enter new password:
Enter it again:
postgres=# \q

[root@slave ~]# su - postgres
-bash-4.2$ psql
psql (9.6.13)
Type "help" for help.

postgres=# \password
Enter new password:
Enter it again:
postgres=# \q

 

Настройка репликации

на мастере:

vim /var/lib/pgsql/9.6/data/pg_hba.conf

host replication postgres 192.168.1.171/32 md5
host all postgres 192.168.1.171/32 md5

Пер­вая строч­ка нуж­на для рабо­ты ути­ли­ты pg_basebackup. Без вто­рой не будет рабо­тать pg_rewind. Если хотим, что­бы в базу по сети мог ходить не толь­ко поль­зо­ва­тель postgres, в послед­ней стро­ке мож­но напи­сать вме­сто его име­ни all.

 

пра­вим основ­ной конфиг

vim /var/lib/pgsql/9.6/data/postgresql.conf

# какие адре­са слу­шать, заме­ни­те на IP сервера
listen_addresses = 'localhost, 192.168.1.170'
wal_level = hot_standby
# это нуж­но, что­бы рабо­тал pg_rewind
wal_log_hints = on
max_wal_senders = 2
wal_keep_segments = 64
hot_standby = on

max_replication_slots = 2

hot_standby_feedback = on

* где

  • 192.168.1.170 — IP-адрес сер­ве­ра, на кото­ром он будем слу­шать запро­сы Postgre; 
  • wal_level ука­зы­ва­ет, сколь­ко инфор­ма­ции запи­сы­ва­ет­ся в WAL (жур­нал опе­ра­ций, кото­рый исполь­зу­ет­ся для репли­ка­ции) — hot_standby ука­зы­ва­ет на хра­не­ние допол­ни­тель­ной инфор­ма­ции, она нуж­на для выпол­не­ния запро­сов на резерв­ном сер­ве­ре в режи­ме толь­ко для чтения; 
  • max_wal_senders — коли­че­ство пла­ни­ру­е­мых слейвов; 
  • max_replication_slots — мак­си­маль­ное чис­ло сло­тов репликации; 
  • hot_standby — опре­де­ля­ет, мож­но или нет под­клю­чать­ся к postgresql для выпол­не­ния запро­сов в про­цес­се восстановления; 
  • hot_standby_feedback — опре­де­ля­ет, будет или нет сер­вер slave сооб­щать масте­ру о запро­сах, кото­рые он выполняет.

 

Далее откры­ва­ем psql:

systemctl start postgresql-9.6

sudo -u postgres psql

Меня­ем пароль поль­зо­ва­те­ля postgres:

 ALTER ROLE postgres PASSWORD 'postgres';

Пере­за­пус­ка­ем PostgreSQL:

systemctl restart postgresql-9.6

на слейве

Оста­нав­ли­ва­ем PostgreSQL

[root@slave ~]# systemctl stop postgresql-9.6

 

Ста­но­вим­ся поль­зо­ва­те­лем postgres:

su - postgres
Под этим поль­зо­ва­те­лем пере­ли­ва­ем дан­ные с масте­ра, сна­ча­ла всё удалим:
rm -rf /var/lib/pgsql/9.6/data/* 
-bash-4.2$ pg_basebackup -h 192.168.1.170 -U postgres -D /var/lib/pgsql/9.6/data --xlog-method=stream --write-recovery-conf
Password:
вво­дим пароль кото­рый зада­ва­ли для поль­зо­ва­те­ля postgres
Про­ве­ря­ем:
-bash-4.2$ ls /var/lib/pgsql/9.6/data/
backup_label pg_dynshmem pg_notify pg_subtrans postgresql.conf
base pg_hba.conf pg_replslot pg_tblspc recovery.conf
global pg_ident.conf pg_serial pg_twophase
log pg_log pg_snapshots PG_VERSION
pg_clog pg_logical pg_stat pg_xlog
pg_commit_ts pg_multixact pg_stat_tmp postgresql.auto.conf

Дан­ная коман­да сде­ла­ла репли­ку базы от масте­ра и созда­ла кон­фи­гу­ра­ци­он­ный файл recovery.conf, в кото­ром ука­за­ны пара­мет­ры репликации.

 

Редак­ти­ру­ем кон­фи­гу­ра­ци­он­ный файл postgresql.conf.

[root@slave ~]# vim /var/lib/pgsql/9.6/data/postgresql.conf

 

Редак­ти­ру­ем сле­ду­ю­щие параметры:

listen_addresses = 'localhost, 192.168.1.171'

* где 192.168.1.171 — IP-адрес наше­го вто­рич­но­го сервера.

так же мож­но ука­зать про­сто звёздочку "*"

 

Редак­ти­ру­ем файл recovery.conf  и добав­ля­ем в него стро­ку recovery_target_timeline = 'latest'

[root@slave ~]# cat /var/lib/pgsql/9.6/data/recovery.conf
standby_mode = 'on'
primary_conninfo = 'user=postgres password=postgres host=192.168.1.170 port=5432 sslmode=prefer sslcompression=1 krbsrvname=postgres'
recovery_target_timeline = 'latest'

 

так же правим
/var/lib/pgsql/9.6/data/pg_hba.conf
host replication postgres 192.168.1.170/32 md5
host all postgres 192.168.1.170/32 md5

 

Сно­ва запус­ка­ем сер­вис postgresql:

[root@slave ~]# systemctl start postgresql-9.6

СОЗДАЁМ replication_slots НА МАСТЕРЕ И СЛЕЙВЕ

На масте­ре
SELECT pg_create_physical_replication_slot('standby_slot');

На слей­ве
SELECT pg_create_physical_replication_slot('standby_1_slot');

Про­ве­ря­ем:
select * from pg_replication_slots;

 

Добав­ля­ем  primary_slot_name = 'standby_slot'  в recovery.conf на слейве,
а на масте­ре он будет выглядеть:
primary_slot_name = 'standby_1_slot'

по ито­гу на слей­ве recovery.conf :

standby_mode = 'on'
primary_conninfo = 'user=repluser password=repluser host=IP_MATERa  port=5432 sslmode=prefer sslcompression=1 krbsrvname=postgres'
recovery_target_timeline = 'latest'
primary_slot_name = 'standby_slot'
trigger_file = '/postgres/9.6/trigger'

 

на масте­ре recovery.doney

standby_mode = 'on'
primary_conninfo = 'user=repluser password=repluser host=IP_SLAVEa port=5432 sslmode=prefer sslcompression=1 krbsrvname=postgres'
recovery_target_timeline = 'latest'
primary_slot_name = 'standby_1_slot'
trigger_file = '/postgres/9.6/trigger'

 

Проверка репликации

на слей­ве:
[root@slave ~]# ps aux | grep receiver
postgres 2406 0.2 0.1 362144 3160 ? Ss 18:39 0:02 postgres: wal receiver process streaming 0/30003E0

на масте­ре:
[root@master ~]# ps aux | grep sender
postgres 11487 0.0 0.1 355824 3004 ? Ss 18:39 0:00 postgres: wal sender process postgres 192.168.1.171(45747) streaming 0/30003E0

На масте­ре:
[root@master ~]# su - postgres
Last login: Wed Jun 5 18:07:00 KGT 2019 on pts/0
-bash-4.2$ psql

postgres=# select * from pg_stat_replication;
pid | usesysid | usename | application_name | client_addr | client_hostname | client_port | backend_start | backend_xmin | state | sent_location |
write_location | flush_location | replay_location | sync_priority | sync_state
-------+----------+----------+------------------+---------------+-----------------+-------------+-------------------------------+--------------+-----------+---------------+-
---------------+----------------+-----------------+---------------+------------
11487 | 10 | postgres | walreceiver | 192.168.1.171 | | 45747 | 2019-06-05 18:39:50.459205+06 | | streaming | 0/30004C0 |
0/30004C0 | 0/30004C0 | 0/30004C0 | 0 | async
(1 row)

 

Созда­ем новую базу данных:

postgres=# CREATE DATABASE repltest ENCODING='UTF8';
CREATE DATABASE

postgres=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+----------+----------+-------------+-------------+-----------------------
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
repltest | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres +
| | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres +
| | | | | postgres=CTc/postgres
(4 rows)

 

На слей­ве:

[root@slave ~]# su - postgres

Last login: Wed Jun 5 19:15:35 KGT 2019 on pts/0
-bash-4.2$ psql
psql (9.6.13)
Type "help" for help.

postgres=# select * from pg_stat_wal_receiver;
pid | status | receive_start_lsn | receive_start_tli | received_lsn | received_tli | last_msg_send_time | last_msg_receipt_time | latest_end_lsn |
latest_end_time | slot_name | conninfo

-------+-----------+-------------------+-------------------+--------------+--------------+-------------------------------+-------------------------------+----------------+--
-----------------------------+-----------+-----------------------------------------------------------------------------------------------------------------------------------
----------------------------------------
11928 | streaming | 0/3000000 | 1 | 0/3001730 | 1 | 2019-06-05 19:24:29.285547+06 | 2019-06-05 19:24:28.979799+06 | 0/3001730 | 2
019-06-05 19:22:29.085126+06 | | user=postgres password=******** dbname=replication host=192.168.1.170 port=5432 fallback_application_name=walreceiver sslmode=pref
er sslcompression=1 krbsrvname=postgres
(1 row)

 

postgres=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges

-----------+----------+----------+-------------+-------------+----------------------
-
postgres | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
repltest | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 |
template0 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres
+
| | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | en_US.UTF-8 | en_US.UTF-8 | =c/postgres
+
| | | | | postgres=CTc/postgres
(4 rows)

 

как видим тесто­вая база repltest  созда­на и на слейве.
при попыт­ке создать базу на слей­ве воз­ник­нет сле­ду­ю­щая ошибка:
CREATE DATABASE repltest2 ENCODING='UTF8';

ERROR: cannot execute CREATE DATABASE in a read-only transaction

 

Изменим Роли. Master => Slave  а Salve => Master

Промоутим реплику до мастера

Оста­но­вим мастер:
systemctl stop postgresql-9.6

На слейве(из кото­ро­го дела­ем масте­ра) говорим:

[root@slave ~]# sudo -u postgres /usr/pgsql-9.6/bin/pg_ctl promote -D /var/lib/pgsql/9.6/data/
could not change directory to "/root": Permission denied
server promoting

При этом в ката­ло­ге  /var/lib/pgsql/9.6/data/ файл recovery.conf авто­ма­ти­че­ски будет пере­име­но­ван в recovery.done.

[root@slave ~]# ll /var/lib/pgsql/9.6/data/recovery.done
-rw-r--r--. 1 postgres postgres 190 Jun 5 19:11 /var/lib/pgsql/9.6/data/recovery.done

В репли­ку теперь мож­но писать. Репли­ку и мож­но про­мо­ут­нуть до масте­ра без пере­за­пус­ка PostgreSQL, на прак­ти­ке вы, веро­ят­но, все же захо­ти­те его пере­за­пу­стить по сле­ду­ю­щей при­чине. Дело в том, что при­ло­же­ние, кото­рое ранее под­клю­чи­лось к этой репли­ке, так и будет исполь­зо­вать ее в каче­стве репли­ки даже после про­мо­у­та. Пере­за­пу­стив PostgreSQL, вы порве­те все сете­вые соеди­не­ния, а зна­чит при­ло­же­нию при­дет­ся под­клю­чить­ся зано­во, про­ве­рить, под­клю­чил­ся ли он к масте­ру или репли­ке (запрос SELECT pg_is_in_recovery();вер­нет false на масте­ре и true на репликах)

Исполь­зу­ем ути­ли­ту pg_rewind кото­рая нахо­дит точ­ку в WAL, начи­ная с кото­рой WAL масте­ра и WAL репли­ки начи­на­ют рас­хо­дить­ся. Затем она «пере­ма­ты­ва­ет» (отсю­да и назва­ние) WAL репли­ки на эту точ­ку и нака­ты­ва­ет недо­ста­ю­щую исто­рию с масте­ра. Таким обра­зом, репли­ка и местер все­гда при­хо­дят к кон­си­стент­но­му состо­я­нию. Плюс к это­му pg_rewind син­хро­ни­зи­ру­ет фай­лы масте­ра и репли­ки намно­го быст­рее, чем pg_basebackup или rsync.

на масте­ре (из кото­ро­го дела­ем слейв)говорим:

systemctl stop postgresql-9.6
[root@master 9.6]# sudo -u postgres /usr/pgsql-9.6/bin/pg_rewind -D /var/lib/pgsql/9.6/data/ --source-server="host=192.168.1.171 port=5432 user=postgres password=postgres"
servers diverged at WAL position 0/30000D0 on timeline 1
no rewind required

созда­ём
recovery.conf

[root@master 9.6]# cat /var/lib/pgsql/9.6/data/recovery.conf
standby_mode = 'on'
primary_conninfo = 'user=postgres password=postgres host=192.168.1.171 port=5432 sslmode=prefer sslcompression=1 krbsrvname=postgres'
recovery_target_timeline = 'latest'

[root@master data]# chown postgres:postgres /var/lib/pgsql/9.6/data/recovery.conf

Запус­ка­ем:
[root@master data]# systemctl start postgresql-9.6

смот­рим в логи. Там обя­за­тель­но долж­но быть:

LOG:  database system is ready to accept read only connections
[root@master data]# grep 'database system is ready to accept read only connections' /var/lib/pgsql/9.6/data/pg_log/postgresql-Wed.log
< 2019-06-05 23:38:52.217 KGT > LOG: database system is ready to accept read only connections

Если вдруг видим что-то вроде:

ERROR: requested WAL segment 0000000200000005 has already been removed

… зна­чит репли­ка слиш­ком отста­ла от масте­ра, и нуж­но пере­не­сти фай­лы с масте­ра при помо­щи pg_basebackup, как было опи­са­но в нача­ле этой статьи.

про­ве­ря­ем, теперь "сер­вер мастер" у нас репли­ка а "сер­вер слейв" теперь мастер, сле­до­ва­тель­но на сер­ве­ре мастер нель­зя вно­сить изме­не­ния в базе.

[root@slave 9.6]# ps aux | grep sender
postgres 13964 0.0 0.1 355856 3104 ? Ss 23:38 0:00 postgres: wal sender process postgres 192.168.1.170(41249) streaming 0/3000480

[root@master data]# ps aux | grep receiver
postgres 12624 0.3 0.1 362176 3164 ? Ss 23:38 0:00 postgres: wal receiver process streaming 0/3000480

[root@master data]# sudo -u postgres psql
psql (9.6.13)
Type "help" for help.

postgres=# CREATE DATABASE repltest45 ENCODING='UTF8';
ERROR: cannot execute CREATE DATABASE in a read-only transaction

 

на "сер­ве­ре слейв" всё ок

[root@slave 9.6]# sudo -u postgres psql
psql (9.6.13)
Type "help" for help.

postgres=# CREATE DATABASE repltest55 ENCODING='UTF8';
CREATE DATABASE

 

Вернём всё как было т.е. master=>master  а slave => slave

Промоутим до мастера

Оста­но­вим мастер(postgres):
[root@slave ~]# systemctl stop postgresql-9.6

На "мастер сервере"(из кото­ро­го дела­ем мастера(postgres)) говорим:

[root@master ~]# sudo -u postgres /usr/pgsql-9.6/bin/pg_ctl promote -D /var/lib/pgsql/9.6/data/
could not change directory to "/root": Permission denied
server promoting

При этом в ката­ло­ге  /var/lib/pgsql/9.6/data/ файл recovery.conf авто­ма­ти­че­ски будет пере­име­но­ван в recovery.done.

[root@master ~]# ll /var/lib/pgsql/9.6/data/recovery.done
-rw-r--r--. 1 postgres postgres 191 Jun 5 23:37 /var/lib/pgsql/9.6/data/recovery.done

В репли­ку теперь мож­но писать. Репли­ку и мож­но про­мо­ут­нуть до масте­ра без пере­за­пус­ка PostgreSQL, на прак­ти­ке вы, веро­ят­но, все же захо­ти­те его пере­за­пу­стить по сле­ду­ю­щей при­чине. Дело в том, что при­ло­же­ние, кото­рое ранее под­клю­чи­лось к этой репли­ке, так и будет исполь­зо­вать ее в каче­стве репли­ки даже после про­мо­у­та. Пере­за­пу­стив PostgreSQL, вы порве­те все сете­вые соеди­не­ния, а зна­чит при­ло­же­нию при­дет­ся под­клю­чить­ся зано­во, про­ве­рить, под­клю­чил­ся ли он к масте­ру или репли­ке (запрос SELECT pg_is_in_recovery();вер­нет false на масте­ре и true на репликах)

Исполь­зу­ем ути­ли­ту pg_rewind кото­рая нахо­дит точ­ку в WAL, начи­ная с кото­рой WAL масте­ра и WAL репли­ки начи­на­ют рас­хо­дить­ся. Затем она «пере­ма­ты­ва­ет» (отсю­да и назва­ние) WAL репли­ки на эту точ­ку и нака­ты­ва­ет недо­ста­ю­щую исто­рию с масте­ра. Таким обра­зом, репли­ка и местер все­гда при­хо­дят к кон­си­стент­но­му состо­я­нию. Плюс к это­му pg_rewind син­хро­ни­зи­ру­ет фай­лы масте­ра и репли­ки намно­го быст­рее, чем pg_basebackup или rsync.

 

на "слейв сервере"(из кото­ро­го дела­ем слейв)говорим:

systemctl stop postgresql-9.6
[root@slave ~]# sudo -u postgres /usr/pgsql-9.6/bin/pg_rewind -D /var/lib/pgsql/9.6/data/ --source-server="host=192.168.1.170 port=5432 user=postgres password=postgres"
could not change directory to "/root": Permission denied
servers diverged at WAL position 0/3002C08 on timeline 2
no rewind required

так как recovery.conf созда­вал­ся ранее то про­сто пере­име­ну­ем его:

[root@slave ~]# mv /var/lib/pgsql/9.6/data/recovery.done /var/lib/pgsql/9.6/data/recovery.conf
[root@slave ~]# cat /var/lib/pgsql/9.6/data/recovery.conf
standby_mode = 'on'
primary_conninfo = 'user=postgres password=postgres host=192.168.1.170 port=5432 sslmode=prefer sslcompression=1 krbsrvname=postgres'
recovery_target_timeline = 'latest'

Запус­ка­ем:
[root@slave ~]# systemctl start postgresql-9.6

смот­рим в логи. Там обя­за­тель­но долж­но быть:

LOG:  database system is ready to accept read only connections
[root@slave ~]# grep 'database system is ready to accept read only connections' /var/lib/pgsql/9.6/data/pg_log/postgresql-Wed.log
< 2019-06-05 23:27:05.175 KGT > LOG: database system is ready to accept read only connections

Если вдруг видим что-то вроде:

ERROR: requested WAL segment 0000000200000005 has already been removed

… зна­чит репли­ка слиш­ком отста­ла от масте­ра, и нуж­но пере­не­сти фай­лы с масте­ра при помо­щи pg_basebackup, как было опи­са­но в нача­ле этой статьи.

 

про­ве­ря­ем, теперь "сер­вер мастер" у нас мастер(postgres ) а "сер­вер слейв" теперь реплика.

[root@master ~]# ps aux | grep sender
postgres 12763 0.0 0.1 355856 3092 ? Ss 02:17 0:00 postgres: wal sender process postgres 192.168.1.171(46672) streaming 0/3002DF8

[root@slave ~]# ps aux | grep receiver
postgres 14251 0.3 0.1 362176 3172 ? Ss 02:17 0:00 postgres: wal receiver process streaming 0/3002DF8

всё ок

 

 

 

Если необ­хо­ди­мо что­бы репли­ка­ция про­из­во­ди­лась под опре­де­лён­ным поль­зо­ва­те­лем, напри­мер repluser то добав­ля­ем в файл:

Созда­ём пользователя:
CREATE USER repluser REPLICATION LOGIN CONNECTION LIMIT 2 ENCRYPTED PASSWORD 'repluser';

cat /var/lib/pgsql/9.6/data/pg_hba.conf
host    replication     repluser      192.168.1.170/32       md5

host    all              postgres     192.168.1.170/32            md5

на вто­ром сервере:
host    replication     repluser      192.168.1.171/32       md5

host    all              postgres       192.168.1.171/32            md5

 

 

На масте­ре

cat /var/lib/pgsql/9.6/data/recovery.done

standby_mode = 'on'

primary_conninfo = 'user=repluser password=repluser host=192.168.1.171 port=5432 sslmode=prefer sslcompression=1 krbsrvname=postgres'

recovery_target_timeline = 'latest'

 

На слей­ве:
cat /var/lib/pgsql/9.6/data/recovery.conf

standby_mode = 'on'

primary_conninfo = 'user=repluser password=repluser host=192.168.1.170 port=5432 sslmode=prefer sslcompression=1 krbsrvname=postgres'

recovery_target_timeline = 'latest'

 

Коман­ды будут выпол­нят­ся соот­ветс­вен­но от это­го пользователя:
sudo -u postgres pg_basebackup -h 192.168.1.170 -U repluser -D /var/lib/pgsql/9.6/data --xlog-method=stream --write-recovery-conf

 

 

 

Если необ­хо­ди­мо изме­нить рас­по­ло­же­ние базы то:

vim /usr/lib/systemd/system/postgresql-9.6.service

Редак­ти­ру­ем путь:
c
Environment=PGDATA=/var/lib/pgsql/9.6/data/
на
Environment=PGDATA=/postgres/9.6/

после

systemctl daemon-reload

 

mkdir /postgres/9.6
chown -R postgres:postgres /postgres/

пра­вим домаш­нюю директорию:
cat /etc/passwd | grep postges

postgres:x:26:26:PostgreSQL Server:/postgres:/bin/bash

 

Ини­ци­и­ру­ем базу
 su - postgres

/usr/pgsql-9.6/bin/initdb -D /postgres/9.6/

 

=================================================

Репликация с использованием triger файла

Про­цесс такой же как и при настрой­ке обыч­ной репли­ка­ции, ини­ци­и­ру­ем базу, созда­ём поль­зо­ва­те­ля repluser даём пра­ва в pg_hba.conf

Копи­ру­ем базу на слейв:

sudo -u postgres pg_basebackup -h -U repluser -D /postgres/9.6/ --xlog-method=stream --write-recovery-conf

СОЗДАЁМ replication_slots НА МАСТЕРЕ И СЛЕЙВЕ

На масте­ре
SELECT pg_create_physical_replication_slot('standby_slot');

На слей­ве
SELECT pg_create_physical_replication_slot('standby_1_slot');

Про­ве­ря­ем:
select * from pg_replication_slots;

 

Добав­ля­ем  primary_slot_name = 'standby_slot'  в recovery.conf на слейве,
а на масте­ре он будет выглядеть:
primary_slot_name = 'standby_1_slot'

====================

На слей­ве recovery conf выгля­дит сле­ду­ю­щим образом:
cat /postgres/9.6/recovery.conf

standby_mode = 'on'

primary_conninfo = 'user=repluser password=repluser host=IP-master port=5432 sslmode=prefer sslcompression=1 krbsrvname=postgres'

recovery_target_timeline = 'latest'

primary_slot_name = 'standby_slot'

trigger_file = '/postgres/9.6/trigger'

Мы доба­ви­ли стро­ку trigger_file = '/postgres/9.6/trigger' для того, что­бы при созда­нии фай­ла /postgres/9.6/trigger слейв база ста­но­ви­лась масте­ром и мог­ла про­из­во­дить запись

 

На масте­ре recovery конф нет, но зара­нее созда­дим recovery.done

standby_mode = 'on'

primary_conninfo = 'user=repluser password=repluser host=IP-slave port=5432 sslmode=prefer sslcompression=1 krbsrvname=postgres'

recovery_target_timeline = 'latest'

primary_slot_name = 'standby_1_slot'

trigger_file = '/postgres/9.6/trigger'

==========================

Пере­клю­чим слейв в мастер

Оста­но­вим мастер:
systemctl stop postgresql-9.6

На слей­ве про­ве­рим нали­чие фай­ла recovery.conf и созда­дим файл triger

[root@btc-vsrv-mpaydb2 9.6]# cat /postgres/9.6/recovery.conf

standby_mode = 'on'

primary_conninfo = 'user=repluser password=repluser host=IP-master port=5432 sslmode=prefer sslcompression=1 krbsrvname=postgres'

recovery_target_timeline = 'latest'

primary_slot_name = 'standby_slot'

trigger_file = '/postgres/9.6/trigger'

 

[root@btc-vsrv-mpaydb2 9.6]# touch /postgres/9.6/trigger

 

Про­ве­ря­ем логи:

[root@btc-vsrv-mpaydb2 9.6]# tail /postgres/9.6/pg_log/postgresql-Thu.log

< 2019-06-20 13:29:23.672 +06 > LOG:  trigger file found: /postgres/9.6/trigger

< 2019-06-20 13:29:23.672 +06 > LOG:  redo done at 0/1A000E50

< 2019-06-20 13:29:23.682 +06 > LOG:  selected new timeline ID: 7

< 2019-06-20 13:29:23.784 +06 > LOG:  archive recovery complete

< 2019-06-20 13:29:23.807 +06 > LOG:  MultiXact member wraparound protections are now enabled

< 2019-06-20 13:29:23.809 +06 > LOGdatabase system is ready to accept connections

< 2019-06-20 13:29:23.810 +06 > LOG:  autovacuum launcher started

 

Стро­ка  database system is ready to accept connections пока­зы­ва­ет, что сер­вер пере­шёл в режим записи

Файл /postgres/9.6/trigger при этом с быв­ше­го слей­ва уда­ля­ет­ся, а recovery.conf авто­ма­ти­че­ски пере­име­но­вы­ва­ет­ся в recovery.done

Что­бы мастер пере­шёл в режим read only нам необ­ход­мо пере­име­но­вать recovery.conf
mv recovery.done recovery.conf

 

И стар­та­нуть базу

systemctl start postgresql-9.6
Проверяем:

[root@btc-vsrv-mpaydb1 9.6]# ps aux | grep rec

postgres  3837  0.0  0.0 362620  2536 ?        Ss   13:35   0:00 postgres: startup process   recovering 00000006000000000000001A

postgres  3841  0.0  0.0 369412  3264 ?        Ss   13:35   0:00 postgres: wal receiver process   idle

root      4037  0.0  0.0 112708   980 pts/0    S+   13:38   0:00 grep --color=auto rec

 

Быв­ший мастер теперь высту­па­ет как слейв

=================================

Что­бы вер­нуть как было мастер - мастер  слейв- слейв.
Оса­нав­ли­ва­ем базу

[root@btc-vsrv-mpaydb2 9.6]# systemctl stop postgresql-9.6

пере­име­но­вы­ва­ем

[root@btc-vsrv-mpaydb2 9.6]# mv recovery.done recovery.conf

 

На масте­ре созда­ём файл trigger

[root@btc-vsrv-mpaydb1 9.6]# touch trigger

(на дан­ном сер­ве­ре файл recovery.conf авто­ма­ти­че­ские пере­име­но­вал­ся в recovery.done)

 

Стар­ту­ем на слейве:
[root@btc-vsrv-mpaydb2 9.6]# systemctl start postgresql-9.6

 

Про­ве­ря­ем:
[root@btc-vsrv-mpaydb2 9.6]# ps aux | grep rec

postgres  7688  0.0  0.0 362620  2524 ?        Ss   15:08   0:00 postgres: startup process   recovering 0000000F000000000000001E

postgres  7692  0.3  0.0 369260  3256 ?        Ss   15:08   0:00 postgres: wal receiver process   streaming 0/1E000A80

 

[root@btc-vsrv-mpaydb1 9.6]# ps aux | grep send

postgres 10459  0.0  0.0 362924  3048 ?        Ss   15:08   0:00 postgres: wal sender process repluser IP-master(56130) streaming 0/1E000A80

 

[root@btc-vsrv-mpaydb2 9.6]# su - postgres

Last login: Thu Jun 20 12:45:09 +06 2019 on pts/0

 

-bash-4.2$ psql

psql (9.2.24, server 9.6.13)

WARNING: psql version 9.2, server version 9.6.

Some psql features might not work.

Type "help" for help.

 

postgres=# select * from pg_replication_slots;

slot_name    | plugin | slot_type | datoid | database | active | active_pid | xmin | catalog_xmin | restart_lsn | confirmed_flush_lsn

----------------+--------+-----------+--------+----------+--------+------------+------+--------------+-------------+---------------------

 standby_1_slot |        | physical  |        |          | f      |            | 1773 |              | 0/1E0008C8  |

(1 row)

 

 

[root@btc-vsrv-mpaydb1 9.6]# su - postgres

Last login: Thu Jun 20 14:42:01 +06 2019 on pts/0

 

-bash-4.2$ psql

psql (9.2.24, server 9.6.13)

WARNING: psql version 9.2, server version 9.6.

Some psql features might not work.

Type "help" for help.

 

postgres=# select * from pg_replication_slots;

slot_name   | plugin | slot_type | datoid | database | active | active_pid | xmin | catalog_xmin | restart_lsn | confirmed_flush_lsn

--------------+--------+-----------+--------+----------+--------+------------+------+--------------+-------------+---------------------

standby_slot |        | physical  |        |          | t      |      10459 | 1773 |              | 0/1E000B60  |

(1 row)