WAL-G: sandaran dan pemulihan DBMS PostgreSQL

Telah lama diketahui bahawa membuat sandaran ke dalam pembuangan SQL (menggunakan pg_dump atau pg_dumpall) bukanlah idea yang baik. Untuk membuat sandaran DBMS PostgreSQL, lebih baik menggunakan arahan pg_basebackup, yang membuat salinan binari log WAL. Tetapi apabila anda mula mengkaji keseluruhan proses mencipta salinan dan memulihkan, anda akan faham bahawa anda perlu menulis sekurang-kurangnya beberapa beca untuk ini berfungsi dan tidak menyebabkan anda sakit di atas dan di bawah. Untuk meringankan penderitaan, WAL-G telah dibangunkan.

WAL-G ialah alat yang ditulis dalam Go untuk membuat sandaran dan memulihkan pangkalan data PostgreSQL (dan lebih baru-baru ini MySQL/MariaDB, MongoDB dan FoundationDB). Ia menyokong kerja dengan storan Amazon S3 (dan analog, contohnya, Penyimpanan Objek Yandex), serta Storan Awan Google, Storan Azure, Storan Objek Swift dan hanya dengan sistem fail. Keseluruhan persediaan datang kepada langkah-langkah mudah, tetapi disebabkan fakta bahawa artikel tentangnya tersebar di Internet, tidak ada manual cara-cara yang lengkap yang akan merangkumi semua langkah dari awal hingga akhir (terdapat beberapa siaran di Habré, tetapi banyak mata yang terlepas di sana).

WAL-G: sandaran dan pemulihan DBMS PostgreSQL

Artikel ini ditulis terutamanya untuk mensistemkan pengetahuan saya. Saya bukan DBA dan saya boleh menyatakan diri saya dalam bahasa awam di suatu tempat, jadi sebarang pembetulan dialu-alukan!

Secara berasingan, saya ambil perhatian bahawa segala-galanya di bawah adalah berkaitan dan diuji untuk PostgreSQL 12.3 pada Ubuntu 18.04, semua arahan mesti dilaksanakan sebagai pengguna istimewa.

Pemasangan

Pada masa menulis artikel ini, versi stabil WAL-G ialah v0.2.15 (Mac 2020). Inilah yang akan kami gunakan (tetapi jika anda ingin membinanya sendiri dari cawangan induk, maka repositori github mempunyai semua arahan untuk ini). Untuk memuat turun dan memasang anda perlu lakukan:

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

Selepas ini, anda perlu mengkonfigurasi WAL-G dahulu, dan kemudian PostgreSQL sendiri.

Menyediakan WAL-G

Untuk contoh menyimpan sandaran, Amazon S3 akan digunakan (kerana ia lebih dekat dengan pelayan saya dan penggunaannya sangat murah). Untuk mengendalikannya, anda memerlukan "baldi s3" dan kekunci akses.

Semua artikel terdahulu tentang WAL-G menggunakan konfigurasi menggunakan pembolehubah persekitaran, tetapi dengan keluaran ini tetapan boleh ditempatkan di fail .walg.json dalam direktori rumah pengguna postgres. Untuk menciptanya, jalankan skrip bash berikut:

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

Biar saya terangkan sedikit tentang semua parameter:

  • WALG_S3_PREFIX – laluan ke baldi S3 anda di mana sandaran akan dimuat naik (anda boleh sama ada ke akar atau folder);
  • AWS_ACCESS_KEY_ID – kunci akses dalam S3 (dalam kes pemulihan pada pelayan ujian, kunci ini mesti mempunyai Dasar Baca Sahaja! Ini diterangkan dengan lebih terperinci dalam bahagian pemulihan.);
  • AWS_SECRET_ACCESS_KEY – kunci rahsia dalam storan S3;
  • WALG_COMPRESSION_METHOD – kaedah mampatan, lebih baik menggunakan Brotli (kerana ini adalah min emas antara saiz akhir dan kelajuan mampatan/penyahmampatan);
  • WALG_DELTA_MAX_STEPS – bilangan "delta" sebelum membuat sandaran penuh (mereka menjimatkan masa dan saiz data yang dimuat turun, tetapi boleh melambatkan sedikit proses pemulihan, jadi tidak dinasihatkan untuk menggunakan nilai yang besar);
  • PGDATA – laluan ke direktori dengan data pangkalan data anda (anda boleh mengetahui dengan menjalankan arahan pg_lsclusters);
  • HANTU – menyambung ke pangkalan data, dengan sandaran tempatan adalah lebih baik untuk melakukannya melalui soket unix seperti dalam contoh ini.

Parameter lain boleh didapati dalam dokumentasi: https://github.com/wal-g/wal-g/blob/v0.2.15/PostgreSQL.md#configuration.

Menyediakan PostgreSQL

Agar pengarkib di dalam pangkalan data memuat naik log WAL ke awan dan memulihkannya daripadanya (jika perlu), anda perlu menetapkan beberapa parameter dalam fail konfigurasi /etc/postgresql/12/main/postgresql.conf. Hanya sebagai permulaan anda perlu pastikanbahawa tiada tetapan di bawah ditetapkan kepada mana-mana nilai lain, supaya apabila konfigurasi dimuat semula, DBMS tidak ranap. Anda boleh menambah parameter ini menggunakan:

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

Penerangan tentang parameter yang akan ditetapkan:

  • wal_level – berapa banyak maklumat untuk ditulis dalam log WAL, “replika” – tulis segala-galanya;
  • mod_arkib – dayakan muat turun log WAL menggunakan arahan daripada parameter arkib_perintah;
  • arkib_perintah – arahan untuk mengarkibkan log WAL yang lengkap;
  • archive_timeout – pengarkiban log dilakukan hanya apabila ia selesai, tetapi jika pelayan anda menukar/menambah sedikit data ke pangkalan data, maka masuk akal untuk menetapkan had di sini dalam beberapa saat, selepas itu arahan pengarkiban akan dipanggil secara paksa (Saya menulis secara intensif ke pangkalan data setiap saat, jadi saya memutuskan untuk tidak menetapkan parameter ini dalam pengeluaran);
  • restore_command – arahan untuk memulihkan log WAL daripada sandaran akan digunakan jika "sandaran penuh" (sandaran asas) tidak mempunyai perubahan terkini dalam pangkalan data.

Anda boleh membaca lebih lanjut mengenai semua parameter ini dalam terjemahan dokumentasi rasmi: https://postgrespro.ru/docs/postgresql/12/runtime-config-wal.

Menyediakan jadual sandaran

Apa sahaja yang boleh dikatakan, cara paling mudah untuk menjalankannya ialah cron. Inilah yang akan kami konfigurasikan untuk membuat sandaran. Mari kita mulakan dengan arahan untuk membuat sandaran penuh: dalam wal-g ini ialah hujah pelancaran tolak sandaran. Tetapi pertama-tama, lebih baik untuk menjalankan arahan ini secara manual daripada pengguna postgres untuk memastikan semuanya baik-baik saja (dan tiada ralat akses):

#!/bin/bash

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

Argumen pelancaran menunjukkan laluan ke direktori data - Saya mengingatkan anda bahawa anda boleh mengetahuinya dengan menjalankan pg_lsclusters.

Jika semuanya berjalan tanpa ralat dan data telah dimuatkan ke dalam storan S3, maka anda boleh mengkonfigurasi pelancaran berkala dalam 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

Dalam contoh ini, proses sandaran bermula setiap hari pada 4:15 pagi.

Memadamkan sandaran lama

Kemungkinan besar, anda tidak perlu menyimpan sepenuhnya semua sandaran dari era Mesozoik, jadi adalah berguna untuk "membersihkan" storan anda secara berkala (kedua-dua "sandaran penuh" dan log WAL). Kami akan melakukan ini semua melalui tugas 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 akan menjalankan tugas ini setiap hari pada 6:30 pagi, memadamkan semua (sandaran penuh, delta dan WAL) kecuali salinan untuk 10 hari terakhir, tetapi meninggalkan sekurang-kurangnya satu sandaran kepada tarikh yang ditetapkan supaya sebarang titik selepas tarikh dimasukkan dalam PITR.

Memulihkan daripada sandaran

Bukan rahsia lagi bahawa kunci kepada pangkalan data yang sihat adalah pemulihan berkala dan pengesahan integriti data di dalamnya. Saya akan memberitahu anda cara memulihkan menggunakan WAL-G dalam bahagian ini, dan kita akan bercakap tentang semakan kemudian.

Secara berasingan, perlu diperhatikan bahawa untuk memulihkan dalam persekitaran ujian (semua yang bukan pengeluaran) anda perlu menggunakan akaun Baca Sahaja dalam S3 supaya tidak menimpa sandaran secara tidak sengaja. Dalam kes WAL-G, anda perlu menetapkan hak berikut untuk pengguna S3 dalam Dasar Kumpulan (Kesan: Benarkan): s3:GetObject, s3:ListBucket, s3:GetBucketLocation. Dan, sudah tentu, jangan lupa untuk menetapkan archive_mode=off dalam fail tetapan postgresql.conf, supaya pangkalan data ujian anda tidak mahu disandarkan secara senyap.

Pemulihan dilakukan dengan sedikit pergerakan tangan memadam semua data PostgreSQL (termasuk pengguna), jadi sila berhati-hati apabila anda menjalankan arahan berikut.

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

Bagi mereka yang ingin menyemak proses pemulihan, sekeping kecil sihir bash telah disediakan di bawah, supaya sekiranya berlaku masalah dalam pemulihan, skrip akan ranap dengan kod keluar bukan sifar. Dalam contoh ini, 120 semakan dibuat dengan tamat masa 5 saat (jumlah 10 minit untuk pemulihan) untuk mengetahui sama ada fail isyarat telah dipadamkan (ini bermakna pemulihan telah berjaya):

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

Selepas pemulihan berjaya, jangan lupa untuk memulakan semua proses kembali (pgbouncer/monit, dsb.).

Menyemak data selepas pemulihan

Adalah penting untuk menyemak integriti pangkalan data selepas pemulihan, supaya situasi dengan sandaran yang rosak/bengkok tidak timbul. Dan lebih baik untuk melakukan ini dengan setiap arkib yang dibuat, tetapi di mana dan bagaimana hanya bergantung pada imaginasi anda (anda boleh menaikkan pelayan individu setiap jam atau menjalankan semakan dalam CI). Tetapi sekurang-kurangnya, adalah perlu untuk menyemak data dan indeks dalam pangkalan data.

Untuk menyemak data, sudah cukup untuk menjalankannya melalui pembuangan, tetapi lebih baik apabila membuat pangkalan data anda telah mengaktifkan checksum (jumlah semak data):

#!/bin/bash

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

Untuk menyemak indeks - wujud modul amcheck, mari kita ambil pertanyaan sql untuknya dari Ujian WAL-G dan bina sedikit logik di sekelilingnya:

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

Untuk Meringkaskan

Saya ingin mengucapkan terima kasih kepada Andrey Borodin atas bantuannya dalam menyediakan penerbitan dan terima kasih khas atas sumbangannya kepada pembangunan WAL-G!

Ini menyimpulkan nota ini. Saya berharap saya dapat menyampaikan kemudahan persediaan dan potensi besar untuk menggunakan alat ini di syarikat anda. Saya mendengar banyak tentang WAL-G, tetapi tidak mempunyai masa yang cukup untuk duduk dan memikirkannya. Dan selepas saya melaksanakannya di rumah, artikel ini keluar dari saya.

Secara berasingan, perlu diperhatikan bahawa WAL-G juga boleh berfungsi dengan DBMS berikut:

Sumber: www.habr.com

Tambah komen