Thank you for reading this post, don't forget to subscribe!
Схема бэкапа с возможностью восстановления до определенного времени
В настройках postgresql.conf необходимо указать
archive_mode = on
archive_command = 'cp %p /cluster/wal/%f' # указать путь, куда будут копироваться wal log
Опционально можно добавить параметры, которые будут сохранять wal_log через определенный промежуток времени и/или при достижению определенного размера
Также параметр копирования можно изменить под скрипт или архивацию (в случае, если этого требуют обстоятельства)
Данные параметры позволяют копировать wal_log в указанную директорию. Указанная директория должна иметь пользователя postgres, и иметь параметры 0700
Также в скрипте бэкапа следует указать через какое время удалять забэкапленные данные, которые уже не понадобятся
find "$BASE_DIR/" -mindepth 1 -type d -mtime +7 -print0 | xargs -0r rm -rfv
Схема восстановления БД postgres с возможностью отката на определенное время
Скрипт должен запускаться из директории, в которой будут права на чтение и выполнение пользователя postgres
В файле pg_gba.conf на сервере, на котором будет восстановление должен быть прописан хост, роль и пользователь для репликации
host replication postgres 10.242.144.156/32 md5
Время восстановления нужно будет выбрать из предложенных вариантов
Невозможно будет восстановить базу, на срок меньше, чем время бекапа резервной копии.
Схема для восстановления standolone БД
Убеждаемся, что wal log находятся в нужной директории и имеется нужная временная метка
Для восстановления базы необходимо запустить скрипт для мастера
Скрипт: останавливает postgres, опционально копирует существующий каталог БД, удаляет существующую БД, копирует БД из бэкапа, откатывает БД к нужному временному промежутку, запускает postgres.
Схема для восстановления обычной репликации без фейловераba
Убеждаемся, что wal log находятся в нужной директории и имеется нужная временная метка
На мастере запустить скрипт
Скрипт: останавливает postgres, опционально копирует существующий каталог БД, удаляет существующую БД, копирует БД из бекапа, откатывает БД к нужному временному промежутку, запускает postgres.
На слейве запустить скрипт для слейва
Запускаем скрипт для слейва
Скрипт: останавливает postgres, копирует postgres.conf и pg_hba.conf, удаляет существующую БД, копируем базу с мастера, восстанавливает postgres.conf и pg_hba.conf, запускает postgres
P.S
Если после восстановления БД сразу запустить еще раз восстановление, то может возникнуть баг (при восстановлении БД в директории wal логов автоматически формируются n-ное количество wal логов, которые впоследствии перезаписываются), который копирует пусты сформированные wal логи в директорию с резервными wal логами, и перезаписывает существующие wal логи.
Схема для восстановления БД на кластере patroni
В отличии от standalone и обычной репликации, patroni на основе postgresql до 12 версии не поддерживает восстановление до определенного времени.
В случае, если база упала, то ее можно восстановить до момента, когда был сохранен последний wal log файл.
Важно, чтобы бэкап wal log файлов был в одну общую директорию, для того, чтобы при переключении лидера между срерверами, бэкапы продолжили заливаться
Для восстановления необходимо остановить кластер patroni на нодах
Далее на одной ноде, которая будет лидером, под пользователем постгрес выполняем:
rm -rf /var/lib/pgsql/10/data/* # Удаляем файлы из директории постгреса
cp -r /cluster/tst-vsrv-pg1/2021-05-12/* /var/lib/pgsql/10/data/ # Копируем бэкап базы в директорию data
rm -rf /var/lib/pgsql/10/data/pg_wal/* # Удаляем старые wal log
cp -r /cluster/wal/* /var/lib/pgsql/10/data/pg_wal/ # Копируем забэкапленные wal log
Запускаем patroni, ждем когда база поднимется, и переходим к ноде-реплике
На ноде-реплике:
rm -rf /var/lib/pgsql/10/data/*
Запускаем patroni, база подтянется автоматически
Успешное восстановление базы запустит новую временную линию, и существующий бекап уже восстановить не получиться.
Скрипт бэкапа БД
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#!/bin/bash PGBB='/usr/bin/pg_basebackup' PSQL='/usr/bin/psql' #Определение IP адреса ifcfg=`ls /etc/sysconfig/network-scripts/ | grep "ifcfg-e" | sed 's|.*-||'` IP="$(ip a | grep $ifcfg | tail -1 | awk '{print $2}' | sed 's/\/.*//')" # Пароль от пользователя postgres #PASS='postgres' # Создание директории для бэкапа BASE_DIR='/cluster' YMD=$(date "+%Y-%m-%d") mkdir -p "$BASE_DIR/$HOSTNAME/$YMD/" chown postgres:postgres -R "$BASE_DIR" CLDIR="$BASE_DIR/$HOSTNAME/$YMD/" #su postgres -c "echo $PASS | $PGBB -h $IP -D $CLDIR" su postgres -c "$PGBB -h $IP -D $CLDIR" # Удаляем файлы, в процессе восстановления, которые могут выдать ошибку rm -rf $CLDIR/pg_replslot/* $CLDIR/postmaster.pid $CLDIR/postmaster.opts # Удаляем старые бекапы find "$BASE_DIR/$HOSTNAME/" -mindepth 1 -type d -mtime +7 -print0 | xargs -0r rm -rfv |
Скрипт восстановления БД на мастере
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
#! /bin/bash PSQL='/usr/bin/psql' url_cluster='/cluster' all_wal_log=`ls /cluster/wal/ | grep -vE 'backup|history'` #Определение IP адреса ifcfg=`ls /etc/sysconfig/network-scripts/ | grep "ifcfg-e" | sed 's|.*-||'` IP="$(ip a | grep $ifcfg | tail -1 | awk '{print $2}' | sed 's/\/.*//')" # Версия postgres version_pg=`find /usr/ -name 'postgres' | grep 'bin/postgres' | sed 's|.*-||' | sed 's/\/.*//'` # Определение атрибутов для wal log файлов if [ "$version_pg" = "10" ]; then wal_dir='pg_wal' log_dump=`find /usr/ -name pg_waldump` else wal_dir='pg_xlog' log_dump=`find /usr/ -name pg_xlogdump` fi # Определение свободного места на разделе, где стоит postgres f_size=`df /var | tail -1 | awk '{print $4}'` # Определение размера резервных wal log w_size=`du $url_cluster/wal/ | awk '{print $1}'` # Определение размера резервной копии базы db_size=`du /var/lib/pgsql/$version_pg/data/ | tail -1 | awk '{print $1}'` # Проверка места под wal log if [ "$f_size" -gt "$w_size" ]; then # Проверка существования бекапа echo "Enter the path to the directory, where will be locate backup postgres (path must end with '/')" echo -n "" read answer_bk ch_a_path=""$answer_bk"postgresql.conf" ch_path=`find $answer_bk -name postgresql.conf` if [[ "$ch_a_path" = "$ch_path" ]]; then # Останавливаем postgres systemctl stop postgresql-$version_pg # Опционально: копируем директорию postgres echo "Do you want copy workdir postgres? y/n" echo -n "" read answer_wd if [ "$answer_wd" = "y" ]; then if [ "$f_size" -gt "$db_size" ]; then su postgres -c "mkdir /var/lib/pgsql/$version_pg/archiv_data" su postgres -c "cp -r /var/lib/pgsql/$version_pg/data/* /var/lib/pgsql/$version_pg/archiv_data/" # Удаляем файлы с директории postgres rm -rf /var/lib/pgsql/$version_pg/data/* # Восстанавливаем директорию под пользователем postgres su postgres -c "cp -r $answer_bk* /var/lib/pgsql/$version_pg/data/" # Удаляем старые файлы из wal_dir rm -rf /var/lib/pgsql/$version_pg/data/$wal_dir/* # Копируем wal log из бекапа wal su postgres -c "cp -r $url_cluster/wal/* /var/lib/pgsql/$version_pg/data/$wal_dir/" # Создаем файл восстановления recovery.conf su postgres -c "touch /var/lib/pgsql/$version_pg/data/recovery.conf" echo "restore_command = 'cp $url_cluster/wal/%f %p'" > /var/lib/pgsql/$version_pg/data/recovery.conf # Блок по выбору времени восстановления и внесение настроек в recovery.conf for i in `ls $url_cluster/wal/ | grep -vE 'backup|history'`; do stat $url_cluster/wal/$i | awk '(NR==6)' | awk '{print $2, $3}' | cut -c 1-19 | uniq; done echo "Choose and copy date for need recovery" echo -n "" read answer_data # Определение timeline time_f_m=`echo "$answer_data" | awk '{print $2}' | cut -c 1-5` time_h=`ls -l $url_cluster/wal/ | grep -vE 'backup|history' | grep $time_f_m | awk '{print $9}' | tail -1` timel=`echo "$time_h" | cut -c 1-8` echo "recovery_target_time = '$answer_data'" >> /var/lib/pgsql/$version_pg/data/recovery.conf echo "recovery_target_timeline = '$timel'" >> /var/lib/pgsql/$version_pg/data/recovery.conf echo "recovery_target_inclusive = 'true'" >> /var/lib/pgsql/$version_pg/data/recovery.conf echo "recovery_target_action = 'promote'" >> /var/lib/pgsql/$version_pg/data/recovery.conf # Запускаем postgres systemctl start postgresql-$version_pg else echo "Not enough free space on the partition for backup the database" fi else # Удаляем файлы с директории postgres rm -rf /var/lib/pgsql/$version_pg/data/* # Восстанавливаем директорию под пользователем postgres su postgres -c "cp -r $answer_bk* /var/lib/pgsql/$version_pg/data/" # Удаляем старые файлы из wal_dir rm -rf /var/lib/pgsql/$version_pg/data/$wal_dir/* # Копируем wal log из бекапа wal su postgres -c "cp -r $url_cluster/wal/* /var/lib/pgsql/$version_pg/data/$wal_dir/" # Создаем файл восстановления recovery.conf su postgres -c "touch /var/lib/pgsql/$version_pg/data/recovery.conf" echo "restore_command = 'cp $url_cluster/wal/%f %p'" > /var/lib/pgsql/$version_pg/data/recovery.conf # Блок по выбору времени восстановления и внесение настроек в recovery.conf for i in `ls $url_cluster/wal/ | grep -vE 'backup|history'`; do stat $url_cluster/wal/$i | awk '(NR==6)' | awk '{print $2, $3}' | cut -c 1-19 | uniq; done echo "Choose and copy date for need recovery" echo -n "" read answer_data # Определение timeline time_f_m=`echo "$answer_data" | awk '{print $2}' | cut -c 1-5` time_h=`ls -l $url_cluster/wal/ | grep -vE 'backup|history' | grep $time_f_m | awk '{print $9}' | tail -1` timel=`echo "$time_h" | cut -c 1-8` echo "recovery_target_time = '$answer_data'" >> /var/lib/pgsql/$version_pg/data/recovery.conf echo "recovery_target_timeline = '$timel'" >> /var/lib/pgsql/$version_pg/data/recovery.conf echo "recovery_target_inclusive = 'true'" >> /var/lib/pgsql/$version_pg/data/recovery.conf echo "recovery_target_action = 'promote'" >> /var/lib/pgsql/$version_pg/data/recovery.conf # Запускаем postgres systemctl start postgresql-$version_pg fi else echo "Not found directory with backup" fi else echo "Not enough free space on the partition for copy wal log" fi |
Восстановление базы на слейве
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
#! /bin/bash echo "Enter IP adress master postgres" echo -n "" read IP_M # Версия postgres version_pg=`find /usr/ -name 'postgres' | grep 'bin/postgres' | sed 's|.*-||' | sed 's/\/.*//'` # Останавливаем postgres systemctl stop postgresql-$version_pg # Копируем postgres.conf и pg_hba.conf su postgres -c "cp /var/lib/pgsql/$version_pg/data/postgresql.conf /var/lib/pgsql/$version_pg/" su postgres -c "cp /var/lib/pgsql/$version_pg/data/pg_hba.conf /var/lib/pgsql/$version_pg/" # Удаляем файлы с директории postgres rm -rf /var/lib/pgsql/$version_pg/data/* # Копируем базу с мастера на слейв su postgres -c "pg_basebackup -h $IP_M -U postgres -D /var/lib/pgsql/$version_pg/data --xlog-method=stream --write-recovery-conf" # Восстанавливаем postgres.conf и pg_hba.conf su postgres -c "cp /var/lib/pgsql/$version_pg/postgresql.conf /var/lib/pgsql/$version_pg/data/" su postgres -c "cp /var/lib/pgsql/$version_pg/pg_hba.conf /var/lib/pgsql/$version_pg/data/" # Запускаем postgres systemctl start postgresql-$version_pg |