Техподдержка: База знаний

Бэкап postgresql

ID статьи: 9
Последнее обновление: 21 янв, 2023

Бэкап postgresql из Linux

Возможности и условия

  • Можно запускать как на сервере с установленным postgresql, так и на удаленной машине.
  • Нужно убедиться, что на удаленной машине установлены клиентские утилиты такой же версии, как и версия сервера.
  • На сервере postgresql нужно не забыть подправить файл pg_hba.conf, чтобы открыть доступ с айпи удаленного ПК.
  • В системе должен быть установлен архиватор pigz, он многопоточный, быстро зажмет большую базу.
  • Добавлены проверки требований, если в системе чего-то не хватает - скрипт расскажет об этом в консоли и логе.
  • Скрипт предназначен для запуска только с linux машины, но ничто не мешает ему подключиться к серверу, который развернут на Windows.
  • Есть возможность остановить сервер 1с на локальном или удаленном ПК, чтобы гарантированно выгнать всех пользователей.
  • Есть возможность после снятия дампа запустить vacuumdb и reindexdb для обслуживания и очистки базы от мусора.
  • Можно бэкапить только явно заданные базы.
  • Можно без перечисления автоматически бэкапить все базы что есть на сервере. В этом режиме можно настроить список исключений.
  • Настраиваемое кол-во хранимых архивов.
  • Ведутся логи в /var/log/%имя_скрипта%
  • В логах создается файл-статус под бэкап каждой базы, на его основе можно добавить мониторинг zabbix.
  • Очень рекомендую почитать сам скрпит, я его ОЧЕНЬ подробно откомментировал.

Листинг скрипта

#!/bin/bash
PATH=/etc:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin

### ОСТАЛОСЬ ОТТЕСТИТЬ, ЧТОБЫ В ЛОГИ ПОПАДАЛИ ОШИБКИ ПРИ УДАЛЕННОМ ВЫКЛЮЧЕНИИ 1С СЕРВЕРА ЧЕРЕЗ ССШ

# НУЖЕН УСТАНОВЛЕННЫЙ PIGZ, он жмет sql дампы многопоточно, это намного быстрее в отличии от обычного gzip.
# Делай уникальное имя скрипта, он автоматически созадет папку логов и папку хранения дампов по именя этого файла.
# Убирай лишние права с этого файла, тут много конфиденциальной информации.


#####################
###   НАСТРОЙКИ   ###
#####################

# Останавливать ли 1с сервер перед выполнением скрипта? Запуск сервера после снятия дампа автоматический.
# Вообще pg_dump отлично снимет бэкап даже в том случае, если пользователи сидят в 1с.
# На нескольких форумах видел холивары, что если во время снятия дампа будут проводиться какие-то транзакции
# есть вариант получить неконсистентный бэкап. Т.е. физически файл получится нормальным и из него можно будет восстановиться,
# но логическая структура данных внутри него будет повреждена.
# Вообще вполне достаточно запускать этот скрипт ночью, когда в базе гарантированно никто не сидит.
# Но на всякий случай добавил возможность останавливать сервер 1с, чтобы по БД гарантированно никаких движений не было.
# 1 - останавливать; 0 - не останавливать.
STOP1C=0

# Адрес удаленного 1с сервера или localhost в случае локального инстанса
STOP1CHOST=localhost

# Пользователь под которым мы войдем на удаленную машину с сервером 1c, должны иметься права на остановку демона. Не забудь настроить
# прозрачную авторизацию по ssh ключам из пользователя от которого запущен скрипт на сервер с 1с в пользователя указанного в этой переменной.
STOP1CUSER=root

# Команда остановки и запуска, прописываем как писал бы в шеле. Помни, что при обновлении релиза имя юнита изменится, поменяй его и здесь.
STOP1SCMD="systemctl stop srv1cv8-8.3.22.1709@default"
START1SCMD="systemctl start srv1cv8-8.3.22.1709@default"

# Настройка конкретных экземпляров исполняемых файлов необходимых для работы скрипта.
# В начале скрипта все эти файлы проверяются на наличие, если чего то нет - скрипт выпадет в ошибку.
PGDUMPX=/opt/pgpro/1c-14/bin/pg_dump
VACAX=/opt/pgpro/1c-14/bin/vacuumdb
REINDX=/opt/pgpro/1c-14/bin/reindexdb
PSQLX=/opt/pgpro/1c-14/bin/psql

# Обычно это менять не надо
PIGZX=/usr/bin/pigz
FINDX=/usr/bin/find

# Пользователь постгрес
USER=postgres

# Пароль пользователя постгрес
PGPASSWORD="password"

# Адрес сервера постгрес
HOST=localhost

# Порт подключения к постгрес, 5432 по умолчанию
PORT=5432

# Снимать ли дамп? Может этим скриптом ты хочешь только провести очистку и реиндексацию таблиц без снятия дампа?
# 1 - делать; 0 - не делать
DODUMP=1

# Делать анализ и очистку БД vacuumdb?
# Вообще при работе постгреса базы со временем разрастаются в объемах. Это нормальное явление.
# Чтобы с этим бороться есть инструмент, который называется vacuum.
# Он может работать как в автоматическом режиме, так называемый autovacuum, так и в ручном режиме.
# Автоматический режим настраивается в конфиге постгреса, дело это не самое простое.
# Если autovacuum выключен, то запустить его вручную можно тут установив параметр VACA=1.
# Процесс очистки запускается не на всем сервере, а только на тех базах,которые указаны ниже в массиве.
# Если автовакуум настроен и он нормально работает, то смысла запускать его вручную нет никакого.
# Есть хорошая статья, она объясняет почему растут базы, как работает vacuum и как настроить autovacuum
# https://infostart.ru/1c/articles/1191667/?
# 1 - делать; 0 - не делать
VACA=0

# Делать ли реиндексацию таблиц БД?
# Тоже регламентная операция, которая позволяет сохранять быстродействие БД на нормальном уровне
# Статья для самообразования по этой теме
# https://interface31.ru/tech_it/2021/05/testirovanie-i-ispravlenie-informacionnoy-bazy-chto-delaet-i-dlya-chego-nuzhno.html
# 1 - делать; 0 - не делать
REIND=0

# Опции pg_dump, удобно менять тут, а не в экзекуции, обычно не требуются.
OPTS=

# Режим обработки баз на сервере
# DBSTYPE=all автоматическое построение списка баз и работа над ВСЕМИ БД, кроме тех, что обозначены в массиве исключенных баз DBSEXCL.
# DBSTYPE= работа только с теми БД, которые явно перечислены в массиве DBS.
DBSTYPE=all

# Массив баз для обработки, регистр символов важен!
# При DBSTYPE=all заданные тут значения игнорируются
DBS=(
'dbname1'
'dbname2'
    )

# Массив баз исключенных из операций
# При режиме DBSTYPE= этот параметр игнорируется
# Значения template0, template1 и postgres обязательны - это служебные базы, которые нам точно бэкапить не надо.
# Названия своих баз, которые не хотим бэкапить добавляем ниже
DBSEXCL=(
'template0'
'template1'
'postgres'
)

# Куда складывать дампы
DEST=/var/1C/backup

# Сколько хранить дампы
# Если дамп снялся с ошибками, старые файлы не удаляются.
# Если в настройка скрипта дамп выключен (DODUMP=0), старые файлы не удаляются
# Варианты:
# -mtime +10 (удалять дампы старше 10 дней)
# -cmin +120 (удалять дампы старше 2 часов)
KEEPDUMPS="-mtime +10"


#######################################
###   ПОДГОТОВКА ДАННЫХ, ПРОВЕРКИ   ###
#######################################

# Лог вывода pg_dump
MDLOG="/var/log/pg_dump/`basename "$0"`"
DEST="$DEST/`basename "$0"`"

# Определяем дату запуска скрипта
DATE=`date +%Y-%m-%d_%H-%M-%S`

# Подготавливаемся к работе, создаем необходимые каталоги
mkdir -p $MDLOG
mkdir -p $DEST

# Обнулим переменную ошибки, если по проверкам что-то пойдет не так, то в нее запишется другое значение.
# В конце этого блока переменную проверим, если она не = 0, то скрипт остановим.
ERR=0

# Проверяем есть ли установленный PIGZ в системе, если нет останавливаемся и пишем ошибку в лог
if [ -e $PIGZX ]
    then 
        echo "found pigz!"
    else
        echo "Check PIGZX setting in script settings"
        echo "$DATE - Check PIGZX setting in script settings">>$MDLOG/`basename "$0"`-ERROR.log
        ERR=1
fi

# Проверяем правильно настроен ли pg_dump
if [ -e $PGDUMPX ]
    then
        echo "found pg_dump!"
    else
        echo "Check PGDUMPX setting in script settings"
        echo "$DATE - Check PGDUMPX setting in script settings">>$MDLOG/`basename "$0"`-ERROR.log
        ERR=1
fi


# Проверяем правильно настроен ли vacuumdb
if [ -e $VACAX ]
    then
        echo "found vacuumdb!"
    else
        echo "Check VACAX setting in script settings"
        echo "$DATE - Check VACAX setting in script settings">>$MDLOG/`basename "$0"`-ERROR.log
        ERR=1
fi


# Проверяем правильно ли настроен reindexdb
if [ -e $REINDX ]
    then
        echo "found reindexdb!"
    else
        echo "Check REINDX setting in script settings"
        echo "$DATE - Check REINDX setting in script settings">>$MDLOG/`basename "$0"`-ERROR.log
        ERR=1
fi


# Проверяем правильно настроен ли psql
if [ -e $PSQLX ]
    then
        echo "found psql!"
    else
        echo "Check PSQLX setting in script settings"
        echo "$DATE - Check PSQLX setting in script settings">>$MDLOG/`basename "$0"`-ERROR.log
        ERR=1
fi

# Проверяем правильно настроен ли find
if [ -e $FINDX ]
    then
        echo "found find!"
    else
        echo "Check FINDX setting in script settings"
        echo "$DATE - Check FINDX setting in script settings">>$MDLOG/`basename "$0"`-ERROR.log
        ERR=1
fi

# Проверки закончились, смотрим на переменную и принимаем решение что делать дальше.
if [ $ERR != 0 ]
    then
        exit
    else
        # На этом месте все проверки пройдены, сотрем файл лога с ошибкой чтобы никого им не пугать
        rm -f $MDLOG/`basename "$0"`-ERROR.log > /dev/null
fi

# Экспортируем переменную с паролем от постгреса
export PGPASSWORD

# Проверяем какой установлен режим выборки баз в параметре DBSTYPE
# если он равен all нужно переопределить список баз
if [ "$DBSTYPE" = "all" ]; then
    for t in ${DBSEXCL[@]}; do
    DBLINE=$DBLINE,$t
    done
    unset DBS
    DBS=`$PSQLX -h $HOST -U $USER -p $PORT -t -A -c "SELECT datname FROM pg_database WHERE datname <> ALL ('{${DBLINE:1}}')"`
fi

echo $DATE - Script started >> $MDLOG/$DATE--$HOST.log

# Определяем надо ли было по условиям останавливать сервер 1с, останавливаем если надо
if [ "$STOP1C" == "1" ]; then
    if [ "$STOP1CHOST" == "localhost" ];
        then
            echo $DATE - Stopping 1sserver with command [$STOP1SCMD] on [$STOP1CHOST] >> $MDLOG/$DATE--$HOST.log
            $STOP1SCMD &>> $MDLOG/$DATE--$HOST.log
        else
            echo $DATE - Stopping 1sserver with command [$STOP1SCMD] on [$STOP1CHOST] >> $MDLOG/$DATE--$HOST.log
            ssh $STOP1CUSER@$STOP1CHOST "$STOP1SCMD" &>> $MDLOG/$DATE--$HOST.log
    fi
else
    echo $DATE - Script started >> $MDLOG/$DATE--$HOST.log
    echo $DATE - No need to stop 1sserver, STOP1C=0 >> $MDLOG/$DATE--$HOST.log
fi


# Обрабатываем массив с перечнем баз и каждую экспортируем.
# ВАЖНО!!! В системе должен стоять pigz архиватор, пользуем его, т.к. он задействует все ядра
for db in ${DBS[@]}; do
    echo  >> $MDLOG/$DATE--$HOST.log
    echo  >> $MDLOG/$DATE--$HOST.log
    echo `date +%Y-%m-%d_%H-%M-%S` - Start working with database [$db] on server [$HOST] >> $MDLOG/$DATE--$HOST.log

    # Уточняем в параметра надо ли делать дамп.
    if [ "$DODUMP" == "1" ]
        then
            echo `date +%Y-%m-%d_%H-%M-%S` - Dumping... >> $MDLOG/$DATE--$HOST.log
            $PGDUMPX -h $HOST -U $USER -p $PORT $OPTS $db > $DEST/$DATE--$HOST--$db.sql 2>>$MDLOG/$DATE--$HOST.log
            # Проверим получившийся дамп.
            # В случае успешного копирования я знаю что должно быть в первой и последней строке дампа.
            # Если я нахожу в дампе нужные мне строки - пишем в лог ОК и жмем дамп,
            # если в этих строках не то что мне нужно - пишем в лог ERROR и дамп стираем.
            FIRST=`head -n 2 $DEST/$DATE--$HOST--$db.sql | grep "database dump" | wc -l`
            LAST=`tail -n 3 $DEST/$DATE--$HOST--$db.sql | grep "dump complete" | wc -l`
            if [ "$FIRST" == "1" ];then
                if [ "$LAST" == "1" ];then
                    echo $DATE $DEST/$DATE--$HOST--$db.sql - OK, starting pigz >> $MDLOG/$HOST--$db--status.log
                    echo `date +%Y-%m-%d_%H-%M-%S` - Archiving with pigz... >> $MDLOG/$DATE--$HOST.log
                    $PIGZX $DEST/$DATE--$HOST--$db.sql &>>$MDLOG/$DATE--$HOST.log

                    # Удаляем архивы и логи старше KEEPDUMPS
                    echo `date +%Y-%m-%d_%H-%M-%S` - Searching and deleting old [$db] dumps... >> $MDLOG/$DATE--$HOST.log
                    $FINDX $DEST/*--$HOST--$db.sql.gz -type f $KEEPDUMPS -exec rm -rf {} \; &>> $MDLOG/$DATE--$HOST.log
                else
                    echo `date +%F_%H-%M` $DEST/$DATE--$HOST--$db.sql - ERROR, deleting bad dump >> $MDLOG/$HOST--$db--status.log
                    /usr/bin/rm $DEST/$DATE--$HOST--$db.sql
                fi
            else
                echo $DATE $DEST/$DATE--$HOST--$db.sql - ERROR, deleting bad dump >> $MDLOG/$HOST--$db--status.log
                /usr/bin/rm $DEST/$DATE--$HOST--$db.sql
            fi

        else
            echo `date +%Y-%m-%d_%H-%M-%S` - Dump disabled, DODUMP=$DODUMP >> $MDLOG/$DATE--$HOST.log
    fi

    # Проверяем надо ли делать очистку БД
    if [ "$VACA" == "1" ]; then
        echo `date +%Y-%m-%d_%H-%M-%S` - Analising with vacuumdb... >> $MDLOG/$DATE--$HOST.log
        $VACAX -h $HOST -U $USER -p $PORT --full --analyze $db 2>>$MDLOG/$DATE--$HOST.log
    else
        echo `date +%Y-%m-%d_%H-%M-%S` - Vacuum and analyse disabled >> $MDLOG/$DATE--$HOST.log
    fi

    # Делаем реиндексацию БД
    if [ "$REIND" == "1" ]; then
        echo `date +%Y-%m-%d_%H-%M-%S` - Analising with reindexdb... >> $MDLOG/$DATE--$HOST.log
        $REINDX -h $HOST -U $USER -p $PORT $db 2>>$MDLOG/$DATE--$HOST.log
    else
        echo `date +%Y-%m-%d_%H-%M-%S` - Reindexdb disabled >> $MDLOG/$DATE--$HOST.log
    fi

done

# Если сервер 1с мы останавливали, то запускаем его по окончанию всех действий
if [ "$STOP1C" == "1" ]; then
    if [ "$STOP1CHOST" == "localhost" ];
        then
            echo >> $MDLOG/$DATE--$HOST.log
            echo >> $MDLOG/$DATE--$HOST.log
            echo `date +%Y-%m-%d_%H-%M-%S` - Starting 1sserver with command [$START1SCMD] on [$STOP1CHOST] >> $MDLOG/$DATE--$HOST.log
            $START1SCMD &>> $MDLOG/$DATE--$HOST.log
        else
            echo >> $MDLOG/$DATE--$HOST.log
            echo >> $MDLOG/$DATE--$HOST.log
            echo `date +%Y-%m-%d_%H-%M-%S` - Starting 1sserver with command [$START1SCMD] on [$STOP1CHOST] >> $MDLOG/$DATE--$HOST.log
            ssh $STOP1CUSER@$STOP1CHOST "$START1SCMD" &>> $MDLOG/$DATE--$HOST.log
    fi
else
    echo >> $MDLOG/$DATE--$HOST.log
    echo >> $MDLOG/$DATE--$HOST.log
    echo `date +%Y-%m-%d_%H-%M-%S` - No need to start 1sserver, it running, STOP1C=0 >> $MDLOG/$DATE--$HOST.log
fi

echo `date +%Y-%m-%d_%H-%M-%S` - Searching and deleting old logs... >> $MDLOG/$DATE--$HOST.log
$FINDX $MDLOG/*--$HOST.log* -type f $KEEPDUMPS -exec rm -rf {} \; &>> $MDLOG/$DATE--$HOST.log

echo `date +%Y-%m-%d_%H-%M-%S` - All done >> $MDLOG/$DATE--$HOST.log

# Обнулим переменную с паролем постгреса
unset PGPASSWORD

##################
# Восстановление #
##################

# Подключаемся к серверу postgresql
#psql -h address -U username

# Получаем список всех баз
#\l

# Удаляем ненужную базу
# Иногда база неудаляется, т.к. она занята.
# Если pgAdmin открыт - надо закрыть.
# Из кластера 1с в этой базе нужно выкинуть всех пользователей и регламентные задания
#DROP DATABASE baddatabase;

# Создаем новую базу
#CREATE DATABASE newdatabase;

# Выходим из консоли БД
#\q

# Заливаем в созданную пустую БД дамп
#zcat dump.sql.gz | psql -h address -U username newdatabase

Процесс восстановления из бэкапа

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

Бэкап postgresql из Windows

На сегодняшний день у нас нет необходимости бэкапиться на windows, поэтому тут мне особо написать нечего.

Точно знаю, что и в платной, и бесплатной версии Effector Saver есть возможность делать дамп силами постгреса. Только в системе должна быть установлена клиентская утилита pg_dump.

Пока необходимости портировать скрипт с linux на cmd нет.

ID статьи: 9
Последнее обновление: 21 янв, 2023
Ревизия: 10
Просмотры: 0
Комментарии: 0