WAL-G: sekurkopioj kaj reakiro de PostgreSQL DBMS

Delonge oni scias, ke fari sekurkopiojn en SQL-rubejojn (uzante pg_dumppg_dumpall) ne estas bona ideo. Por sekurkopii la PostgreSQL-DBMS, estas pli bone uzi la komandon pg_basebackup, kiu faras binaran kopion de WAL-protokoloj. Sed kiam vi komencos studi la tutan procezon krei kopion kaj restarigi, vi komprenos, ke vi devas skribi almenaŭ kelkajn triciklojn por ke ĉi tio funkciu kaj ne kaŭzu vin doloro kaj supre kaj sube. Por mildigi suferon, WAL-G estis evoluigita.

WAL-G estas ilo skribita en Go por sekurkopio kaj restarigo de PostgreSQL-datumbazoj (kaj pli lastatempe MySQL/MariaDB, MongoDB kaj FoundationDB). Ĝi subtenas labori kun Amazon S3-stokado (kaj analogoj, ekzemple, Yandex Object Storage), same kiel Google Cloud Storage, Azure Storage, Swift Object Storage kaj simple kun la dosiersistemo. La tuta aranĝo konsistas en simplaj paŝoj, sed pro la fakto, ke artikoloj pri ĝi estas disigitaj tra la Interreto, ne ekzistas kompleta manlibro, kiu inkludus ĉiujn paŝojn de la komenco ĝis la fino (estas pluraj afiŝoj pri Habré, sed tie mankas multaj punktoj).

WAL-G: sekurkopioj kaj reakiro de PostgreSQL DBMS

Ĉi tiu artikolo estis verkita ĉefe por sistemigi miajn sciojn. Mi ne estas DBA kaj mi povas esprimi min en laika lingvo ie, do ĉiuj korektoj estas bonvenaj!

Aparte, mi rimarkas, ke ĉio ĉi sube estas grava kaj provita por PostgreSQL 12.3 sur Ubuntu 18.04, ĉiuj komandoj devas esti ekzekutitaj kiel privilegiita uzanto.

fikso

En la momento de verkado de ĉi tiu artikolo, la stabila versio de WAL-G estas v0.2.15 (marto 2020). Jen kion ni uzos (sed se vi volas konstrui ĝin mem el la majstra branĉo, tiam la github-deponejo havas ĉiujn instrukciojn por ĉi tio.). Por elŝuti kaj instali vi devas fari:

#!/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/

Post ĉi tio, vi devas unue agordi WAL-G, kaj poste PostgreSQL mem.

Starigante WAL-G

Por ekzemplo de stokado de sekurkopioj, Amazon S3 estos uzata (ĉar ĝi estas pli proksima al miaj serviloj kaj ĝia uzo estas tre malmultekosta). Por labori kun ĝi, vi bezonas "s3 sitelo" kaj alirŝlosilojn.

Ĉiuj antaŭaj artikoloj pri WAL-G uzis agordon uzante mediajn variablojn, sed kun ĉi tiu eldono la agordoj povas troviĝi en .walg.json dosiero en la hejma dosierujo de la postgres-uzanto. Por krei ĝin, rulu la sekvan bash-skripton:

#!/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

Mi klarigu iomete pri ĉiuj parametroj:

  • WALG_S3_PREFIX – la vojo al via S3-sitelo kie sekurkopioj estos alŝutitaj (vi povas aŭ al la radiko aŭ al dosierujo);
  • AWS_ACCESS_KEY_ID - alirŝlosilo en S3 (en kazo de reakiro sur testa servilo, ĉi tiuj ŝlosiloj devas havi Nurlegeblan Politikon! Ĉi tio estas priskribita pli detale en la sekcio pri reakiro.);
  • AWS_SECRET_ACCESS_KEY - sekreta ŝlosilo en S3-stokado;
  • WALG_COMPRESSION_METHOD – kunprema metodo, estas pli bone uzi Brotli (ĉar ĉi tio estas la ora meznombro inter la fina grandeco kaj kunpremado/malkunprema rapido);
  • WALG_DELTA_MAX_STEPS - la nombro da "deltoj" antaŭ krei plenan sekurkopion (ili ŝparas tempon kaj la grandecon de elŝutitaj datumoj, sed povas iomete malrapidigi la reakiran procezon, do ne rekomendas uzi grandajn valorojn);
  • PGDATA - vojo al la dosierujo kun viaj datumbazoj (vi povas ekscii rulante la komandon pg_lsclusters);
  • PGHOST – konektante al la datumbazo, kun loka sekurkopio estas pli bone fari ĝin per unix-socket kiel en ĉi tiu ekzemplo.

Aliaj parametroj troveblas en la dokumentado: https://github.com/wal-g/wal-g/blob/v0.2.15/PostgreSQL.md#configuration.

Agordante PostgreSQL

Por ke la arkivisto ene de la datumbazo alŝutu WAL-programojn al la nubo kaj restarigi ilin de ili (se necese), vi devas agordi plurajn parametrojn en la agorda dosiero. /etc/postgresql/12/main/postgresql.conf. Nur por komenci vi devas certigike neniu el la subaj agordoj estas agordita al iuj aliaj valoroj, tiel ke kiam la agordo estas reŝargita, la DBMS ne kraŝas. Vi povas aldoni ĉi tiujn parametrojn uzante:

#!/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

Priskribo de la agordaj parametroj:

  • wal_nivelo – kiom da informoj skribi en WAL-protokoloj, “replica” – skribi ĉion;
  • arkivo_modo – ebligu elŝuton de WAL-protokoloj per la komando de la parametro arkivo_komando;
  • arkivo_komando – komando por arkivado de kompletigita WAL-protokolo;
  • archive_timeout – arkivado de protokoloj estas farata nur kiam ĝi estas finita, sed se via servilo ŝanĝas/aldonas malmulte da datumoj al la datumbazo, tiam estas senco agordi limon ĉi tie en sekundoj, post kio la arkiva komando estos vokita perforte (Mi skribas intense al la datumbazo ĉiun sekundon, do mi decidis ne agordi ĉi tiun parametron en produktado);
  • restarigi_komando – la komando por restarigi la WAL protokolon de sekurkopio estos uzata se al la "plena sekurkopio" (baza sekurkopio) mankas la lastaj ŝanĝoj en la datumbazo.

Vi povas legi pli pri ĉiuj ĉi tiuj parametroj en la traduko de la oficiala dokumentaro: https://postgrespro.ru/docs/postgresql/12/runtime-config-wal.

Agordi rezervan horaron

Kion ajn oni povas diri, la plej oportuna maniero funkciigi ĝin estas cron. Jen kion ni agordos por krei sekurkopiojn. Ni komencu per la komando krei plenan sekurkopion: en wal-g ĉi tio estas la lanĉa argumento rezerva-puŝo. Sed unue, estas pli bone ruli ĉi tiun komandon permane de la postgres-uzanto por certigi, ke ĉio estas en ordo (kaj ne estas alireraroj):

#!/bin/bash

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

La lanĉaj argumentoj indikas la vojon al la datumdosierujo - mi memorigas al vi, ke vi povas ekscii ĝin ruliĝante pg_lsclusters.

Se ĉio iris sen eraroj kaj la datumoj estis ŝarĝitaj en S3-stokadon, tiam vi povas agordi periodan lanĉon en 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 ĉi tiu ekzemplo, la rezerva procezo komenciĝas ĉiutage je 4:15 a.m.

Forigo de malnovaj sekurkopioj

Plej verŝajne, vi ne bezonas konservi absolute ĉiujn sekurkopiojn de la mezozoika epoko, do estos utile periode "purigi" vian stokadon (kaj "plenaj sekurkopioj" kaj WAL-programoj). Ni faros ĉi tion per cron-tasko:

#!/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 funkcios ĉi tiun taskon ĉiutage je 6:30 a.m., forigante ĉion (plenaj sekurkopioj, deltoj kaj WALs) krom kopioj dum la lastaj 10 tagoj, sed lasante almenaŭ unu sekurkopion. por specifita dato por ke ajna punkto после datoj estis inkluditaj en PITR.

Restarigo de sekurkopio

Ne estas sekreto, ke la ŝlosilo al sana datumbazo estas perioda restarigo kaj kontrolo de la integreco de la datumoj ene. Mi diros al vi kiel rekuperi uzante WAL-G en ĉi tiu sekcio, kaj ni parolos pri kontroloj poste.

Indas noti aparte ke por restarigi en prova medio (ĉion, kio ne estas produktado), oni devas uzi Nurlegeblan konton en S3 por ne hazarde anstataŭigi sekurkopiojn. En la kazo de WAL-G, vi devas agordi la sekvajn rajtojn por la uzanto de S3 en Gruppolitiko (Efekto: Permesi): s3:GetObject, s3:ListBucket, s3:GetBucketLocation. Kaj, kompreneble, ne forgesu agordi archive_mode=malŝaltita en la agorda dosiero postgresql.conf, por ke via testdatumbazo ne volas trankvile subteni.

Restarigo efektiviĝas per eta movo de la mano forigante ĉiujn PostgreSQL-datumojn (inkluzive de uzantoj), do bonvolu esti ege singarda kiam vi rulas la jenajn komandojn.

#!/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

Por tiuj, kiuj volas kontroli la reakivan procezon, malgranda peco de bash-magio estis preparita sube, por ke en kazo de problemoj en reakiro, la skripto kraŝos kun ne-nula elirkodo. En ĉi tiu ekzemplo, 120 kontroloj estas faritaj kun tempodaŭro de 5 sekundoj (tute 10 minutoj por reakiro) por ekscii ĉu la signaldosiero estis forigita (ĉi tio signifos, ke la reakiro estis sukcesa):

#!/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

Post sukcesa reakiro, ne forgesu rekomenci ĉiujn procezojn (pgbouncer/monit, ktp.).

Kontrolante datumojn post reakiro

Nepras kontroli la integrecon de la datumbazo post restarigo, por ke ne aperu situacio kun rompita/malrekta sekurkopio. Kaj estas pli bone fari tion kun ĉiu kreita arkivo, sed kie kaj kiel dependas nur de via imago (vi povas levi individuajn servilojn ĉiuhora aŭ fari kontrolon en CI). Sed minimume, necesas kontroli la datumojn kaj indeksojn en la datumbazo.

Por kontroli la datumojn, sufiĉas ruli ĝin tra rubejo, sed estas pli bone, ke dum kreado de la datumbazo vi havas ĉeksumojn ebligitaj (datumkontroloj):

#!/bin/bash

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

Por kontroli indeksojn - ekzistas amcheck modulo, ni prenu la sql-demandon por ĝi de WAL-G-testoj kaj konstruu iom da logiko ĉirkaŭ ĝi:

#!/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

Resumi

Mi ŝatus esprimi mian dankemon al Andreo Borodin pro lia helpo en la preparado de la eldonaĵo kaj specialan dankon pro lia kontribuo al la disvolviĝo de WAL-G!

Ĉi tio finas ĉi tiun noton. Mi esperas, ke mi povis transdoni la facilecon de aranĝo kaj la grandegan potencialon por uzi ĉi tiun ilon en via kompanio. Mi aŭdis multon pri WAL-G, sed neniam havis sufiĉe da tempo por sidiĝi kaj eltrovi ĝin. Kaj post kiam mi efektivigis ĝin hejme, ĉi tiu artikolo eliris el mi.

Aparte, indas noti, ke WAL-G ankaŭ povas funkcii kun la sekva DBMS:

fonto: www.habr.com

Aldoni komenton