ШПАРГАЛКИ
CI/CD
KUBERNETES
  • DOCKERFILE
  • DOCKER-COMPOSE
  • JENKINSFILE
  • JENKINS-PIPELINE
  • GITLAB CI/CD
  • GROOVIE
  • INSTALL
  • PODS
  • INGRESS

Настраиваем потоковую репликацию в PostgreSQL 10

Быстрая памятка для себя. Содержит описание создания реплики и восстановления. 

1. Подготовка

1.1 Сначала ставим 10 PostgreSQL

Версии на серверах должны быть одинаковые.

sudo apt-get update
sudo apt-get -y upgrade

wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -

echo "deb http://apt.postgresql.org/pub/repos/apt/ $(lsb_release -cs)-pgdg main" \
| sudo tee /etc/apt/sources.list.d/postgresql-pgdg.list > /dev/null

sudo apt-get update

sudo apt-get install postgresql-10

dpkg -l | grep postgresql

1.2 Настраиваем брандмауэр

При использовании брандмауэра, необходимо открыть TCP-порт 5432 — он используется сервером postgre.

а) Firewalld:

firewall-cmd --permanent --add-port=5432/tcp
firewall-cmd --reload

б) Iptables:

iptables -A INPUT -p tcp --dport 5432 -j ACCEPT

в) UFW:

ufw allow 5432/tcp

1.3 Отключаем SELinux

Если активирована система безопасности SELinux (по умолчанию в системах Red Hat / CentOS / Fedora), отключаем ее:

setenforce 0
sed -i 's/^SELINUX=.*/SELINUX=disabled/g' /etc/selinux/config

Если необходимо, чтобы SELinux работал, настраиваем его.

2. Настройки на Master

Будем настраивать серверы с IP-адресами 10.14.0.143 (первичный или master) и 10.14.0.85 (вторичный или slave).

Переходим на сервер, с которого будем реплицировать данные (мастер) и выполняем следующие действия.

2.1 Создаем пользователя в PostgreSQL

Входим в систему под пользователем postgres:

sudo su
su postgres

Создаем нового пользователя для репликации:

createuser --replication -P repluser

* система запросит пароль — его нужно придумать и ввести дважды. В данном примере мы создаем пользователя repluser.

Выходим из оболочки пользователя postgres:

exit

2.2 Настраиваем postgresql

Смотрим расположение конфигурационного файла postgresql.conf командой:

su -u postgres -c "psql -c 'SHOW config_file;'"

В моем случае система вернула строку:

/etc/postgresql/10/main/postgresql.conf

* конфигурационный файл находится по пути /etc/postgresql/10/main/postgresql.conf.

Открываем конфигурационный файл postgresql.conf.

nano /etc/postgresql/10/main/postgresql.conf

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

listen_addresses = 'localhost, 10.14.0.143'
wal_level = replica
max_wal_senders = 2
max_replication_slots = 2
hot_standby = on
hot_standby_feedback = on

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

Открываем конфигурационный файл pg_hba.conf — он находитсяч в том же каталоге, что и файл postgresql.conf:

nano /etc/postgresql/10/main/pg_hba.conf

Добавляем следующие строки:

host replication repluser 127.0.0.1/32 md5
host replication repluser 10.14.0.143/32 md5
host replication repluser 10.14.0.85/32 md5

* данной настройкой мы разрешаем подключение к базе данных replication пользователю repluser с локального сервера (localhost и 10.14.0.143) и сервера 10.14.0.85.

Перезапускаем службу postgresql:

systemctl restart postgresql
  • обратите внимание, что название для сервиса в системах Linux может различаться.

3. Настройки на Slave

3.1 Подготавливаемся к репликации

Смотрим путь до конфигурационного файла postgresql:

sudo su
su -u postgres -c "psql -c 'SHOW data_directory;'" 

В моем случае путь был:

/var/lib/postgresql/10/main

Также смотрим путь до конфигурационного файла postgresql.conf (нам это понадобиться ниже):

su -u postgres -c "psql -c 'SHOW config_file;'"

Останавливаем сервис postgresql:

systemctl stop postgresql

На всякий случай, создаем архив базы:

tar -czvf /tmp/data_pgsql.tar.gz /var/lib/postgresql/10/main

* в данном примере мы сохраним все содержимое каталога /var/lib/pgsql/9.6/data в виде архива /tmp/data_pgsql.tar.gz.

Удаляем содержимое каталога с данными:

rm -rf /var/lib/postgresql/10/main/*

3.2 Реплицируем данные с Master сервера

а) Если у нас postgresql 9:

su -u postgres -с "pg_basebackup \
-h 10.14.0.143 \
-U repluser \
-D /var/lib/pgsql/9.6/data \
--xlog-method=stream \
--write-recovery-conf"
  • где 10.14.0.143 — IP-адрес мастера
  • /var/lib/pgsql/9.6/data — путь до каталога с данными.

б) Если у нас postgresql 10:

# Входим в screen
screen -S recovery
sudo su

pg_basebackup \
--host=10.14.0.143 \
--username=repluser \
--pgdata=/var/lib/postgresql/10/main \
--progress \
--checkpoint=fast \
--wal-method=stream \
--write-recovery-conf \
&& chown -R postgres:postgres /var/lib/postgresql/10/main \
&& service postgresql start

# Выход из Screen Ctrl+a и d
# Просмотр всех сеансов screen -ls
# Подключится обратно screen -r recovery
  • где 10.14.0.143 — IP-адрес мастера
  • /var/lib/postgresql/10/main — путь до каталога с данными.

После ввода команды система запросит пароль для созданной ранее учетной записи repluser — вводим его. Начнется процесс клонирования данных.

А еще, желательно, почитать о том, что такое pg_basebackup

3.3 Настраиваем конфиг Slave сервера после клонирования данных

Ввиду того, что утилита pg_basebackup (которой мы пользовались выше) клонирует БД полностью, в том числе и конфиги, то не повторяйте мою ошибку. Только после окончания миграции данных из пункта 2.2 вы открываете конфигурационный файл postgresql.conf на Slave:

nano /etc/postgresql/10/main/postgresql.conf

Если это сделать во время миграции, старый конфиг, который вы изменили, затрется тем, что восстановится с Master и репликации у вас не будет. А будут только данные, сбэкапленные с Мастера. Идем дальше.

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

listen_addresses = 'localhost, 10.14.0.85'
  • где 10.14.0.85 — IP-адрес нашего вторичного сервера (Slave).

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

systemctl start postgresql

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

4.1 Посмотреть статус

Статус работы репликации можно посмотреть следующими командами.

На Master:

select * from pg_stat_replication;

На Slave:

select * from pg_stat_wal_receiver;

4.2 Создать тестовую базу

На мастере заходим в командную оболочку PostgreSQL:

su -u postgres -c "psql"

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

=# CREATE DATABASE repltest ENCODING='UTF8';

Теперь на Slave сервере смотрим список баз:

su -u postgres -c "psql"

=# \l

Мы должны увидеть среди баз ту, которую создали на первичном сервере:

   Name    |  Owner   | Encoding |   Collate   |    Ctype    |   Access
 ...
 repltest  | postgres | UTF8     | ru_RU.UTF-8 | ru_RU.UTF-8 | 
 ...

5. Восстановление

5.1 Превращаем Slave в Master

Что делать, когда ваш мастер случайно и неожиданно умер? Правильно. Нужно повысить Slave до Master. Потом создать новый сервер и повторить все шаги с начала этой статьи.

sudo -u postgres /usr/lib/postgresql/10/bin/pg_ctl promote -D /var/lib/postgresql/10/main
  • где pg_ctl - утилита работы с сервером
  • -D /var/lib/postgresql/10/main -- путь до наших данных в postgresql 

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

Легко проверить, что в бывшую реплику теперь можно писать. Конечно, если только вы не использовали синхронную репликацию с одной-единственной репликой.

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

5.2 Переключение на новый Master

Переключение остальных реплик на новый мастер, а также восстановление бывшего мастера в качестве реплики происходит одинаково.

Чтобы было чуть меньше путаницы с новым мастером, старым мастером, старой репликой и новой репликой, условимся, что сервера мы называем в соответствии с их текущими ролями. То есть, мастером мы называем новый мастер, бывший репликой до фейловера, а репликой — тот, второй сервер.

В простом и не совсем правильном варианте нужно отредактировать, или создать, если его еще нет, файл /var/lib/postgresql/10/main/recovery.conf, указав в нем правильный IP мастера, и сделать sudo service postgresql restart (простой reload не прокатит). Кто-то для того, чтобы не править конфиги и не останавливать СУБД, использует схему с балансировщикам и DNS, но я лично так никогда не делал. В любом случае, этот способ неправильный. Для того, чтобы все хорошо работало во всяких хитрых граничных случаях, реплику следует остановить, сделать pg_rewind, затем запустить реплику.

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

Если вы считаете, что pg_rewind не требуется при использовании синхронной репликации, вот пример маловероятной, но теоретически возможной ситуации. У вас много серверов с PostgreSQL. Сервера в кластере умирают сравнительно часто, поэтому вы решили автоматизировать фейловер. Умирает мастер, запускается фейловер. Среди реплик находится та, что имеет наиболее длинный WAL, на ней делается pg_ctl promote. В этот момент с очень большой задержкой (скажем, 5 секунд — были какие-то сетевые проблемы) на другую реплику прилетает пакет от уже мертвого мастера, и WAL этой реплики становится длиннее WAL нового мастера. Вы не сможете подключить эту реплику к новому мастеру, все сломалось. Если вы хотите, чтобы фейловер работал в том числе и при таких странных граничных случаях, используйте pg_rewind.

Итак, на реплике говорим:

sudo -u postgres /usr/lib/postgresql/9.5/bin/pg_rewind \
  -D /var/lib/postgresql/9.5/main/ \
  --source-server="host=10.0.3.223 port=5432 user=postgres password=??"

Перемещаем и правим recovery.conf:

sudo mv /var/lib/postgresql/9.5/main/recovery.done \
  /var/lib/postgresql/9.5/main/recovery.conf
sudo vim /var/lib/postgresql/9.5/main/recovery.conf

Проверяем IP мастера и наличие строчки:

recovery_target_timeline = 'latest'

Запускаем реплику, смотрим в логи. Там обязательно должно быть:

LOG:  database system is ready to accept read only connections

Значит PostgreSQL работает в качестве реплики.

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

ERROR: requested WAL segment 0000000200000005 has already been removed

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

PS: Ошибка локали.
Если у вас стоит убунта, с EN_US UTF8, а базы созданы в локали RU_UTF8, то сделайте следующее:

sudo locale-gen ru_RU.UTF-8

И еще немного теории и практики вот тут

Оцените статью

Еще никто не оставил комментарий. Будьте первым!