WAL-G: còpies de seguretat i recuperació de SGBD PostgreSQL

Fa temps que se sap que fer còpies de seguretat en abocadors SQL (utilitzant pg_dump o pg_dumpall) no és una bona idea. Per fer una còpia de seguretat del SGBD PostgreSQL, és millor utilitzar l'ordre pg_basebackup, que fa una còpia binària dels registres WAL. Però quan comencis a estudiar tot el procés de creació d'una còpia i restauració, entendràs que cal escriure almenys un parell de tricicles perquè això funcioni i no et provoqui dolor tant a dalt com a sota. Per alleujar el patiment, es va desenvolupar WAL-G.

WAL-G és una eina escrita a Go per fer còpies de seguretat i restaurar bases de dades PostgreSQL (i més recentment MySQL/MariaDB, MongoDB i FoundationDB). Admet treballar amb emmagatzematge d'Amazon S3 (i anàlegs, per exemple, Yandex Object Storage), així com Google Cloud Storage, Azure Storage, Swift Object Storage i simplement amb el sistema de fitxers. Tota la configuració es redueix a passos senzills, però a causa del fet que els articles al respecte estan escampats per Internet, no hi ha cap manual complet que inclogui tots els passos des del principi fins al final (hi ha diverses publicacions a Habré, però hi falten molts punts).

WAL-G: còpies de seguretat i recuperació de SGBD PostgreSQL

Aquest article va ser escrit principalment per sistematitzar els meus coneixements. No sóc DBA i puc expressar-me en un llenguatge profà en algun lloc, així que qualsevol correcció és benvinguda!

Per separat, observo que tot el que hi ha a continuació és rellevant i provat per a PostgreSQL 12.3 a Ubuntu 18.04, totes les ordres s'han d'executar com a usuari amb privilegis.

Instal · lació

En el moment d'escriure aquest article, la versió estable de WAL-G és v0.2.15 (març de 2020). Això és el que farem servir (però si voleu construir-lo vosaltres mateixos des de la branca mestra, aleshores el repositori github té totes les instruccions per a això). Per descarregar i instal·lar cal fer:

#!/bin/bash

curl -L "https://github.com/wal-g/wal-g/releases/download/v0.2.15/wal-g.linux-amd64.tar.gz" -o "wal-g.linux-amd64.tar.gz"
tar -xzf wal-g.linux-amd64.tar.gz
mv wal-g /usr/local/bin/

Després d'això, primer heu de configurar WAL-G i després el mateix PostgreSQL.

Configuració de WAL-G

Per a un exemple d'emmagatzematge de còpies de seguretat, s'utilitzarà Amazon S3 (perquè està més a prop dels meus servidors i el seu ús és molt barat). Per treballar-hi, necessiteu un "cub s3" i claus d'accés.

Tots els articles anteriors sobre WAL-G utilitzaven la configuració mitjançant variables d'entorn, però amb aquesta versió la configuració es pot localitzar a fitxer .walg.json al directori d'inici de l'usuari de postgres. Per crear-lo, executeu l'script bash següent:

#!/bin/bash

cat > /var/lib/postgresql/.walg.json << EOF
{
    "WALG_S3_PREFIX": "s3://your_bucket/path",
    "AWS_ACCESS_KEY_ID": "key_id",
    "AWS_SECRET_ACCESS_KEY": "secret_key",
    "WALG_COMPRESSION_METHOD": "brotli",
    "WALG_DELTA_MAX_STEPS": "5",
    "PGDATA": "/var/lib/postgresql/12/main",
    "PGHOST": "/var/run/postgresql/.s.PGSQL.5432"
}
EOF
# обязательно меняем владельца файла:
chown postgres: /var/lib/postgresql/.walg.json

Permeteu-me explicar una mica sobre tots els paràmetres:

  • WALG_S3_PREFIX – el camí al vostre cub S3 on es penjaran les còpies de seguretat (pots fer-ho a l'arrel o a una carpeta);
  • AWS_ACCESS_KEY_ID - clau d'accés a S3 (en cas de recuperació en un servidor de prova, aquestes claus han de tenir una política de només lectura! Això es descriu amb més detall a la secció de recuperació.);
  • AWS_SECRET_ACCESS_KEY – clau secreta a l'emmagatzematge S3;
  • WALG_COMPRESSION_METHOD – mètode de compressió, és millor utilitzar Brotli (ja que aquesta és la mitjana daurada entre la mida final i la velocitat de compressió/descompressió);
  • WALG_DELTA_MAX_STEPS – el nombre de “deltas” abans de crear una còpia de seguretat completa (estalvien temps i la mida de les dades descarregades, però poden alentir lleugerament el procés de recuperació, per la qual cosa no és recomanable utilitzar valors grans);
  • PGDATA - camí al directori amb les dades de la vostra base de dades (podeu esbrinar executant l'ordre pg_lsclusters);
  • PGHOST – connectant-se a la base de dades, amb una còpia de seguretat local és millor fer-ho mitjançant un socket Unix com en aquest exemple.

Altres paràmetres es poden trobar a la documentació: https://github.com/wal-g/wal-g/blob/v0.2.15/PostgreSQL.md#configuration.

Configuració de PostgreSQL

Perquè l'arxivador dins de la base de dades carregui els registres WAL al núvol i els restauri des d'ells (si cal), heu d'establir diversos paràmetres al fitxer de configuració. /etc/postgresql/12/main/postgresql.conf. Només per començar cal assegurar-seque cap dels paràmetres següents no tingui cap altre valor, de manera que quan es torni a carregar la configuració, el SGBD no es bloqueja. Podeu afegir aquests paràmetres mitjançant:

#!/bin/bash

echo "wal_level=replica" >> /etc/postgresql/12/main/postgresql.conf
echo "archive_mode=on" >> /etc/postgresql/12/main/postgresql.conf
echo "archive_command='/usr/local/bin/wal-g wal-push "%p" >> /var/log/postgresql/archive_command.log 2>&1' " >> /etc/postgresql/12/main/postgresql.conf
echo “archive_timeout=60” >> /etc/postgresql/12/main/postgresql.conf
echo "restore_command='/usr/local/bin/wal-g wal-fetch "%f" "%p" >> /var/log/postgresql/restore_command.log 2>&1' " >> /etc/postgresql/12/main/postgresql.conf

# перезагружаем конфиг через отправку SIGHUP сигнала всем процессам БД
killall -s HUP postgres

Descripció dels paràmetres a configurar:

  • nivell_wal – quanta informació cal escriure als registres WAL, “rèplica” – escriu-ho tot;
  • mode_arxiu – habiliteu la descàrrega de registres WAL mitjançant l'ordre del paràmetre ordre_arxiu;
  • ordre_arxiu – ordre per arxivar un registre WAL completat;
  • archive_timeout – l'arxivament de registres es realitza només quan s'ha completat, però si el vostre servidor canvia/afegeix poques dades a la base de dades, té sentit establir aquí un límit en segons, després del qual l'ordre d'arxivament es cridarà a la força (Escric intensament a la base de dades cada segon, així que vaig decidir no establir aquest paràmetre en producció);
  • comanda_restaurar – s'utilitzarà l'ordre per restaurar el registre WAL des d'una còpia de seguretat si la "còpia de seguretat completa" (còpia de seguretat base) no té els darrers canvis a la base de dades.

Podeu llegir més sobre tots aquests paràmetres a la traducció de la documentació oficial: https://postgrespro.ru/docs/postgresql/12/runtime-config-wal.

Configuració d'un programa de còpia de seguretat

Sigui el que es digui, la manera més còmoda d'executar-lo és cron. Això és el que configurarem per crear còpies de seguretat. Comencem amb l'ordre per crear una còpia de seguretat completa: a wal-g aquest és l'argument de llançament backup-push. Però primer, és millor executar aquesta comanda manualment des de l'usuari de postgres per assegurar-se que tot està bé (i no hi ha errors d'accés):

#!/bin/bash

su - postgres -c '/usr/local/bin/wal-g backup-push /var/lib/postgresql/12/main'

Els arguments de llançament indiquen el camí al directori de dades; us recordo que podeu trobar-ho executant-lo pg_lsclusters.

Si tot ha anat sense errors i les dades es van carregar a l'emmagatzematge S3, llavors podeu configurar el llançament periòdic a crontab:

#!/bin/bash

echo "15 4 * * *    /usr/local/bin/wal-g backup-push /var/lib/postgresql/12/main >> /var/log/postgresql/walg_backup.log 2>&1" >> /var/spool/cron/crontabs/postgres
# задаем владельца и выставляем правильные права файлу
chown postgres: /var/spool/cron/crontabs/postgres
chmod 600 /var/spool/cron/crontabs/postgres

En aquest exemple, el procés de còpia de seguretat comença cada dia a les 4:15 del matí.

Eliminació de còpies de seguretat antigues

El més probable és que no necessiteu conservar absolutament totes les còpies de seguretat de l'era mesozoica, per la qual cosa serà útil "netejar" periòdicament el vostre emmagatzematge (tant "còpies de seguretat completes" com els registres WAL). Tot això ho farem mitjançant una tasca cron:

#!/bin/bash

echo "30 6 * * *    /usr/local/bin/wal-g delete before FIND_FULL $(date -d '-10 days' '+%FT%TZ') --confirm >> /var/log/postgresql/walg_delete.log 2>&1" >> /var/spool/cron/crontabs/postgres
# ещё раз задаем владельца и выставляем правильные права файлу (хоть это обычно это и не нужно повторно делать)
chown postgres: /var/spool/cron/crontabs/postgres
chmod 600 /var/spool/cron/crontabs/postgres

Cron executarà aquesta tasca cada dia a les 6:30 del matí, suprimint-ho tot (còpies de seguretat completes, deltes i WAL) excepte les còpies dels darrers 10 dies, però deixant almenys una còpia de seguretat до data especificada perquè qualsevol punt després les dates es van incloure al PITR.

Restauració des d'una còpia de seguretat

No és cap secret que la clau per a una base de dades sana és la restauració periòdica i la verificació de la integritat de les dades a l'interior. En aquesta secció us explicaré com recuperar-vos amb WAL-G i més endavant parlarem de les comprovacions.

Cal assenyalar-ho per separat que per restaurar en un entorn de prova (tot el que no és de producció) cal utilitzar un compte de només lectura a S3 per no sobreescriure accidentalment les còpies de seguretat. En el cas de WAL-G, cal que configureu els drets següents per a l'usuari S3 a la Política de grup (Efecte: Permetre): s3:GetObject, s3:ListBucket, s3:GetBucketLocation. I, per descomptat, no us oblideu de configurar mode_arxiu=desactivat al fitxer de configuració postgresql.conf, de manera que la vostra base de dades de prova no vol fer una còpia de seguretat en silenci.

La restauració es realitza amb un lleuger moviment de la mà eliminant totes les dades de PostgreSQL (inclosos els usuaris), així que tingueu molta cura quan executeu les ordres següents.

#!/bin/bash

# если есть балансировщик подключений (например, pgbouncer), то вначале отключаем его, чтобы он не нарыгал ошибок в лог
service pgbouncer stop
# если есть демон, который перезапускает упавшие процессы (например, monit), то останавливаем в нём процесс мониторинга базы (у меня это pgsql12)
monit stop pgsql12
# или останавливаем мониторинг полностью
service monit stop
# останавливаем саму базу данных
service postgresql stop
# удаляем все данные из текущей базы (!!!); лучше предварительно сделать их копию, если есть свободное место на диске
rm -rf /var/lib/postgresql/12/main
# скачиваем резервную копию и разархивируем её
su - postgres -c '/usr/local/bin/wal-g backup-fetch /var/lib/postgresql/12/main LATEST'
# помещаем рядом с базой специальный файл-сигнал для восстановления (см. https://postgrespro.ru/docs/postgresql/12/runtime-config-wal#RUNTIME-CONFIG-WAL-ARCHIVE-RECOVERY ), он обязательно должен быть создан от пользователя postgres
su - postgres -c 'touch /var/lib/postgresql/12/main/recovery.signal'
# запускаем базу данных, чтобы она инициировала процесс восстановления
service postgresql start

Per a aquells que vulguin comprovar el procés de recuperació, a continuació s'ha preparat un petit tros de màgia bash, de manera que en cas de problemes en la recuperació, l'script s'estavellarà amb un codi de sortida diferent de zero. En aquest exemple, es fan 120 comprovacions amb un temps d'espera de 5 segons (un total de 10 minuts per a la recuperació) per esbrinar si el fitxer de senyal s'ha suprimit (això significarà que la recuperació va ser correcta):

#!/bin/bash

CHECK_RECOVERY_SIGNAL_ITER=0
while [ ${CHECK_RECOVERY_SIGNAL_ITER} -le 120 ]
do
    if [ ! -f "/var/lib/postgresql/12/main/recovery.signal" ]
    then
        echo "recovery.signal removed"
        break
    fi
    sleep 5
    ((CHECK_RECOVERY_SIGNAL_ITER+1))
done

# если после всех проверок файл всё равно существует, то падаем с ошибкой
if [ -f "/var/lib/postgresql/12/main/recovery.signal" ]
then
    echo "recovery.signal still exists!"
    exit 17
fi

Després de la recuperació correcta, no us oblideu de tornar a iniciar tots els processos (pgbouncer/monit, etc.).

Comprovació de dades després de la recuperació

És imprescindible comprovar la integritat de la base de dades després de la restauració, de manera que no es produeixi una situació amb una còpia de seguretat trencada/torçada. I és millor fer-ho amb cada arxiu creat, però on i com depèn només de la vostra imaginació (podeu augmentar servidors individuals cada hora o fer una comprovació a CI). Però, com a mínim, cal comprovar les dades i els índexs de la base de dades.

Per comprovar les dades, n'hi ha prou d'executar-les a través d'un bolcat, però és millor que en crear la base de dades tingueu les sumes de comprovació habilitades (sumes de comprovació de dades):

#!/bin/bash

if ! su - postgres -c 'pg_dumpall > /dev/null'
then
    echo 'pg_dumpall failed'
    exit 125
fi

Per comprovar els índexs - existeix mòdul amcheck, anem a prendre la consulta sql per a això Proves WAL-G i construïu una mica de lògica al voltant:

#!/bin/bash

# добавляем sql-запрос для проверки в файл во временной директории
cat > /tmp/amcheck.sql << EOF
CREATE EXTENSION IF NOT EXISTS amcheck;
SELECT bt_index_check(c.oid), c.relname, c.relpages
FROM pg_index i
JOIN pg_opclass op ON i.indclass[0] = op.oid
JOIN pg_am am ON op.opcmethod = am.oid
JOIN pg_class c ON i.indexrelid = c.oid
JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE am.amname = 'btree'
AND c.relpersistence != 't'
AND i.indisready AND i.indisvalid;
EOF
chown postgres: /tmp/amcheck.sql

# добавляем скрипт для запуска проверок всех доступных баз в кластере
# (обратите внимание что переменные и запуск команд – экранированы)
cat > /tmp/run_amcheck.sh << EOF
for DBNAME in $(su - postgres -c 'psql -q -A -t -c "SELECT datname FROM pg_database WHERE datistemplate = false;" ')
do
    echo "Database: ${DBNAME}"
    su - postgres -c "psql -f /tmp/amcheck.sql -v 'ON_ERROR_STOP=1' ${DBNAME}" && EXIT_STATUS=$? || EXIT_STATUS=$?
    if [ "${EXIT_STATUS}" -ne 0 ]
    then
        echo "amcheck failed on DB: ${DBNAME}"
        exit 125
    fi
done
EOF
chmod +x /tmp/run_amcheck.sh

# запускаем скрипт
/tmp/run_amcheck.sh > /tmp/amcheck.log

# для проверки что всё прошло успешно можно проверить exit code или grep’нуть ошибку
if grep 'amcheck failed' "/tmp/amcheck.log"
then
    echo 'amcheck failed: '
    cat /tmp/amcheck.log
    exit 125
fi

Resumint

M'agradaria expressar el meu agraïment a Andrey Borodin per la seva ajuda en la preparació de la publicació i un agraïment especial per la seva contribució al desenvolupament de WAL-G!

Això conclou aquesta nota. Espero haver pogut transmetre la facilitat de configuració i l'enorme potencial d'utilitzar aquesta eina a la vostra empresa. Vaig escoltar molt sobre WAL-G, però mai vaig tenir prou temps per seure i descobrir-ho. I després que el vaig implementar a casa, em va sortir aquest article.

Per separat, val la pena assenyalar que WAL-G també pot funcionar amb els següents DBMS:

Font: www.habr.com

Afegeix comentari