- LINUX
- GIT
- DOCKER
- DOCKERFILE
- DOCKER-COMPOSE
- DOCKERSWARM
- KUBERNETES
- ANSIBLE
- BASH
- 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
И еще немного теории и практики вот тут