Какво представляват слотове за репликация?
В дните, когато „слотовете за репликация“ все още не бяха въведени, управлението на WAL сегментите беше предизвикателство. При стандартната стрийминг репликация главният няма познания за състоянието на подчинения. Вземете пример за главен, който изпълнява голяма транзакция, докато възелът в режим на готовност е в режим на поддръжка за няколко часа (като надграждане на системните пакети, настройка на мрежовата сигурност, надстройка на хардуера и т.н.). В даден момент главният премахва своя регистър на транзакциите (WAL сегменти), когато контролната точка преминава. След като робът е изключен от поддръжка, той вероятно има огромно изоставане на роба и трябва да настигне главния. В крайна сметка робът ще получи фатален проблем като по-долу:
LOG: started streaming WAL from primary at 0/73000000 on timeline 1
FATAL: could not receive data from WAL stream: ERROR: requested WAL segment 000000010000000000000073 has already been removed
Типичният подход е да посочите във вашия postgresql.conf WAL архивен скрипт, който ще копира WAL файлове в едно или повече места за дългосрочни архиви. Ако нямате резерви или други клиенти за стрийминг репликация, тогава по принцип сървърът може да изхвърли WAL файла, след като архивният скрипт приключи или отговори ОК. Но все пак ще ви трябват някои скорошни WAL файлове за възстановяване при срив (данните от последните WAL файлове се възпроизвеждат по време на възстановяване при срив. В нашия пример за резервен възел, който е поставен за дълъг период на поддръжка, възникват проблеми, когато се върне онлайн и пита основният за WAL файл, който основният вече няма, тогава репликацията е неуспешна.
Този проблем беше адресиран в PostgreSQL 9.4 чрез "Репликационни слотове".
Ако не използвате слотове за репликация, често срещан начин за намаляване на риска от неуспешна репликация е да настроите wal_keep_segments достатъчно високо, така че WAL файловете, които може да са необходими, да не се завъртат или рециклират. Недостатъкът на този подход е, че е трудно да се определи коя стойност е най-добра за вашата настройка. Няма да имате нужда от поддръжка на дневна база или няма да е необходимо да съхранявате голяма купчина WAL файлове, които изяждат вашето дисково хранилище. Въпреки че това работи, това не е идеално решение, тъй като рискуването на дисково пространство на главния може да доведе до неуспех на входящите транзакции.
Алтернативните подходи за неизползване на слотове за репликация е да конфигурирате PostgreSQL с непрекъснато архивиране и да предоставите restore_command, за да предоставите на репликата достъп до архива. За да избегнете натрупване на WAL на основния, можете да използвате отделен том или устройство за съхранение за WAL файловете, например SAN или NFS. Друго нещо е със синхронната репликация, тъй като тя изисква първичният трябва да изчака резервните възли да завършат транзакцията. Това означава, че гарантира, че WAL файловете са били приложени към възлите в режим на готовност. Но все пак е най-добре да предоставите команди за архивиране от основния, така че след като WAL са рециклирани в основния, бъдете сигурни, че имате резервни копия на WAL в случай на възстановяване. Въпреки че в някои ситуации синхронната репликация не е идеално решение, тъй като идва с някои допълнителни разходи в сравнение с асинхронната репликация.
Типове слотове за репликация
Има два типа слотове за репликация. Това са:
Слотове за физическа репликация
Може да се използва за стандартно стрийминг репликация. Те ще се уверят, че данните не се рециклират твърде рано.
Слотове за логическа репликация
Логическата репликация прави същото като слотовете за физическа репликация и се използват за логическа репликация. Те обаче се използват за логическо декодиране. Идеята зад логическото декодиране е да се даде възможност на потребителите да се прикачат към регистъра на транзакциите и да го декодират с плъгин. Позволява извличане на промени, направени в базата данни и следователно в регистъра на транзакциите във всякакъв формат и за всякакви цели.
В този блог ще използваме слотове за физическа репликация и как да постигнем това с помощта на ClusterControl.
Предимства и недостатъци на използването на слотове за репликация
Слотовете за репликации определено са полезни, след като са активирани. По подразбиране „слотовете за репликация“ не са активирани и трябва да бъдат зададени ръчно. Сред предимствата на използването на слотове за репликация са
- Гарантира, че главният запазва достатъчно WAL сегменти, за да могат всички реплики да ги получат
- Предотвратява главната програма да премахва редове, които биха могли да причинят конфликт при възстановяване на репликите
- Главният може да рециклира регистрационния файл на транзакциите само след като бъде използван от всички реплики. Предимството тук е, че робът никога не може да изостане толкова много, че да е необходимо повторно синхронизиране.
Слотове за репликация също идват с някои предупреждения.
- Осиротяла репликация слот може да причини неограничен растеж на диска поради натрупани WAL файлове от главния
- Подчинените възли, поставени на продължителна поддръжка (като дни или седмици) и които са свързани със слот за репликация, ще имат неограничен растеж на диска поради натрупаните WAL файлове от главния
Можете да наблюдавате това, като потърсите pg_replication_slots, за да определите слотове, които не се използват. Ще проверим отново това малко по-късно.
Използване на слотове за репликация
Както беше посочено по-рано, има два типа слотове за репликация. За този блог ще използваме физически слотове за репликация за поточно репликация.
Създаване на слот за репликация
Създаването на репликация е лесно. Трябва да извикате съществуващата функция pg_create_physical_replication_slot, за да направите това и трябва да бъде стартирана и създадена в главния възел. Функцията е проста,
maximus_db=# \df pg_create_physical_replication_slot
Schema | pg_catalog
Name | pg_create_physical_replication_slot
Result data type | record
Argument data types | slot_name name, immediately_reserve boolean DEFAULT false, OUT slot_name name, OUT xlog_position pg_lsn
Type | normal
напр. Създаване на слот за репликация с име slot1,
postgres=# SELECT pg_create_physical_replication_slot('slot1');
-[ RECORD 1 ]-----------------------+---------
pg_create_physical_replication_slot | (slot1,)
Имената на слотовете за репликация и тяхната основна конфигурация са само за цялата система, а не за целия клъстер. Например, ако имате nodeA (текущ главен) и възли в готовност nodeB и nodeC, създавайки слота на главен възел A, а именно "slot1", тогава данните няма да бъдат достъпни за nodeB и nodeC. Следователно, когато предстои преминаване/превключване при отказ, трябва да създадете отново слотовете, които сте създали.
Изпускане на слот за репликация
Неизползваните слотове за репликация трябва да бъдат премахнати или изтрити. Както беше посочено по-рано, когато има осиротели слотове за репликация или слотове, които не са присвоени на нито един клиент или резервни възли, това може да доведе до безкрайни проблеми с дисковото пространство, ако не бъде изпуснато. Така че е много важно те да бъдат изхвърлени, когато вече не се използват. За да го пуснете, просто извикайте pg_drop_replication_slot. Тази функция има следното определение:
maximus_db=# \df pg_drop_replication_slot
Schema | pg_catalog
Name | pg_drop_replication_slot
Result data type | void
Argument data types | name
Type | normal
Изтриването е лесно:
maximus_db=# select pg_drop_replication_slot('slot2');
-[ RECORD 1 ]------------+-
pg_drop_replication_slot |
Наблюдение на вашите слотове за репликация на PostgreSQL
Наблюдението на вашите слотове за репликация е нещо, което не искате да пропуснете. Просто съберете информацията от view pg_replication_slots в основния/главния възел точно както по-долу:
postgres=# select * from pg_replication_slots;
-[ RECORD 1 ]-------+-----------
slot_name | main_slot
plugin |
slot_type | physical
datoid |
database |
active | t
active_pid | 16297
xmin |
catalog_xmin |
restart_lsn | 2/F4000108
confirmed_flush_lsn |
-[ RECORD 2 ]-------+-----------
slot_name | main_slot2
plugin |
slot_type | physical
datoid |
database |
active | f
active_pid |
xmin |
catalog_xmin |
restart_lsn |
confirmed_flush_lsn |
Горният резултат показва, че main_slot е зает, но не и main_slot2.
Друго нещо, което можете да направите, е да следите колко изостават от слотовете, които имате. За да постигнете това, можете просто да използвате заявката въз основа на примерния резултат по-долу:
postgres=# SELECT redo_lsn, slot_name,restart_lsn,
round((redo_lsn-restart_lsn) / 1024 / 1024 / 1024, 2) AS GB_behind
FROM pg_control_checkpoint(), pg_replication_slots;
redo_lsn | slot_name | restart_lsn | gb_behind
------------+-----------+-------------+-----------
1/8D400238 | slot1 | 0/9A000000 | 3.80
Но redo_lsn не присъства в 9.6, ще използва redo_location, така че в 9.6,
imbd=# SELECT redo_location, slot_name,restart_lsn,
round((redo_location-restart_lsn) / 1024 / 1024 / 1024, 2) AS GB_behind
FROM pg_control_checkpoint(), pg_replication_slots;
-[ RECORD 1 ]-+-----------
redo_location | 2/F6008BE0
slot_name | main_slot
restart_lsn | 2/F6008CC0
gb_behind | 0.00
-[ RECORD 2 ]-+-----------
redo_location | 2/F6008BE0
slot_name | main_slot2
restart_lsn | 2/F6008CC0
gb_behind | 0.00
Изисквания за системни променливи
Внедряването на слотове за репликация изисква ръчна настройка. Има променливи, които трябва да имате предвид, които изискват промени и да бъдат посочени във вашия postgresql.conf. Вижте по-долу:
- max_replication_slots – Ако е зададено на 0, това означава, че слотове за репликация са напълно забранени. Ако използвате PostgreSQL <10 версии, този слот трябва да бъде посочен различен от 0 (по подразбиране). От PostgreSQL 10, по подразбиране е 10. Тази променлива определя максималния брой слотове за репликация. Задаването му на по-ниска стойност от броя на съществуващите в момента слотове за репликация ще попречи на сървъра да стартира.
- wal_level – трябва да бъде поне реплика или по-висока (репликата е по подразбиране). Настройката на hot_standby или архив ще се преобразува в реплика. За слот за физическа репликация, репликата е достатъчна. За логически слотове за репликация се предпочита логическият.
- max_wal_senders – зададено на 10 по подразбиране, 0 във версия 9.6, което означава, че репликацията е деактивирана. Предлагаме ви да зададете това поне на 16, особено когато работите с ClusterControl.
- hot_standby – във версии <10, трябва да зададете това на включено, което е изключено по подразбиране. Това е важно за възли в режим на готовност, което означава, че когато е включено, можете да се свързвате и да изпълнявате заявки по време на възстановяване или в режим на готовност.
- primary_slot_name – тази променлива се задава чрез recovery.conf на възела в режим на готовност. Това е слотът, който трябва да се използва от получателя или възела в режим на готовност, когато се свързва с подателя (или основния/главния).
Трябва да вземете под внимание, че тези променливи най-вече изискват рестартиране на услугата за база данни, за да се презаредят нови стойности.
Използване на слотове за репликация в ClusterControl PostgreSQL среда
Сега нека да видим как можем да използваме слотове за физическа репликация и да ги внедрим в настройка на Postgres, управлявана от ClusterControl.
Разгръщане на възли на базата данни PostgreSQL
Нека започнем да внедряваме PostgreSQL клъстер с 3 възела, като използваме ClusterControl, използвайки версия на PostgreSQL 9.6 този път.
ClusterControl ще разгърне възли със следните системни променливи, дефинирани съответно въз основа на техните настройки по подразбиране или настроени стойности. В:
postgres=# select name, setting from pg_settings where name in ('max_replication_slots', 'wal_level', 'max_wal_senders', 'hot_standby');
name | setting
-----------------------+---------
hot_standby | on
max_replication_slots | 0
max_wal_senders | 16
wal_level | replica
(4 rows)
Във версии на PostgreSQL> 9.6 стойността по подразбиране на max_replication_slots е 10, която е активирана по подразбиране, но не и в 9.6 или по-ниски версии, която е деактивирана по подразбиране. Трябва да зададете max_replication_slots по-високо от 0. В този пример зададох max_replication_slots на 5.
[email protected]:~# grep 'max_replication_slots' /etc/postgresql/9.6/main/postgresql.conf
# max_replication_slots = 0 # max number of replication slots
max_replication_slots = 5
и рестартира услугата,
[email protected]:~# pg_lsclusters
Ver Cluster Port Status Owner Data directory Log file
9.6 main 5432 online postgres /var/lib/postgresql/9.6/main pg_log/postgresql-%Y-%m-%d_%H%M%S.log
[email protected]:~# pg_ctlcluster 9.6 main restart
Задаване на слотове за репликация за първични и резервни възли
В ClusterControl няма опция за това, така че трябва да създадете своите слотове ръчно. В този пример създадох слотове в първичния хост 192.168.30.100:
192.168.10.100:5432 [email protected]_db=# SELECT pg_create_physical_replication_slot('slot1'), pg_create_physical_replication_slot('slot2');
pg_create_physical_replication_slot | pg_create_physical_replication_slot
-------------------------------------+-------------------------------------
(slot1,) | (slot2,)
(1 row)
Проверка на това, което току-що създадохме показва,
192.168.10.100:5432 [email protected]_db=# select * from pg_replication_slots;
slot_name | plugin | slot_type | datoid | database | active | active_pid | xmin | catalog_xmin | restart_lsn | confirmed_flush_lsn
-----------+--------+-----------+--------+----------+--------+------------+------+--------------+-------------+---------------------
slot1 | | physical | | | f | | | | |
slot2 | | physical | | | f | | | | |
(2 rows)
Сега в възлите в режим на готовност трябва да актуализираме recovery.conf и да добавим променливата primary_slot_name и да променим името на приложението, така че да е по-лесно да идентифицираме възела. Ето как изглежда в хост 192.168.30.110 recovery.conf:
[email protected]:/var/lib/postgresql/9.6/main/pg_log# cat ../recovery.conf
standby_mode = 'on'
primary_conninfo = 'application_name=node11 host=192.168.30.100 port=5432 user=cmon_replication password=m8rLmZxyn23Lc2Rk'
recovery_target_timeline = 'latest'
primary_slot_name = 'slot1'
trigger_file = '/tmp/failover_5432.trigger'
Прави същото нещо и в хост 192.168.30.120, но промени името_на_приложение и зададе основното_име_слота ='slot2'.
Проверка на здравето на слота за репликация:
192.168.10.100:5432 [email protected]_db=# select * from pg_replication_slots;
slot_name | plugin | slot_type | datoid | database | active | active_pid | xmin | catalog_xmin | restart_lsn | confirmed_flush_lsn
-----------+--------+-----------+--------+----------+--------+------------+------+--------------+-------------+---------------------
slot1 | | physical | | | t | 24252 | | | 0/CF0A4218 |
slot2 | | physical | | | t | 11635 | | | 0/CF0A4218 |
(2 rows)
Какво друго ви трябва?
Тъй като ClusterControl не поддържа репликационни слотове от този момент, има неща, които трябва да вземете предвид. Какви са тези? Да отидем в подробности.
Процес на отказ/превключване
Когато е направен опит за автоматично превключване или превключване чрез ClusterControl, слотове няма да бъдат задържани от първичните и от резервните възли. Трябва да създадете отново това ръчно, да проверите променливите дали са зададени правилно и съответно да промените recovery.conf.
Възстановяване на подчинен от главен
При повторно изграждане на подчинен файл recovery.conf няма да бъде запазен. Това означава, че вашите настройки за recovery.conf, които имат основното_слот_име, ще бъдат изтрити. Трябва да зададете това ръчно отново и да проверите изгледа pg_replication_slots, за да определите дали слотове се използват правилно или са оставени сираци.
Ако искате да изградите отново подчинения/готовия възел от главен, може да се наложи да обмислите да посочите променливата PGAPPNAME env точно като командата по-долу:
$ export PGAPPNAME="app_repl_testnode15"; /usr/pgsql-9.6/bin/pg_basebackup -h 192.168.10.190 -U cmon_replication -D /var/lib/pgsql/9.6/data -p5434 -W -S main_slot -X s -R -P
Уточняването на параметъра -R е много важно, така че ще създаде повторно recovery.conf, докато -S ще укаже името на слота да се използва при възстановяване на възела в режим на готовност.
Заключение
Внедряването на слотове за репликация в PostgreSQL е лесно, но има някои предупреждения, които трябва да запомните. Когато внедрявате с ClusterControl, ще трябва да актуализирате някои настройки по време на преодоляване на отказ или повторно изграждане на подчинен.